190fbb282SAlexey Brodkin /*
290fbb282SAlexey Brodkin * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
390fbb282SAlexey Brodkin *
490fbb282SAlexey Brodkin * SPDX-License-Identifier: GPL-2.0+
590fbb282SAlexey Brodkin */
690fbb282SAlexey Brodkin
790fbb282SAlexey Brodkin #include <common.h>
84feefdcfSMasahiro Yamada #include <clk.h>
9a1cee8e8SPatrice Chotard #include <dm/ofnode.h>
100d0ba1a7SPatrice Chotard #include <generic-phy.h>
118824cfc1SMasahiro Yamada #include <reset.h>
12643cacb6SMarek Vasut #include <asm/io.h>
1390fbb282SAlexey Brodkin #include <dm.h>
1490fbb282SAlexey Brodkin #include "ehci.h"
154e900a7dSPatrice Chotard #include <power/regulator.h>
1690fbb282SAlexey Brodkin
1790fbb282SAlexey Brodkin /*
1890fbb282SAlexey Brodkin * Even though here we don't explicitly use "struct ehci_ctrl"
1990fbb282SAlexey Brodkin * ehci_register() expects it to be the first thing that resides in
2090fbb282SAlexey Brodkin * device's private data.
2190fbb282SAlexey Brodkin */
2290fbb282SAlexey Brodkin struct generic_ehci {
2390fbb282SAlexey Brodkin struct ehci_ctrl ctrl;
24a1cee8e8SPatrice Chotard struct clk *clocks;
25a1cee8e8SPatrice Chotard struct reset_ctl *resets;
260d0ba1a7SPatrice Chotard struct phy phy;
274e900a7dSPatrice Chotard #ifdef CONFIG_DM_REGULATOR
284e900a7dSPatrice Chotard struct udevice *vbus_supply;
294e900a7dSPatrice Chotard #endif
30a1cee8e8SPatrice Chotard int clock_count;
31a1cee8e8SPatrice Chotard int reset_count;
3290fbb282SAlexey Brodkin };
3390fbb282SAlexey Brodkin
344e900a7dSPatrice Chotard #ifdef CONFIG_DM_REGULATOR
ehci_enable_vbus_supply(struct udevice * dev)354e900a7dSPatrice Chotard static int ehci_enable_vbus_supply(struct udevice *dev)
364e900a7dSPatrice Chotard {
374e900a7dSPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev);
384e900a7dSPatrice Chotard int ret;
394e900a7dSPatrice Chotard
404e900a7dSPatrice Chotard ret = device_get_supply_regulator(dev, "vbus-supply",
414e900a7dSPatrice Chotard &priv->vbus_supply);
424e900a7dSPatrice Chotard if (ret && ret != -ENOENT)
434e900a7dSPatrice Chotard return ret;
444e900a7dSPatrice Chotard
454e900a7dSPatrice Chotard if (priv->vbus_supply) {
464e900a7dSPatrice Chotard ret = regulator_set_enable(priv->vbus_supply, true);
474e900a7dSPatrice Chotard if (ret) {
484e900a7dSPatrice Chotard dev_err(dev, "Error enabling VBUS supply\n");
494e900a7dSPatrice Chotard return ret;
504e900a7dSPatrice Chotard }
514e900a7dSPatrice Chotard } else {
524e900a7dSPatrice Chotard dev_dbg(dev, "No vbus supply\n");
534e900a7dSPatrice Chotard }
544e900a7dSPatrice Chotard
554e900a7dSPatrice Chotard return 0;
564e900a7dSPatrice Chotard }
574e900a7dSPatrice Chotard
ehci_disable_vbus_supply(struct generic_ehci * priv)584e900a7dSPatrice Chotard static int ehci_disable_vbus_supply(struct generic_ehci *priv)
594e900a7dSPatrice Chotard {
604e900a7dSPatrice Chotard if (priv->vbus_supply)
614e900a7dSPatrice Chotard return regulator_set_enable(priv->vbus_supply, false);
624e900a7dSPatrice Chotard else
634e900a7dSPatrice Chotard return 0;
644e900a7dSPatrice Chotard }
654e900a7dSPatrice Chotard #else
ehci_enable_vbus_supply(struct udevice * dev)664e900a7dSPatrice Chotard static int ehci_enable_vbus_supply(struct udevice *dev)
674e900a7dSPatrice Chotard {
684e900a7dSPatrice Chotard return 0;
694e900a7dSPatrice Chotard }
704e900a7dSPatrice Chotard
ehci_disable_vbus_supply(struct generic_ehci * priv)714e900a7dSPatrice Chotard static int ehci_disable_vbus_supply(struct generic_ehci *priv)
724e900a7dSPatrice Chotard {
734e900a7dSPatrice Chotard return 0;
744e900a7dSPatrice Chotard }
754e900a7dSPatrice Chotard #endif
764e900a7dSPatrice Chotard
ehci_usb_probe(struct udevice * dev)7790fbb282SAlexey Brodkin static int ehci_usb_probe(struct udevice *dev)
7890fbb282SAlexey Brodkin {
79a1cee8e8SPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev);
80643cacb6SMarek Vasut struct ehci_hccr *hccr;
8190fbb282SAlexey Brodkin struct ehci_hcor *hcor;
82a1cee8e8SPatrice Chotard int i, err, ret, clock_nb, reset_nb;
834feefdcfSMasahiro Yamada
84a1cee8e8SPatrice Chotard err = 0;
85a1cee8e8SPatrice Chotard priv->clock_count = 0;
86a1cee8e8SPatrice Chotard clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
87a1cee8e8SPatrice Chotard "#clock-cells");
88a1cee8e8SPatrice Chotard if (clock_nb > 0) {
89a1cee8e8SPatrice Chotard priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
90a1cee8e8SPatrice Chotard GFP_KERNEL);
91a1cee8e8SPatrice Chotard if (!priv->clocks)
92a1cee8e8SPatrice Chotard return -ENOMEM;
934feefdcfSMasahiro Yamada
94a1cee8e8SPatrice Chotard for (i = 0; i < clock_nb; i++) {
95a1cee8e8SPatrice Chotard err = clk_get_by_index(dev, i, &priv->clocks[i]);
96a1cee8e8SPatrice Chotard
97a1cee8e8SPatrice Chotard if (err < 0)
984feefdcfSMasahiro Yamada break;
99a1cee8e8SPatrice Chotard err = clk_enable(&priv->clocks[i]);
100*5311a685SKever Yang if (err && err != -ENOSYS) {
101b653780cSPatrice Chotard dev_err(dev, "failed to enable clock %d\n", i);
102a1cee8e8SPatrice Chotard clk_free(&priv->clocks[i]);
103a1cee8e8SPatrice Chotard goto clk_err;
104a1cee8e8SPatrice Chotard }
105a1cee8e8SPatrice Chotard priv->clock_count++;
106a1cee8e8SPatrice Chotard }
107a1cee8e8SPatrice Chotard } else {
108a1cee8e8SPatrice Chotard if (clock_nb != -ENOENT) {
109b653780cSPatrice Chotard dev_err(dev, "failed to get clock phandle(%d)\n",
110b653780cSPatrice Chotard clock_nb);
111a1cee8e8SPatrice Chotard return clock_nb;
112a1cee8e8SPatrice Chotard }
1134feefdcfSMasahiro Yamada }
11490fbb282SAlexey Brodkin
115a1cee8e8SPatrice Chotard priv->reset_count = 0;
116a1cee8e8SPatrice Chotard reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
117a1cee8e8SPatrice Chotard "#reset-cells");
118a1cee8e8SPatrice Chotard if (reset_nb > 0) {
119a1cee8e8SPatrice Chotard priv->resets = devm_kcalloc(dev, reset_nb,
120a1cee8e8SPatrice Chotard sizeof(struct reset_ctl),
121a1cee8e8SPatrice Chotard GFP_KERNEL);
122a1cee8e8SPatrice Chotard if (!priv->resets)
123a1cee8e8SPatrice Chotard return -ENOMEM;
1248824cfc1SMasahiro Yamada
125a1cee8e8SPatrice Chotard for (i = 0; i < reset_nb; i++) {
126a1cee8e8SPatrice Chotard err = reset_get_by_index(dev, i, &priv->resets[i]);
127a1cee8e8SPatrice Chotard if (err < 0)
1288824cfc1SMasahiro Yamada break;
129a1cee8e8SPatrice Chotard
130a1cee8e8SPatrice Chotard if (reset_deassert(&priv->resets[i])) {
131b653780cSPatrice Chotard dev_err(dev, "failed to deassert reset %d\n",
132b653780cSPatrice Chotard i);
133a1cee8e8SPatrice Chotard reset_free(&priv->resets[i]);
134a1cee8e8SPatrice Chotard goto reset_err;
135a1cee8e8SPatrice Chotard }
136a1cee8e8SPatrice Chotard priv->reset_count++;
137a1cee8e8SPatrice Chotard }
138a1cee8e8SPatrice Chotard } else {
139a1cee8e8SPatrice Chotard if (reset_nb != -ENOENT) {
140b653780cSPatrice Chotard dev_err(dev, "failed to get reset phandle(%d)\n",
141b653780cSPatrice Chotard reset_nb);
142a1cee8e8SPatrice Chotard goto clk_err;
143a1cee8e8SPatrice Chotard }
1448824cfc1SMasahiro Yamada }
1458824cfc1SMasahiro Yamada
1464e900a7dSPatrice Chotard err = ehci_enable_vbus_supply(dev);
147f06fcfdeSPatrice Chotard if (err)
1480d0ba1a7SPatrice Chotard goto reset_err;
1490d0ba1a7SPatrice Chotard
1504e900a7dSPatrice Chotard err = ehci_setup_phy(dev, &priv->phy, 0);
1514e900a7dSPatrice Chotard if (err)
1524e900a7dSPatrice Chotard goto regulator_err;
1534e900a7dSPatrice Chotard
15497ff91faSPhilipp Tomsich hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
15590fbb282SAlexey Brodkin hcor = (struct ehci_hcor *)((uintptr_t)hccr +
15690fbb282SAlexey Brodkin HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
15790fbb282SAlexey Brodkin
158a1cee8e8SPatrice Chotard err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
159a1cee8e8SPatrice Chotard if (err)
1600d0ba1a7SPatrice Chotard goto phy_err;
161a1cee8e8SPatrice Chotard
162a1cee8e8SPatrice Chotard return 0;
163a1cee8e8SPatrice Chotard
1640d0ba1a7SPatrice Chotard phy_err:
165f5439a16SMarek Vasut ret = ehci_shutdown_phy(dev, &priv->phy);
1663d54c056SPatrice Chotard if (ret)
167f06fcfdeSPatrice Chotard dev_err(dev, "failed to shutdown usb phy\n");
1680d0ba1a7SPatrice Chotard
1694e900a7dSPatrice Chotard regulator_err:
1704e900a7dSPatrice Chotard ret = ehci_disable_vbus_supply(priv);
1714e900a7dSPatrice Chotard if (ret)
1724e900a7dSPatrice Chotard dev_err(dev, "failed to disable VBUS supply\n");
1734e900a7dSPatrice Chotard
174a1cee8e8SPatrice Chotard reset_err:
175a1cee8e8SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count);
176a1cee8e8SPatrice Chotard if (ret)
177b653780cSPatrice Chotard dev_err(dev, "failed to assert all resets\n");
178a1cee8e8SPatrice Chotard clk_err:
179a1cee8e8SPatrice Chotard ret = clk_release_all(priv->clocks, priv->clock_count);
180a1cee8e8SPatrice Chotard if (ret)
181b653780cSPatrice Chotard dev_err(dev, "failed to disable all clocks\n");
182a1cee8e8SPatrice Chotard
183a1cee8e8SPatrice Chotard return err;
184a1cee8e8SPatrice Chotard }
185a1cee8e8SPatrice Chotard
ehci_usb_remove(struct udevice * dev)186a1cee8e8SPatrice Chotard static int ehci_usb_remove(struct udevice *dev)
187a1cee8e8SPatrice Chotard {
188a1cee8e8SPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev);
189a1cee8e8SPatrice Chotard int ret;
190a1cee8e8SPatrice Chotard
191a1cee8e8SPatrice Chotard ret = ehci_deregister(dev);
192a1cee8e8SPatrice Chotard if (ret)
193a1cee8e8SPatrice Chotard return ret;
194a1cee8e8SPatrice Chotard
195f5439a16SMarek Vasut ret = ehci_shutdown_phy(dev, &priv->phy);
1963d54c056SPatrice Chotard if (ret)
1973d54c056SPatrice Chotard return ret;
1983d54c056SPatrice Chotard
1994e900a7dSPatrice Chotard ret = ehci_disable_vbus_supply(priv);
2004e900a7dSPatrice Chotard if (ret)
2014e900a7dSPatrice Chotard return ret;
2024e900a7dSPatrice Chotard
203a1cee8e8SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count);
204a1cee8e8SPatrice Chotard if (ret)
205a1cee8e8SPatrice Chotard return ret;
206a1cee8e8SPatrice Chotard
207a1cee8e8SPatrice Chotard return clk_release_all(priv->clocks, priv->clock_count);
20890fbb282SAlexey Brodkin }
20990fbb282SAlexey Brodkin
21090fbb282SAlexey Brodkin static const struct udevice_id ehci_usb_ids[] = {
21190fbb282SAlexey Brodkin { .compatible = "generic-ehci" },
21290fbb282SAlexey Brodkin { }
21390fbb282SAlexey Brodkin };
21490fbb282SAlexey Brodkin
21590fbb282SAlexey Brodkin U_BOOT_DRIVER(ehci_generic) = {
21690fbb282SAlexey Brodkin .name = "ehci_generic",
21790fbb282SAlexey Brodkin .id = UCLASS_USB,
21890fbb282SAlexey Brodkin .of_match = ehci_usb_ids,
21990fbb282SAlexey Brodkin .probe = ehci_usb_probe,
220a1cee8e8SPatrice Chotard .remove = ehci_usb_remove,
22190fbb282SAlexey Brodkin .ops = &ehci_usb_ops,
22290fbb282SAlexey Brodkin .priv_auto_alloc_size = sizeof(struct generic_ehci),
22390fbb282SAlexey Brodkin .flags = DM_FLAG_ALLOC_PRIV_DMA,
22490fbb282SAlexey Brodkin };
225