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 <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 int clock_count; /* number of clock in clock list */ 23 int reset_count; /* number of reset in reset list */ 24 }; 25 26 static int ohci_usb_probe(struct udevice *dev) 27 { 28 struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); 29 struct generic_ohci *priv = dev_get_priv(dev); 30 int i, err, ret, clock_nb, reset_nb; 31 32 err = 0; 33 priv->clock_count = 0; 34 clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); 35 if (clock_nb > 0) { 36 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 37 GFP_KERNEL); 38 if (!priv->clocks) 39 return -ENOMEM; 40 41 for (i = 0; i < clock_nb; i++) { 42 err = clk_get_by_index(dev, i, &priv->clocks[i]); 43 if (err < 0) 44 break; 45 46 err = clk_enable(&priv->clocks[i]); 47 if (err) { 48 error("failed to enable clock %d\n", i); 49 clk_free(&priv->clocks[i]); 50 goto clk_err; 51 } 52 priv->clock_count++; 53 } 54 } else if (clock_nb != -ENOENT) { 55 error("failed to get clock phandle(%d)\n", clock_nb); 56 return clock_nb; 57 } 58 59 priv->reset_count = 0; 60 reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells"); 61 if (reset_nb > 0) { 62 priv->resets = devm_kcalloc(dev, reset_nb, 63 sizeof(struct reset_ctl), 64 GFP_KERNEL); 65 if (!priv->resets) 66 return -ENOMEM; 67 68 for (i = 0; i < reset_nb; i++) { 69 err = reset_get_by_index(dev, i, &priv->resets[i]); 70 if (err < 0) 71 break; 72 73 err = reset_deassert(&priv->resets[i]); 74 if (err) { 75 error("failed to deassert reset %d\n", i); 76 reset_free(&priv->resets[i]); 77 goto reset_err; 78 } 79 priv->reset_count++; 80 } 81 } else if (reset_nb != -ENOENT) { 82 error("failed to get reset phandle(%d)\n", reset_nb); 83 goto clk_err; 84 } 85 86 err = ohci_register(dev, regs); 87 if (err) 88 goto reset_err; 89 90 return 0; 91 92 reset_err: 93 ret = reset_release_all(priv->resets, priv->reset_count); 94 if (ret) 95 error("failed to assert all resets\n"); 96 clk_err: 97 ret = clk_release_all(priv->clocks, priv->clock_count); 98 if (ret) 99 error("failed to disable all clocks\n"); 100 101 return err; 102 } 103 104 static int ohci_usb_remove(struct udevice *dev) 105 { 106 struct generic_ohci *priv = dev_get_priv(dev); 107 int ret; 108 109 ret = ohci_deregister(dev); 110 if (ret) 111 return ret; 112 113 ret = reset_release_all(priv->resets, priv->reset_count); 114 if (ret) 115 return ret; 116 117 return clk_release_all(priv->clocks, priv->clock_count); 118 } 119 120 static const struct udevice_id ohci_usb_ids[] = { 121 { .compatible = "generic-ohci" }, 122 { } 123 }; 124 125 U_BOOT_DRIVER(ohci_generic) = { 126 .name = "ohci_generic", 127 .id = UCLASS_USB, 128 .of_match = ohci_usb_ids, 129 .probe = ohci_usb_probe, 130 .remove = ohci_usb_remove, 131 .ops = &ohci_usb_ops, 132 .priv_auto_alloc_size = sizeof(struct generic_ohci), 133 .flags = DM_FLAG_ALLOC_PRIV_DMA, 134 }; 135