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 29*8a1be473SPatrice Chotard static int ohci_setup_phy(struct udevice *dev, int index) 30*8a1be473SPatrice Chotard { 31*8a1be473SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 32*8a1be473SPatrice Chotard int ret; 33*8a1be473SPatrice Chotard 34*8a1be473SPatrice Chotard ret = generic_phy_get_by_index(dev, index, &priv->phy); 35*8a1be473SPatrice Chotard if (ret) { 36*8a1be473SPatrice Chotard if (ret != -ENOENT) { 37*8a1be473SPatrice Chotard dev_err(dev, "failed to get usb phy\n"); 38*8a1be473SPatrice Chotard return ret; 39*8a1be473SPatrice Chotard } 40*8a1be473SPatrice Chotard } else { 41*8a1be473SPatrice Chotard ret = generic_phy_init(&priv->phy); 42*8a1be473SPatrice Chotard if (ret) { 43*8a1be473SPatrice Chotard dev_err(dev, "failed to init usb phy\n"); 44*8a1be473SPatrice Chotard return ret; 45*8a1be473SPatrice Chotard } 46*8a1be473SPatrice Chotard 47*8a1be473SPatrice Chotard ret = generic_phy_power_on(&priv->phy); 48*8a1be473SPatrice Chotard if (ret) { 49*8a1be473SPatrice Chotard dev_err(dev, "failed to power on usb phy\n"); 50*8a1be473SPatrice Chotard return generic_phy_exit(&priv->phy); 51*8a1be473SPatrice Chotard } 52*8a1be473SPatrice Chotard } 53*8a1be473SPatrice Chotard 54*8a1be473SPatrice Chotard return 0; 55*8a1be473SPatrice Chotard } 56*8a1be473SPatrice Chotard 57*8a1be473SPatrice Chotard static int ohci_shutdown_phy(struct udevice *dev) 58*8a1be473SPatrice Chotard { 59*8a1be473SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 60*8a1be473SPatrice Chotard int ret = 0; 61*8a1be473SPatrice Chotard 62*8a1be473SPatrice Chotard if (generic_phy_valid(&priv->phy)) { 63*8a1be473SPatrice Chotard ret = generic_phy_power_off(&priv->phy); 64*8a1be473SPatrice Chotard if (ret) { 65*8a1be473SPatrice Chotard dev_err(dev, "failed to power off usb phy\n"); 66*8a1be473SPatrice Chotard return ret; 67*8a1be473SPatrice Chotard } 68*8a1be473SPatrice Chotard 69*8a1be473SPatrice Chotard ret = generic_phy_exit(&priv->phy); 70*8a1be473SPatrice Chotard if (ret) { 71*8a1be473SPatrice Chotard dev_err(dev, "failed to power off usb phy\n"); 72*8a1be473SPatrice Chotard return ret; 73*8a1be473SPatrice Chotard } 74*8a1be473SPatrice Chotard } 75*8a1be473SPatrice Chotard 76*8a1be473SPatrice Chotard return 0; 77*8a1be473SPatrice Chotard } 78*8a1be473SPatrice 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]); 100d2e45d1fSFrank Wang if (err && err != -ENOSYS) { 10190aa625cSMasahiro Yamada pr_err("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) { 10890aa625cSMasahiro Yamada pr_err("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) { 12890aa625cSMasahiro Yamada pr_err("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) { 13590aa625cSMasahiro Yamada pr_err("failed to get reset phandle(%d)\n", reset_nb); 1368a51b4b3SPatrice Chotard goto clk_err; 1378a51b4b3SPatrice Chotard } 1388a51b4b3SPatrice Chotard 139*8a1be473SPatrice Chotard err = ohci_setup_phy(dev, 0); 140*8a1be473SPatrice Chotard if (err) 14128df1cfdSPatrice Chotard 14228df1cfdSPatrice Chotard goto reset_err; 14328df1cfdSPatrice Chotard 1445ccb6a79SFrank Wang regs = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE); 145155d9f65SPatrice Chotard err = ohci_register(dev, regs); 146155d9f65SPatrice Chotard if (err) 14728df1cfdSPatrice Chotard goto phy_err; 148155d9f65SPatrice Chotard 149155d9f65SPatrice Chotard return 0; 150155d9f65SPatrice Chotard 15128df1cfdSPatrice Chotard phy_err: 152*8a1be473SPatrice Chotard ret = ohci_shutdown_phy(dev); 153324810fcSPatrice Chotard if (ret) 154*8a1be473SPatrice Chotard dev_err(dev, "failed to shutdown usb phy\n"); 15528df1cfdSPatrice Chotard 1568a51b4b3SPatrice Chotard reset_err: 1578a51b4b3SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 1588a51b4b3SPatrice Chotard if (ret) 15990aa625cSMasahiro Yamada pr_err("failed to assert all resets\n"); 160155d9f65SPatrice Chotard clk_err: 161155d9f65SPatrice Chotard ret = clk_release_all(priv->clocks, priv->clock_count); 162155d9f65SPatrice Chotard if (ret) 16390aa625cSMasahiro Yamada pr_err("failed to disable all clocks\n"); 164155d9f65SPatrice Chotard 165155d9f65SPatrice Chotard return err; 166fee331f6SAlexey Brodkin } 167fee331f6SAlexey Brodkin 168fee331f6SAlexey Brodkin static int ohci_usb_remove(struct udevice *dev) 169fee331f6SAlexey Brodkin { 170155d9f65SPatrice Chotard struct generic_ohci *priv = dev_get_priv(dev); 171155d9f65SPatrice Chotard int ret; 172155d9f65SPatrice Chotard 173155d9f65SPatrice Chotard ret = ohci_deregister(dev); 174155d9f65SPatrice Chotard if (ret) 175155d9f65SPatrice Chotard return ret; 176155d9f65SPatrice Chotard 177*8a1be473SPatrice Chotard ret = ohci_shutdown_phy(dev); 178324810fcSPatrice Chotard if (ret) 179324810fcSPatrice Chotard return ret; 180324810fcSPatrice Chotard 1818a51b4b3SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 1828a51b4b3SPatrice Chotard if (ret) 1838a51b4b3SPatrice Chotard return ret; 1848a51b4b3SPatrice Chotard 185155d9f65SPatrice Chotard return clk_release_all(priv->clocks, priv->clock_count); 186fee331f6SAlexey Brodkin } 187fee331f6SAlexey Brodkin 188fee331f6SAlexey Brodkin static const struct udevice_id ohci_usb_ids[] = { 189fee331f6SAlexey Brodkin { .compatible = "generic-ohci" }, 190fee331f6SAlexey Brodkin { } 191fee331f6SAlexey Brodkin }; 192fee331f6SAlexey Brodkin 193fee331f6SAlexey Brodkin U_BOOT_DRIVER(ohci_generic) = { 194fee331f6SAlexey Brodkin .name = "ohci_generic", 195fee331f6SAlexey Brodkin .id = UCLASS_USB, 196fee331f6SAlexey Brodkin .of_match = ohci_usb_ids, 197fee331f6SAlexey Brodkin .probe = ohci_usb_probe, 198fee331f6SAlexey Brodkin .remove = ohci_usb_remove, 199fee331f6SAlexey Brodkin .ops = &ohci_usb_ops, 200fee331f6SAlexey Brodkin .priv_auto_alloc_size = sizeof(struct generic_ohci), 201fee331f6SAlexey Brodkin .flags = DM_FLAG_ALLOC_PRIV_DMA, 202fee331f6SAlexey Brodkin }; 203