1fee331f6SAlexey Brodkin /* 2fee331f6SAlexey Brodkin * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com> 3fee331f6SAlexey Brodkin * 4fee331f6SAlexey Brodkin * SPDX-License-Identifier: GPL-2.0+ 5fee331f6SAlexey Brodkin */ 6fee331f6SAlexey Brodkin 7fee331f6SAlexey Brodkin #include <common.h> 8*155d9f65SPatrice Chotard #include <clk.h> 9fee331f6SAlexey Brodkin #include <dm.h> 10*155d9f65SPatrice Chotard #include <dm/ofnode.h> 11fee331f6SAlexey Brodkin #include "ohci.h" 12fee331f6SAlexey Brodkin 13fee331f6SAlexey Brodkin #if !defined(CONFIG_USB_OHCI_NEW) 14fee331f6SAlexey Brodkin # error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW" 15fee331f6SAlexey Brodkin #endif 16fee331f6SAlexey Brodkin 17fee331f6SAlexey Brodkin struct generic_ohci { 18fee331f6SAlexey Brodkin ohci_t ohci; 19*155d9f65SPatrice Chotard struct clk *clocks; /* clock list */ 20*155d9f65SPatrice Chotard int clock_count; /* number of clock in clock list */ 21fee331f6SAlexey Brodkin }; 22fee331f6SAlexey Brodkin 23fee331f6SAlexey Brodkin static int ohci_usb_probe(struct udevice *dev) 24fee331f6SAlexey Brodkin { 25a821c4afSSimon Glass struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); 26*155d9f65SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 27*155d9f65SPatrice Chotard int i, err, ret, clock_nb; 28fee331f6SAlexey Brodkin 29*155d9f65SPatrice Chotard err = 0; 30*155d9f65SPatrice Chotard priv->clock_count = 0; 31*155d9f65SPatrice Chotard clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); 32*155d9f65SPatrice Chotard if (clock_nb > 0) { 33*155d9f65SPatrice Chotard priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 34*155d9f65SPatrice Chotard GFP_KERNEL); 35*155d9f65SPatrice Chotard if (!priv->clocks) 36*155d9f65SPatrice Chotard return -ENOMEM; 37*155d9f65SPatrice Chotard 38*155d9f65SPatrice Chotard for (i = 0; i < clock_nb; i++) { 39*155d9f65SPatrice Chotard err = clk_get_by_index(dev, i, &priv->clocks[i]); 40*155d9f65SPatrice Chotard if (err < 0) 41*155d9f65SPatrice Chotard break; 42*155d9f65SPatrice Chotard 43*155d9f65SPatrice Chotard err = clk_enable(&priv->clocks[i]); 44*155d9f65SPatrice Chotard if (err) { 45*155d9f65SPatrice Chotard error("failed to enable clock %d\n", i); 46*155d9f65SPatrice Chotard clk_free(&priv->clocks[i]); 47*155d9f65SPatrice Chotard goto clk_err; 48*155d9f65SPatrice Chotard } 49*155d9f65SPatrice Chotard priv->clock_count++; 50*155d9f65SPatrice Chotard } 51*155d9f65SPatrice Chotard } else if (clock_nb != -ENOENT) { 52*155d9f65SPatrice Chotard error("failed to get clock phandle(%d)\n", clock_nb); 53*155d9f65SPatrice Chotard return clock_nb; 54*155d9f65SPatrice Chotard } 55*155d9f65SPatrice Chotard 56*155d9f65SPatrice Chotard err = ohci_register(dev, regs); 57*155d9f65SPatrice Chotard if (err) 58*155d9f65SPatrice Chotard goto clk_err; 59*155d9f65SPatrice Chotard 60*155d9f65SPatrice Chotard return 0; 61*155d9f65SPatrice Chotard 62*155d9f65SPatrice Chotard clk_err: 63*155d9f65SPatrice Chotard ret = clk_release_all(priv->clocks, priv->clock_count); 64*155d9f65SPatrice Chotard if (ret) 65*155d9f65SPatrice Chotard error("failed to disable all clocks\n"); 66*155d9f65SPatrice Chotard 67*155d9f65SPatrice Chotard return err; 68fee331f6SAlexey Brodkin } 69fee331f6SAlexey Brodkin 70fee331f6SAlexey Brodkin static int ohci_usb_remove(struct udevice *dev) 71fee331f6SAlexey Brodkin { 72*155d9f65SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 73*155d9f65SPatrice Chotard int ret; 74*155d9f65SPatrice Chotard 75*155d9f65SPatrice Chotard ret = ohci_deregister(dev); 76*155d9f65SPatrice Chotard if (ret) 77*155d9f65SPatrice Chotard return ret; 78*155d9f65SPatrice Chotard 79*155d9f65SPatrice Chotard return clk_release_all(priv->clocks, priv->clock_count); 80fee331f6SAlexey Brodkin } 81fee331f6SAlexey Brodkin 82fee331f6SAlexey Brodkin static const struct udevice_id ohci_usb_ids[] = { 83fee331f6SAlexey Brodkin { .compatible = "generic-ohci" }, 84fee331f6SAlexey Brodkin { } 85fee331f6SAlexey Brodkin }; 86fee331f6SAlexey Brodkin 87fee331f6SAlexey Brodkin U_BOOT_DRIVER(ohci_generic) = { 88fee331f6SAlexey Brodkin .name = "ohci_generic", 89fee331f6SAlexey Brodkin .id = UCLASS_USB, 90fee331f6SAlexey Brodkin .of_match = ohci_usb_ids, 91fee331f6SAlexey Brodkin .probe = ohci_usb_probe, 92fee331f6SAlexey Brodkin .remove = ohci_usb_remove, 93fee331f6SAlexey Brodkin .ops = &ohci_usb_ops, 94fee331f6SAlexey Brodkin .priv_auto_alloc_size = sizeof(struct generic_ohci), 95fee331f6SAlexey Brodkin .flags = DM_FLAG_ALLOC_PRIV_DMA, 96fee331f6SAlexey Brodkin }; 97