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 298a1be473SPatrice Chotard static int ohci_setup_phy(struct udevice *dev, int index) 308a1be473SPatrice Chotard { 318a1be473SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 328a1be473SPatrice Chotard int ret; 338a1be473SPatrice Chotard 348a1be473SPatrice Chotard ret = generic_phy_get_by_index(dev, index, &priv->phy); 358a1be473SPatrice Chotard if (ret) { 368a1be473SPatrice Chotard if (ret != -ENOENT) { 378a1be473SPatrice Chotard dev_err(dev, "failed to get usb phy\n"); 388a1be473SPatrice Chotard return ret; 398a1be473SPatrice Chotard } 408a1be473SPatrice Chotard } else { 418a1be473SPatrice Chotard ret = generic_phy_init(&priv->phy); 428a1be473SPatrice Chotard if (ret) { 438a1be473SPatrice Chotard dev_err(dev, "failed to init usb phy\n"); 448a1be473SPatrice Chotard return ret; 458a1be473SPatrice Chotard } 468a1be473SPatrice Chotard 478a1be473SPatrice Chotard ret = generic_phy_power_on(&priv->phy); 488a1be473SPatrice Chotard if (ret) { 498a1be473SPatrice Chotard dev_err(dev, "failed to power on usb phy\n"); 508a1be473SPatrice Chotard return generic_phy_exit(&priv->phy); 518a1be473SPatrice Chotard } 528a1be473SPatrice Chotard } 538a1be473SPatrice Chotard 548a1be473SPatrice Chotard return 0; 558a1be473SPatrice Chotard } 568a1be473SPatrice Chotard 578a1be473SPatrice Chotard static int ohci_shutdown_phy(struct udevice *dev) 588a1be473SPatrice Chotard { 598a1be473SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 608a1be473SPatrice Chotard int ret = 0; 618a1be473SPatrice Chotard 628a1be473SPatrice Chotard if (generic_phy_valid(&priv->phy)) { 638a1be473SPatrice Chotard ret = generic_phy_power_off(&priv->phy); 648a1be473SPatrice Chotard if (ret) { 658a1be473SPatrice Chotard dev_err(dev, "failed to power off usb phy\n"); 668a1be473SPatrice Chotard return ret; 678a1be473SPatrice Chotard } 688a1be473SPatrice Chotard 698a1be473SPatrice Chotard ret = generic_phy_exit(&priv->phy); 708a1be473SPatrice Chotard if (ret) { 718a1be473SPatrice Chotard dev_err(dev, "failed to power off usb phy\n"); 728a1be473SPatrice Chotard return ret; 738a1be473SPatrice Chotard } 748a1be473SPatrice Chotard } 758a1be473SPatrice Chotard 768a1be473SPatrice Chotard return 0; 778a1be473SPatrice Chotard } 788a1be473SPatrice Chotard 79fee331f6SAlexey Brodkin static int ohci_usb_probe(struct udevice *dev) 80fee331f6SAlexey Brodkin { 815ccb6a79SFrank Wang struct ohci_regs *regs; 82155d9f65SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 838a51b4b3SPatrice Chotard int i, err, ret, clock_nb, reset_nb; 84fee331f6SAlexey Brodkin 85155d9f65SPatrice Chotard err = 0; 86155d9f65SPatrice Chotard priv->clock_count = 0; 87155d9f65SPatrice Chotard clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); 88155d9f65SPatrice Chotard if (clock_nb > 0) { 89155d9f65SPatrice Chotard priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 90155d9f65SPatrice Chotard GFP_KERNEL); 91155d9f65SPatrice Chotard if (!priv->clocks) 92155d9f65SPatrice Chotard return -ENOMEM; 93155d9f65SPatrice Chotard 94155d9f65SPatrice Chotard for (i = 0; i < clock_nb; i++) { 95155d9f65SPatrice Chotard err = clk_get_by_index(dev, i, &priv->clocks[i]); 96155d9f65SPatrice Chotard if (err < 0) 97155d9f65SPatrice Chotard break; 98155d9f65SPatrice Chotard 99155d9f65SPatrice Chotard err = clk_enable(&priv->clocks[i]); 100*f7dd2187SPatrice Chotard if (err) { 101*f7dd2187SPatrice Chotard dev_err(dev, "failed to enable clock %d\n", i); 102155d9f65SPatrice Chotard clk_free(&priv->clocks[i]); 103155d9f65SPatrice Chotard goto clk_err; 104155d9f65SPatrice Chotard } 105155d9f65SPatrice Chotard priv->clock_count++; 106155d9f65SPatrice Chotard } 107155d9f65SPatrice Chotard } else if (clock_nb != -ENOENT) { 108*f7dd2187SPatrice Chotard dev_err(dev, "failed to get clock phandle(%d)\n", clock_nb); 109155d9f65SPatrice Chotard return clock_nb; 110155d9f65SPatrice Chotard } 111155d9f65SPatrice Chotard 1128a51b4b3SPatrice Chotard priv->reset_count = 0; 1138a51b4b3SPatrice Chotard reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells"); 1148a51b4b3SPatrice Chotard if (reset_nb > 0) { 1158a51b4b3SPatrice Chotard priv->resets = devm_kcalloc(dev, reset_nb, 1168a51b4b3SPatrice Chotard sizeof(struct reset_ctl), 1178a51b4b3SPatrice Chotard GFP_KERNEL); 1188a51b4b3SPatrice Chotard if (!priv->resets) 1198a51b4b3SPatrice Chotard return -ENOMEM; 1208a51b4b3SPatrice Chotard 1218a51b4b3SPatrice Chotard for (i = 0; i < reset_nb; i++) { 1228a51b4b3SPatrice Chotard err = reset_get_by_index(dev, i, &priv->resets[i]); 1238a51b4b3SPatrice Chotard if (err < 0) 1248a51b4b3SPatrice Chotard break; 1258a51b4b3SPatrice Chotard 1268a51b4b3SPatrice Chotard err = reset_deassert(&priv->resets[i]); 1278a51b4b3SPatrice Chotard if (err) { 128*f7dd2187SPatrice Chotard dev_err(dev, "failed to deassert reset %d\n", i); 1298a51b4b3SPatrice Chotard reset_free(&priv->resets[i]); 1308a51b4b3SPatrice Chotard goto reset_err; 1318a51b4b3SPatrice Chotard } 1328a51b4b3SPatrice Chotard priv->reset_count++; 1338a51b4b3SPatrice Chotard } 1348a51b4b3SPatrice Chotard } else if (reset_nb != -ENOENT) { 135*f7dd2187SPatrice Chotard dev_err(dev, "failed to get reset phandle(%d)\n", reset_nb); 1368a51b4b3SPatrice Chotard goto clk_err; 1378a51b4b3SPatrice Chotard } 1388a51b4b3SPatrice Chotard 1398a1be473SPatrice Chotard err = ohci_setup_phy(dev, 0); 1408a1be473SPatrice Chotard if (err) 14128df1cfdSPatrice Chotard goto reset_err; 14228df1cfdSPatrice Chotard 1435ccb6a79SFrank Wang regs = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE); 144155d9f65SPatrice Chotard err = ohci_register(dev, regs); 145155d9f65SPatrice Chotard if (err) 14628df1cfdSPatrice Chotard goto phy_err; 147155d9f65SPatrice Chotard 148155d9f65SPatrice Chotard return 0; 149155d9f65SPatrice Chotard 15028df1cfdSPatrice Chotard phy_err: 1518a1be473SPatrice Chotard ret = ohci_shutdown_phy(dev); 152324810fcSPatrice Chotard if (ret) 1538a1be473SPatrice Chotard dev_err(dev, "failed to shutdown usb phy\n"); 15428df1cfdSPatrice Chotard 1558a51b4b3SPatrice Chotard reset_err: 1568a51b4b3SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 1578a51b4b3SPatrice Chotard if (ret) 158*f7dd2187SPatrice Chotard dev_err(dev, "failed to assert all resets\n"); 159155d9f65SPatrice Chotard clk_err: 160155d9f65SPatrice Chotard ret = clk_release_all(priv->clocks, priv->clock_count); 161155d9f65SPatrice Chotard if (ret) 162*f7dd2187SPatrice Chotard dev_err(dev, "failed to disable all clocks\n"); 163155d9f65SPatrice Chotard 164155d9f65SPatrice Chotard return err; 165fee331f6SAlexey Brodkin } 166fee331f6SAlexey Brodkin 167fee331f6SAlexey Brodkin static int ohci_usb_remove(struct udevice *dev) 168fee331f6SAlexey Brodkin { 169155d9f65SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 170155d9f65SPatrice Chotard int ret; 171155d9f65SPatrice Chotard 172155d9f65SPatrice Chotard ret = ohci_deregister(dev); 173155d9f65SPatrice Chotard if (ret) 174155d9f65SPatrice Chotard return ret; 175155d9f65SPatrice Chotard 1768a1be473SPatrice Chotard ret = ohci_shutdown_phy(dev); 177324810fcSPatrice Chotard if (ret) 178324810fcSPatrice Chotard return ret; 179324810fcSPatrice Chotard 1808a51b4b3SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 1818a51b4b3SPatrice Chotard if (ret) 1828a51b4b3SPatrice Chotard return ret; 1838a51b4b3SPatrice Chotard 184155d9f65SPatrice Chotard return clk_release_all(priv->clocks, priv->clock_count); 185fee331f6SAlexey Brodkin } 186fee331f6SAlexey Brodkin 187fee331f6SAlexey Brodkin static const struct udevice_id ohci_usb_ids[] = { 188fee331f6SAlexey Brodkin { .compatible = "generic-ohci" }, 189fee331f6SAlexey Brodkin { } 190fee331f6SAlexey Brodkin }; 191fee331f6SAlexey Brodkin 192fee331f6SAlexey Brodkin U_BOOT_DRIVER(ohci_generic) = { 193fee331f6SAlexey Brodkin .name = "ohci_generic", 194fee331f6SAlexey Brodkin .id = UCLASS_USB, 195fee331f6SAlexey Brodkin .of_match = ohci_usb_ids, 196fee331f6SAlexey Brodkin .probe = ohci_usb_probe, 197fee331f6SAlexey Brodkin .remove = ohci_usb_remove, 198fee331f6SAlexey Brodkin .ops = &ohci_usb_ops, 199fee331f6SAlexey Brodkin .priv_auto_alloc_size = sizeof(struct generic_ohci), 200fee331f6SAlexey Brodkin .flags = DM_FLAG_ALLOC_PRIV_DMA, 201fee331f6SAlexey Brodkin }; 202