1 // SPDX-License-Identifier: GPL-2.0+
5 * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
8 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
12 #include <asm/arch/clock.h>
17 #include <generic-phy.h>
19 #ifdef CONFIG_SUNXI_GEN_SUN4I
20 #define AHB_CLK_DIST 2
22 #define AHB_CLK_DIST 1
25 struct ohci_sunxi_priv {
26 struct sunxi_ccm_reg *ccm;
28 int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
29 int usb_gate_mask; /* Mask of usb_clk_cfg clk gate bits for this hcd */
33 static int ohci_usb_probe(struct udevice *dev)
35 struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev);
36 struct ohci_sunxi_priv *priv = dev_get_priv(dev);
37 struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
38 int extra_ahb_gate_mask = 0;
41 priv->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
42 if (IS_ERR(priv->ccm))
43 return PTR_ERR(priv->ccm);
45 phys = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
51 ret = generic_phy_get_by_name(dev, "usb", &priv->phy);
53 pr_err("failed to get %s usb PHY\n", dev->name);
57 ret = generic_phy_init(&priv->phy);
59 pr_err("failed to init %s USB PHY\n", dev->name);
63 ret = generic_phy_power_on(&priv->phy);
65 pr_err("failed to power on %s USB PHY\n", dev->name);
70 bus_priv->companion = true;
73 * This should go away once we've moved to the driver model for
76 priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0;
77 #ifdef CONFIG_MACH_SUN8I_H3
78 extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0;
80 priv->usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK;
81 priv->ahb_gate_mask <<= phys * AHB_CLK_DIST;
82 extra_ahb_gate_mask <<= phys * AHB_CLK_DIST;
83 priv->usb_gate_mask <<= phys;
85 setbits_le32(&priv->ccm->ahb_gate0,
86 priv->ahb_gate_mask | extra_ahb_gate_mask);
87 setbits_le32(&priv->ccm->usb_clk_cfg, priv->usb_gate_mask);
88 #ifdef CONFIG_SUNXI_GEN_SUN6I
89 setbits_le32(&priv->ccm->ahb_reset0_cfg,
90 priv->ahb_gate_mask | extra_ahb_gate_mask);
93 return ohci_register(dev, regs);
96 static int ohci_usb_remove(struct udevice *dev)
98 struct ohci_sunxi_priv *priv = dev_get_priv(dev);
101 if (generic_phy_valid(&priv->phy)) {
102 ret = generic_phy_exit(&priv->phy);
104 pr_err("failed to exit %s USB PHY\n", dev->name);
109 ret = ohci_deregister(dev);
113 #ifdef CONFIG_SUNXI_GEN_SUN6I
114 clrbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask);
116 clrbits_le32(&priv->ccm->usb_clk_cfg, priv->usb_gate_mask);
117 clrbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask);
122 static const struct udevice_id ohci_usb_ids[] = {
123 { .compatible = "allwinner,sun4i-a10-ohci", },
124 { .compatible = "allwinner,sun5i-a13-ohci", },
125 { .compatible = "allwinner,sun6i-a31-ohci", },
126 { .compatible = "allwinner,sun7i-a20-ohci", },
127 { .compatible = "allwinner,sun8i-a23-ohci", },
128 { .compatible = "allwinner,sun8i-a83t-ohci", },
129 { .compatible = "allwinner,sun8i-h3-ohci", },
130 { .compatible = "allwinner,sun9i-a80-ohci", },
131 { .compatible = "allwinner,sun50i-a64-ohci", },
135 U_BOOT_DRIVER(usb_ohci) = {
136 .name = "ohci_sunxi",
138 .of_match = ohci_usb_ids,
139 .probe = ohci_usb_probe,
140 .remove = ohci_usb_remove,
141 .ops = &ohci_usb_ops,
142 .platdata_auto_alloc_size = sizeof(struct usb_platdata),
143 .priv_auto_alloc_size = sizeof(struct ohci_sunxi_priv),
144 .flags = DM_FLAG_ALLOC_PRIV_DMA,