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