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> 8155d9f65SPatrice Chotard #include <clk.h> 9fee331f6SAlexey Brodkin #include <dm.h> 10155d9f65SPatrice Chotard #include <dm/ofnode.h> 11*8a51b4b3SPatrice Chotard #include <reset.h> 12fee331f6SAlexey Brodkin #include "ohci.h" 13fee331f6SAlexey Brodkin 14fee331f6SAlexey Brodkin #if !defined(CONFIG_USB_OHCI_NEW) 15fee331f6SAlexey Brodkin # error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW" 16fee331f6SAlexey Brodkin #endif 17fee331f6SAlexey Brodkin 18fee331f6SAlexey Brodkin struct generic_ohci { 19fee331f6SAlexey Brodkin ohci_t ohci; 20155d9f65SPatrice Chotard struct clk *clocks; /* clock list */ 21*8a51b4b3SPatrice Chotard struct reset_ctl *resets; /* reset list */ 22155d9f65SPatrice Chotard int clock_count; /* number of clock in clock list */ 23*8a51b4b3SPatrice Chotard int reset_count; /* number of reset in reset list */ 24fee331f6SAlexey Brodkin }; 25fee331f6SAlexey Brodkin 26fee331f6SAlexey Brodkin static int ohci_usb_probe(struct udevice *dev) 27fee331f6SAlexey Brodkin { 28a821c4afSSimon Glass struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); 29155d9f65SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 30*8a51b4b3SPatrice Chotard int i, err, ret, clock_nb, reset_nb; 31fee331f6SAlexey Brodkin 32155d9f65SPatrice Chotard err = 0; 33155d9f65SPatrice Chotard priv->clock_count = 0; 34155d9f65SPatrice Chotard clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); 35155d9f65SPatrice Chotard if (clock_nb > 0) { 36155d9f65SPatrice Chotard priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 37155d9f65SPatrice Chotard GFP_KERNEL); 38155d9f65SPatrice Chotard if (!priv->clocks) 39155d9f65SPatrice Chotard return -ENOMEM; 40155d9f65SPatrice Chotard 41155d9f65SPatrice Chotard for (i = 0; i < clock_nb; i++) { 42155d9f65SPatrice Chotard err = clk_get_by_index(dev, i, &priv->clocks[i]); 43155d9f65SPatrice Chotard if (err < 0) 44155d9f65SPatrice Chotard break; 45155d9f65SPatrice Chotard 46155d9f65SPatrice Chotard err = clk_enable(&priv->clocks[i]); 47155d9f65SPatrice Chotard if (err) { 48155d9f65SPatrice Chotard error("failed to enable clock %d\n", i); 49155d9f65SPatrice Chotard clk_free(&priv->clocks[i]); 50155d9f65SPatrice Chotard goto clk_err; 51155d9f65SPatrice Chotard } 52155d9f65SPatrice Chotard priv->clock_count++; 53155d9f65SPatrice Chotard } 54155d9f65SPatrice Chotard } else if (clock_nb != -ENOENT) { 55155d9f65SPatrice Chotard error("failed to get clock phandle(%d)\n", clock_nb); 56155d9f65SPatrice Chotard return clock_nb; 57155d9f65SPatrice Chotard } 58155d9f65SPatrice Chotard 59*8a51b4b3SPatrice Chotard priv->reset_count = 0; 60*8a51b4b3SPatrice Chotard reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells"); 61*8a51b4b3SPatrice Chotard if (reset_nb > 0) { 62*8a51b4b3SPatrice Chotard priv->resets = devm_kcalloc(dev, reset_nb, 63*8a51b4b3SPatrice Chotard sizeof(struct reset_ctl), 64*8a51b4b3SPatrice Chotard GFP_KERNEL); 65*8a51b4b3SPatrice Chotard if (!priv->resets) 66*8a51b4b3SPatrice Chotard return -ENOMEM; 67*8a51b4b3SPatrice Chotard 68*8a51b4b3SPatrice Chotard for (i = 0; i < reset_nb; i++) { 69*8a51b4b3SPatrice Chotard err = reset_get_by_index(dev, i, &priv->resets[i]); 70*8a51b4b3SPatrice Chotard if (err < 0) 71*8a51b4b3SPatrice Chotard break; 72*8a51b4b3SPatrice Chotard 73*8a51b4b3SPatrice Chotard err = reset_deassert(&priv->resets[i]); 74*8a51b4b3SPatrice Chotard if (err) { 75*8a51b4b3SPatrice Chotard error("failed to deassert reset %d\n", i); 76*8a51b4b3SPatrice Chotard reset_free(&priv->resets[i]); 77*8a51b4b3SPatrice Chotard goto reset_err; 78*8a51b4b3SPatrice Chotard } 79*8a51b4b3SPatrice Chotard priv->reset_count++; 80*8a51b4b3SPatrice Chotard } 81*8a51b4b3SPatrice Chotard } else if (reset_nb != -ENOENT) { 82*8a51b4b3SPatrice Chotard error("failed to get reset phandle(%d)\n", reset_nb); 83*8a51b4b3SPatrice Chotard goto clk_err; 84*8a51b4b3SPatrice Chotard } 85*8a51b4b3SPatrice Chotard 86155d9f65SPatrice Chotard err = ohci_register(dev, regs); 87155d9f65SPatrice Chotard if (err) 88*8a51b4b3SPatrice Chotard goto reset_err; 89155d9f65SPatrice Chotard 90155d9f65SPatrice Chotard return 0; 91155d9f65SPatrice Chotard 92*8a51b4b3SPatrice Chotard reset_err: 93*8a51b4b3SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 94*8a51b4b3SPatrice Chotard if (ret) 95*8a51b4b3SPatrice Chotard error("failed to assert all resets\n"); 96155d9f65SPatrice Chotard clk_err: 97155d9f65SPatrice Chotard ret = clk_release_all(priv->clocks, priv->clock_count); 98155d9f65SPatrice Chotard if (ret) 99155d9f65SPatrice Chotard error("failed to disable all clocks\n"); 100155d9f65SPatrice Chotard 101155d9f65SPatrice Chotard return err; 102fee331f6SAlexey Brodkin } 103fee331f6SAlexey Brodkin 104fee331f6SAlexey Brodkin static int ohci_usb_remove(struct udevice *dev) 105fee331f6SAlexey Brodkin { 106155d9f65SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 107155d9f65SPatrice Chotard int ret; 108155d9f65SPatrice Chotard 109155d9f65SPatrice Chotard ret = ohci_deregister(dev); 110155d9f65SPatrice Chotard if (ret) 111155d9f65SPatrice Chotard return ret; 112155d9f65SPatrice Chotard 113*8a51b4b3SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 114*8a51b4b3SPatrice Chotard if (ret) 115*8a51b4b3SPatrice Chotard return ret; 116*8a51b4b3SPatrice Chotard 117155d9f65SPatrice Chotard return clk_release_all(priv->clocks, priv->clock_count); 118fee331f6SAlexey Brodkin } 119fee331f6SAlexey Brodkin 120fee331f6SAlexey Brodkin static const struct udevice_id ohci_usb_ids[] = { 121fee331f6SAlexey Brodkin { .compatible = "generic-ohci" }, 122fee331f6SAlexey Brodkin { } 123fee331f6SAlexey Brodkin }; 124fee331f6SAlexey Brodkin 125fee331f6SAlexey Brodkin U_BOOT_DRIVER(ohci_generic) = { 126fee331f6SAlexey Brodkin .name = "ohci_generic", 127fee331f6SAlexey Brodkin .id = UCLASS_USB, 128fee331f6SAlexey Brodkin .of_match = ohci_usb_ids, 129fee331f6SAlexey Brodkin .probe = ohci_usb_probe, 130fee331f6SAlexey Brodkin .remove = ohci_usb_remove, 131fee331f6SAlexey Brodkin .ops = &ohci_usb_ops, 132fee331f6SAlexey Brodkin .priv_auto_alloc_size = sizeof(struct generic_ohci), 133fee331f6SAlexey Brodkin .flags = DM_FLAG_ALLOC_PRIV_DMA, 134fee331f6SAlexey Brodkin }; 135