1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2015 Alexey Brodkin <abrodkin (at) synopsys.com> 4 */ 5 6 #include <common.h> 7 #include <clk.h> 8 #include <dm.h> 9 #include <dm/ofnode.h> 10 #include <generic-phy.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 struct phy phy; 23 int clock_count; /* number of clock in clock list */ 24 int reset_count; /* number of reset in reset list */ 25 }; 26 27 static int ohci_setup_phy(struct udevice *dev, int index) 28 { 29 struct generic_ohci *priv = dev_get_priv(dev); 30 int ret; 31 32 ret = generic_phy_get_by_index(dev, index, &priv->phy); 33 if (ret) { 34 if (ret != -ENOENT) { 35 dev_err(dev, "failed to get usb phy\n"); 36 return ret; 37 } 38 } else { 39 ret = generic_phy_init(&priv->phy); 40 if (ret) { 41 dev_err(dev, "failed to init usb phy\n"); 42 return ret; 43 } 44 45 ret = generic_phy_power_on(&priv->phy); 46 if (ret) { 47 dev_err(dev, "failed to power on usb phy\n"); 48 return generic_phy_exit(&priv->phy); 49 } 50 } 51 52 return 0; 53 } 54 55 static int ohci_shutdown_phy(struct udevice *dev) 56 { 57 struct generic_ohci *priv = dev_get_priv(dev); 58 int ret = 0; 59 60 if (generic_phy_valid(&priv->phy)) { 61 ret = generic_phy_power_off(&priv->phy); 62 if (ret) { 63 dev_err(dev, "failed to power off usb phy\n"); 64 return ret; 65 } 66 67 ret = generic_phy_exit(&priv->phy); 68 if (ret) { 69 dev_err(dev, "failed to power off usb phy\n"); 70 return ret; 71 } 72 } 73 74 return 0; 75 } 76 77 static int ohci_usb_probe(struct udevice *dev) 78 { 79 struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); 80 struct generic_ohci *priv = dev_get_priv(dev); 81 int i, err, ret, clock_nb, reset_nb; 82 83 err = 0; 84 priv->clock_count = 0; 85 clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); 86 if (clock_nb > 0) { 87 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 88 GFP_KERNEL); 89 if (!priv->clocks) 90 return -ENOMEM; 91 92 for (i = 0; i < clock_nb; i++) { 93 err = clk_get_by_index(dev, i, &priv->clocks[i]); 94 if (err < 0) 95 break; 96 97 err = clk_enable(&priv->clocks[i]); 98 if (err) { 99 dev_err(dev, "failed to enable clock %d\n", i); 100 clk_free(&priv->clocks[i]); 101 goto clk_err; 102 } 103 priv->clock_count++; 104 } 105 } else if (clock_nb != -ENOENT) { 106 dev_err(dev, "failed to get clock phandle(%d)\n", clock_nb); 107 return clock_nb; 108 } 109 110 priv->reset_count = 0; 111 reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells"); 112 if (reset_nb > 0) { 113 priv->resets = devm_kcalloc(dev, reset_nb, 114 sizeof(struct reset_ctl), 115 GFP_KERNEL); 116 if (!priv->resets) 117 return -ENOMEM; 118 119 for (i = 0; i < reset_nb; i++) { 120 err = reset_get_by_index(dev, i, &priv->resets[i]); 121 if (err < 0) 122 break; 123 124 err = reset_deassert(&priv->resets[i]); 125 if (err) { 126 dev_err(dev, "failed to deassert reset %d\n", i); 127 reset_free(&priv->resets[i]); 128 goto reset_err; 129 } 130 priv->reset_count++; 131 } 132 } else if (reset_nb != -ENOENT) { 133 dev_err(dev, "failed to get reset phandle(%d)\n", reset_nb); 134 goto clk_err; 135 } 136 137 err = ohci_setup_phy(dev, 0); 138 if (err) 139 goto reset_err; 140 141 err = ohci_register(dev, regs); 142 if (err) 143 goto phy_err; 144 145 return 0; 146 147 phy_err: 148 ret = ohci_shutdown_phy(dev); 149 if (ret) 150 dev_err(dev, "failed to shutdown usb phy\n"); 151 152 reset_err: 153 ret = reset_release_all(priv->resets, priv->reset_count); 154 if (ret) 155 dev_err(dev, "failed to assert all resets\n"); 156 clk_err: 157 ret = clk_release_all(priv->clocks, priv->clock_count); 158 if (ret) 159 dev_err(dev, "failed to disable all clocks\n"); 160 161 return err; 162 } 163 164 static int ohci_usb_remove(struct udevice *dev) 165 { 166 struct generic_ohci *priv = dev_get_priv(dev); 167 int ret; 168 169 ret = ohci_deregister(dev); 170 if (ret) 171 return ret; 172 173 ret = ohci_shutdown_phy(dev); 174 if (ret) 175 return ret; 176 177 ret = reset_release_all(priv->resets, priv->reset_count); 178 if (ret) 179 return ret; 180 181 return clk_release_all(priv->clocks, priv->clock_count); 182 } 183 184 static const struct udevice_id ohci_usb_ids[] = { 185 { .compatible = "generic-ohci" }, 186 { } 187 }; 188 189 U_BOOT_DRIVER(ohci_generic) = { 190 .name = "ohci_generic", 191 .id = UCLASS_USB, 192 .of_match = ohci_usb_ids, 193 .probe = ohci_usb_probe, 194 .remove = ohci_usb_remove, 195 .ops = &ohci_usb_ops, 196 .priv_auto_alloc_size = sizeof(struct generic_ohci), 197 .flags = DM_FLAG_ALLOC_PRIV_DMA, 198 }; 199