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