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 <generic-phy.h> 12 #include <reset.h> 13 #include "ohci.h" 14 15 #if !defined(CONFIG_USB_OHCI_NEW) 16 # error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW" 17 #endif 18 19 struct generic_ohci { 20 ohci_t ohci; 21 struct clk *clocks; /* clock list */ 22 struct reset_ctl *resets; /* reset list */ 23 struct phy phy; 24 int clock_count; /* number of clock in clock list */ 25 int reset_count; /* number of reset in reset list */ 26 }; 27 28 static int ohci_usb_probe(struct udevice *dev) 29 { 30 struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); 31 struct generic_ohci *priv = dev_get_priv(dev); 32 int i, err, ret, clock_nb, reset_nb; 33 34 err = 0; 35 priv->clock_count = 0; 36 clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); 37 if (clock_nb > 0) { 38 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 39 GFP_KERNEL); 40 if (!priv->clocks) 41 return -ENOMEM; 42 43 for (i = 0; i < clock_nb; i++) { 44 err = clk_get_by_index(dev, i, &priv->clocks[i]); 45 if (err < 0) 46 break; 47 48 err = clk_enable(&priv->clocks[i]); 49 if (err) { 50 error("failed to enable clock %d\n", i); 51 clk_free(&priv->clocks[i]); 52 goto clk_err; 53 } 54 priv->clock_count++; 55 } 56 } else if (clock_nb != -ENOENT) { 57 error("failed to get clock phandle(%d)\n", clock_nb); 58 return clock_nb; 59 } 60 61 priv->reset_count = 0; 62 reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells"); 63 if (reset_nb > 0) { 64 priv->resets = devm_kcalloc(dev, reset_nb, 65 sizeof(struct reset_ctl), 66 GFP_KERNEL); 67 if (!priv->resets) 68 return -ENOMEM; 69 70 for (i = 0; i < reset_nb; i++) { 71 err = reset_get_by_index(dev, i, &priv->resets[i]); 72 if (err < 0) 73 break; 74 75 err = reset_deassert(&priv->resets[i]); 76 if (err) { 77 error("failed to deassert reset %d\n", i); 78 reset_free(&priv->resets[i]); 79 goto reset_err; 80 } 81 priv->reset_count++; 82 } 83 } else if (reset_nb != -ENOENT) { 84 error("failed to get reset phandle(%d)\n", reset_nb); 85 goto clk_err; 86 } 87 88 err = generic_phy_get_by_index(dev, 0, &priv->phy); 89 if (err) { 90 if (err != -ENOENT) { 91 error("failed to get usb phy\n"); 92 goto reset_err; 93 } 94 } else { 95 96 err = generic_phy_init(&priv->phy); 97 if (err) { 98 error("failed to init usb phy\n"); 99 goto reset_err; 100 } 101 } 102 103 err = ohci_register(dev, regs); 104 if (err) 105 goto phy_err; 106 107 return 0; 108 109 phy_err: 110 if (generic_phy_valid(&priv->phy)) { 111 ret = generic_phy_exit(&priv->phy); 112 if (ret) 113 error("failed to release phy\n"); 114 } 115 116 reset_err: 117 ret = reset_release_all(priv->resets, priv->reset_count); 118 if (ret) 119 error("failed to assert all resets\n"); 120 clk_err: 121 ret = clk_release_all(priv->clocks, priv->clock_count); 122 if (ret) 123 error("failed to disable all clocks\n"); 124 125 return err; 126 } 127 128 static int ohci_usb_remove(struct udevice *dev) 129 { 130 struct generic_ohci *priv = dev_get_priv(dev); 131 int ret; 132 133 ret = ohci_deregister(dev); 134 if (ret) 135 return ret; 136 137 if (generic_phy_valid(&priv->phy)) { 138 ret = generic_phy_exit(&priv->phy); 139 if (ret) 140 return ret; 141 } 142 143 ret = reset_release_all(priv->resets, priv->reset_count); 144 if (ret) 145 return ret; 146 147 return clk_release_all(priv->clocks, priv->clock_count); 148 } 149 150 static const struct udevice_id ohci_usb_ids[] = { 151 { .compatible = "generic-ohci" }, 152 { } 153 }; 154 155 U_BOOT_DRIVER(ohci_generic) = { 156 .name = "ohci_generic", 157 .id = UCLASS_USB, 158 .of_match = ohci_usb_ids, 159 .probe = ohci_usb_probe, 160 .remove = ohci_usb_remove, 161 .ops = &ohci_usb_ops, 162 .priv_auto_alloc_size = sizeof(struct generic_ohci), 163 .flags = DM_FLAG_ALLOC_PRIV_DMA, 164 }; 165