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 75ccb6a79SFrank Wang #include <asm/io.h> 8fee331f6SAlexey Brodkin #include <common.h> 9155d9f65SPatrice Chotard #include <clk.h> 10fee331f6SAlexey Brodkin #include <dm.h> 11155d9f65SPatrice Chotard #include <dm/ofnode.h> 1228df1cfdSPatrice Chotard #include <generic-phy.h> 138a51b4b3SPatrice Chotard #include <reset.h> 14fee331f6SAlexey Brodkin #include "ohci.h" 15fee331f6SAlexey Brodkin 16fee331f6SAlexey Brodkin #if !defined(CONFIG_USB_OHCI_NEW) 17fee331f6SAlexey Brodkin # error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW" 18fee331f6SAlexey Brodkin #endif 19fee331f6SAlexey Brodkin 20fee331f6SAlexey Brodkin struct generic_ohci { 21fee331f6SAlexey Brodkin ohci_t ohci; 22155d9f65SPatrice Chotard struct clk *clocks; /* clock list */ 238a51b4b3SPatrice Chotard struct reset_ctl *resets; /* reset list */ 2428df1cfdSPatrice Chotard struct phy phy; 25155d9f65SPatrice Chotard int clock_count; /* number of clock in clock list */ 268a51b4b3SPatrice Chotard int reset_count; /* number of reset in reset list */ 27fee331f6SAlexey Brodkin }; 28fee331f6SAlexey Brodkin 29fee331f6SAlexey Brodkin static int ohci_usb_probe(struct udevice *dev) 30fee331f6SAlexey Brodkin { 315ccb6a79SFrank Wang struct ohci_regs *regs; 32155d9f65SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 338a51b4b3SPatrice Chotard int i, err, ret, clock_nb, reset_nb; 34fee331f6SAlexey Brodkin 35155d9f65SPatrice Chotard err = 0; 36155d9f65SPatrice Chotard priv->clock_count = 0; 37155d9f65SPatrice Chotard clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); 38155d9f65SPatrice Chotard if (clock_nb > 0) { 39155d9f65SPatrice Chotard priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 40155d9f65SPatrice Chotard GFP_KERNEL); 41155d9f65SPatrice Chotard if (!priv->clocks) 42155d9f65SPatrice Chotard return -ENOMEM; 43155d9f65SPatrice Chotard 44155d9f65SPatrice Chotard for (i = 0; i < clock_nb; i++) { 45155d9f65SPatrice Chotard err = clk_get_by_index(dev, i, &priv->clocks[i]); 46155d9f65SPatrice Chotard if (err < 0) 47155d9f65SPatrice Chotard break; 48155d9f65SPatrice Chotard 49155d9f65SPatrice Chotard err = clk_enable(&priv->clocks[i]); 50*d2e45d1fSFrank Wang if (err && err != -ENOSYS) { 5190aa625cSMasahiro Yamada pr_err("failed to enable clock %d\n", i); 52155d9f65SPatrice Chotard clk_free(&priv->clocks[i]); 53155d9f65SPatrice Chotard goto clk_err; 54155d9f65SPatrice Chotard } 55155d9f65SPatrice Chotard priv->clock_count++; 56155d9f65SPatrice Chotard } 57155d9f65SPatrice Chotard } else if (clock_nb != -ENOENT) { 5890aa625cSMasahiro Yamada pr_err("failed to get clock phandle(%d)\n", clock_nb); 59155d9f65SPatrice Chotard return clock_nb; 60155d9f65SPatrice Chotard } 61155d9f65SPatrice Chotard 628a51b4b3SPatrice Chotard priv->reset_count = 0; 638a51b4b3SPatrice Chotard reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells"); 648a51b4b3SPatrice Chotard if (reset_nb > 0) { 658a51b4b3SPatrice Chotard priv->resets = devm_kcalloc(dev, reset_nb, 668a51b4b3SPatrice Chotard sizeof(struct reset_ctl), 678a51b4b3SPatrice Chotard GFP_KERNEL); 688a51b4b3SPatrice Chotard if (!priv->resets) 698a51b4b3SPatrice Chotard return -ENOMEM; 708a51b4b3SPatrice Chotard 718a51b4b3SPatrice Chotard for (i = 0; i < reset_nb; i++) { 728a51b4b3SPatrice Chotard err = reset_get_by_index(dev, i, &priv->resets[i]); 738a51b4b3SPatrice Chotard if (err < 0) 748a51b4b3SPatrice Chotard break; 758a51b4b3SPatrice Chotard 768a51b4b3SPatrice Chotard err = reset_deassert(&priv->resets[i]); 778a51b4b3SPatrice Chotard if (err) { 7890aa625cSMasahiro Yamada pr_err("failed to deassert reset %d\n", i); 798a51b4b3SPatrice Chotard reset_free(&priv->resets[i]); 808a51b4b3SPatrice Chotard goto reset_err; 818a51b4b3SPatrice Chotard } 828a51b4b3SPatrice Chotard priv->reset_count++; 838a51b4b3SPatrice Chotard } 848a51b4b3SPatrice Chotard } else if (reset_nb != -ENOENT) { 8590aa625cSMasahiro Yamada pr_err("failed to get reset phandle(%d)\n", reset_nb); 868a51b4b3SPatrice Chotard goto clk_err; 878a51b4b3SPatrice Chotard } 888a51b4b3SPatrice Chotard 8928df1cfdSPatrice Chotard err = generic_phy_get_by_index(dev, 0, &priv->phy); 9028df1cfdSPatrice Chotard if (err) { 9128df1cfdSPatrice Chotard if (err != -ENOENT) { 9290aa625cSMasahiro Yamada pr_err("failed to get usb phy\n"); 9328df1cfdSPatrice Chotard goto reset_err; 9428df1cfdSPatrice Chotard } 952080d023SPatrice Chotard } else { 9628df1cfdSPatrice Chotard 9728df1cfdSPatrice Chotard err = generic_phy_init(&priv->phy); 9828df1cfdSPatrice Chotard if (err) { 9990aa625cSMasahiro Yamada pr_err("failed to init usb phy\n"); 10028df1cfdSPatrice Chotard goto reset_err; 10128df1cfdSPatrice Chotard } 1022080d023SPatrice Chotard } 10328df1cfdSPatrice Chotard 1045ccb6a79SFrank Wang regs = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE); 105155d9f65SPatrice Chotard err = ohci_register(dev, regs); 106155d9f65SPatrice Chotard if (err) 10728df1cfdSPatrice Chotard goto phy_err; 108155d9f65SPatrice Chotard 109155d9f65SPatrice Chotard return 0; 110155d9f65SPatrice Chotard 11128df1cfdSPatrice Chotard phy_err: 11228df1cfdSPatrice Chotard if (generic_phy_valid(&priv->phy)) { 11328df1cfdSPatrice Chotard ret = generic_phy_exit(&priv->phy); 11428df1cfdSPatrice Chotard if (ret) 11590aa625cSMasahiro Yamada pr_err("failed to release phy\n"); 11628df1cfdSPatrice Chotard } 11728df1cfdSPatrice Chotard 1188a51b4b3SPatrice Chotard reset_err: 1198a51b4b3SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 1208a51b4b3SPatrice Chotard if (ret) 12190aa625cSMasahiro Yamada pr_err("failed to assert all resets\n"); 122155d9f65SPatrice Chotard clk_err: 123155d9f65SPatrice Chotard ret = clk_release_all(priv->clocks, priv->clock_count); 124155d9f65SPatrice Chotard if (ret) 12590aa625cSMasahiro Yamada pr_err("failed to disable all clocks\n"); 126155d9f65SPatrice Chotard 127155d9f65SPatrice Chotard return err; 128fee331f6SAlexey Brodkin } 129fee331f6SAlexey Brodkin 130fee331f6SAlexey Brodkin static int ohci_usb_remove(struct udevice *dev) 131fee331f6SAlexey Brodkin { 132155d9f65SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 133155d9f65SPatrice Chotard int ret; 134155d9f65SPatrice Chotard 135155d9f65SPatrice Chotard ret = ohci_deregister(dev); 136155d9f65SPatrice Chotard if (ret) 137155d9f65SPatrice Chotard return ret; 138155d9f65SPatrice Chotard 13928df1cfdSPatrice Chotard if (generic_phy_valid(&priv->phy)) { 14028df1cfdSPatrice Chotard ret = generic_phy_exit(&priv->phy); 14128df1cfdSPatrice Chotard if (ret) 14228df1cfdSPatrice Chotard return ret; 14328df1cfdSPatrice Chotard } 14428df1cfdSPatrice Chotard 1458a51b4b3SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 1468a51b4b3SPatrice Chotard if (ret) 1478a51b4b3SPatrice Chotard return ret; 1488a51b4b3SPatrice Chotard 149155d9f65SPatrice Chotard return clk_release_all(priv->clocks, priv->clock_count); 150fee331f6SAlexey Brodkin } 151fee331f6SAlexey Brodkin 152fee331f6SAlexey Brodkin static const struct udevice_id ohci_usb_ids[] = { 153fee331f6SAlexey Brodkin { .compatible = "generic-ohci" }, 154fee331f6SAlexey Brodkin { } 155fee331f6SAlexey Brodkin }; 156fee331f6SAlexey Brodkin 157fee331f6SAlexey Brodkin U_BOOT_DRIVER(ohci_generic) = { 158fee331f6SAlexey Brodkin .name = "ohci_generic", 159fee331f6SAlexey Brodkin .id = UCLASS_USB, 160fee331f6SAlexey Brodkin .of_match = ohci_usb_ids, 161fee331f6SAlexey Brodkin .probe = ohci_usb_probe, 162fee331f6SAlexey Brodkin .remove = ohci_usb_remove, 163fee331f6SAlexey Brodkin .ops = &ohci_usb_ops, 164fee331f6SAlexey Brodkin .priv_auto_alloc_size = sizeof(struct generic_ohci), 165fee331f6SAlexey Brodkin .flags = DM_FLAG_ALLOC_PRIV_DMA, 166fee331f6SAlexey Brodkin }; 167