blob: 936e30438d9ff32e1d95fa04fbc861c31ebc94fe [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Alexey Brodkina6aff432015-12-02 12:32:02 +03002/*
3 * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
Alexey Brodkina6aff432015-12-02 12:32:02 +03004 */
5
6#include <common.h>
Masahiro Yamadafbb66bf2016-01-25 15:00:36 +09007#include <clk.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -07009#include <dm/device_compat.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070010#include <dm/devres.h>
Patrice Chotarda0809dc2017-07-18 11:57:10 +020011#include <dm/ofnode.h>
Patrice Chotard1a62cde2017-07-18 11:57:11 +020012#include <generic-phy.h>
Masahiro Yamada8a5a1802016-09-21 11:29:02 +090013#include <reset.h>
Marek Vasut851fecc2016-01-23 21:04:46 +010014#include <asm/io.h>
Alexey Brodkina6aff432015-12-02 12:32:02 +030015#include <dm.h>
16#include "ehci.h"
Patrice Chotardfc424682018-09-04 11:37:25 +020017#include <power/regulator.h>
Alexey Brodkina6aff432015-12-02 12:32:02 +030018
19/*
20 * Even though here we don't explicitly use "struct ehci_ctrl"
21 * ehci_register() expects it to be the first thing that resides in
22 * device's private data.
23 */
24struct generic_ehci {
25 struct ehci_ctrl ctrl;
Patrice Chotard0ef45712022-05-06 08:22:34 +020026 struct clk_bulk clocks;
27 struct reset_ctl_bulk resets;
Patrice Chotard1a62cde2017-07-18 11:57:11 +020028 struct phy phy;
Patrice Chotardfc424682018-09-04 11:37:25 +020029 struct udevice *vbus_supply;
Alexey Brodkina6aff432015-12-02 12:32:02 +030030};
31
Patrice Chotardfc424682018-09-04 11:37:25 +020032static int ehci_enable_vbus_supply(struct udevice *dev)
33{
34 struct generic_ehci *priv = dev_get_priv(dev);
35 int ret;
36
37 ret = device_get_supply_regulator(dev, "vbus-supply",
38 &priv->vbus_supply);
39 if (ret && ret != -ENOENT)
40 return ret;
41
Jonas Karlman2b9e2482023-07-19 21:20:57 +000042 ret = regulator_set_enable_if_allowed(priv->vbus_supply, true);
43 if (ret && ret != -ENOSYS) {
44 dev_err(dev, "Error enabling VBUS supply (ret=%d)\n", ret);
45 return ret;
Patrice Chotardfc424682018-09-04 11:37:25 +020046 }
47
48 return 0;
49}
50
51static int ehci_disable_vbus_supply(struct generic_ehci *priv)
52{
Jonas Karlman2b9e2482023-07-19 21:20:57 +000053 int ret;
54
55 ret = regulator_set_enable_if_allowed(priv->vbus_supply, false);
56 if (ret && ret != -ENOSYS)
57 return ret;
58
59 return 0;
Patrice Chotardfc424682018-09-04 11:37:25 +020060}
Patrice Chotardfc424682018-09-04 11:37:25 +020061
Alexey Brodkina6aff432015-12-02 12:32:02 +030062static int ehci_usb_probe(struct udevice *dev)
63{
Patrice Chotarda0809dc2017-07-18 11:57:10 +020064 struct generic_ehci *priv = dev_get_priv(dev);
Marek Vasut851fecc2016-01-23 21:04:46 +010065 struct ehci_hccr *hccr;
Alexey Brodkina6aff432015-12-02 12:32:02 +030066 struct ehci_hcor *hcor;
Patrice Chotard0ef45712022-05-06 08:22:34 +020067 int err, ret;
Masahiro Yamadafbb66bf2016-01-25 15:00:36 +090068
Patrice Chotarda0809dc2017-07-18 11:57:10 +020069 err = 0;
Patrice Chotard0ef45712022-05-06 08:22:34 +020070 ret = clk_get_bulk(dev, &priv->clocks);
Andre Przywarafbcb8f02022-06-08 00:42:22 +010071 if (ret && ret != -ENOENT) {
Patrice Chotard0ef45712022-05-06 08:22:34 +020072 dev_err(dev, "Failed to get clocks (ret=%d)\n", ret);
73 return ret;
Masahiro Yamadafbb66bf2016-01-25 15:00:36 +090074 }
Alexey Brodkina6aff432015-12-02 12:32:02 +030075
Patrice Chotard0ef45712022-05-06 08:22:34 +020076 err = clk_enable_bulk(&priv->clocks);
77 if (err) {
78 dev_err(dev, "Failed to enable clocks (err=%d)\n", err);
79 goto clk_err;
80 }
Masahiro Yamada8a5a1802016-09-21 11:29:02 +090081
Patrice Chotard0ef45712022-05-06 08:22:34 +020082 err = reset_get_bulk(dev, &priv->resets);
Andre Przywara47bb0dc2022-07-02 01:45:10 +010083 if (err && err != -ENOENT) {
Patrice Chotard0ef45712022-05-06 08:22:34 +020084 dev_err(dev, "Failed to get resets (err=%d)\n", err);
85 goto clk_err;
86 }
Patrice Chotarda0809dc2017-07-18 11:57:10 +020087
Patrice Chotard0ef45712022-05-06 08:22:34 +020088 err = reset_deassert_bulk(&priv->resets);
89 if (err) {
90 dev_err(dev, "Failed to get deassert resets (err=%d)\n", err);
91 goto reset_err;
Masahiro Yamada8a5a1802016-09-21 11:29:02 +090092 }
93
Patrice Chotardfc424682018-09-04 11:37:25 +020094 err = ehci_enable_vbus_supply(dev);
Patrice Chotard36afc032018-03-14 17:48:54 +010095 if (err)
Patrice Chotard36afc032018-03-14 17:48:54 +010096 goto reset_err;
Patrice Chotard1a62cde2017-07-18 11:57:11 +020097
Patrice Chotard343ff752022-09-06 08:15:28 +020098 err = generic_setup_phy(dev, &priv->phy, 0);
Patrice Chotardfc424682018-09-04 11:37:25 +020099 if (err)
100 goto regulator_err;
101
Philipp Tomsich9f3f4232017-09-12 17:32:28 +0200102 hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
Alexey Brodkina6aff432015-12-02 12:32:02 +0300103 hcor = (struct ehci_hcor *)((uintptr_t)hccr +
104 HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
105
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200106 err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
107 if (err)
Patrice Chotard1a62cde2017-07-18 11:57:11 +0200108 goto phy_err;
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200109
110 return 0;
111
Patrice Chotard1a62cde2017-07-18 11:57:11 +0200112phy_err:
Patrice Chotard343ff752022-09-06 08:15:28 +0200113 ret = generic_shutdown_phy(&priv->phy);
Patrice Chotard36afc032018-03-14 17:48:54 +0100114 if (ret)
Patrice Chotard0ef45712022-05-06 08:22:34 +0200115 dev_err(dev, "failed to shutdown usb phy (ret=%d)\n", ret);
Patrice Chotard1a62cde2017-07-18 11:57:11 +0200116
Patrice Chotardfc424682018-09-04 11:37:25 +0200117regulator_err:
118 ret = ehci_disable_vbus_supply(priv);
119 if (ret)
Patrice Chotard0ef45712022-05-06 08:22:34 +0200120 dev_err(dev, "failed to disable VBUS supply (ret=%d)\n", ret);
Patrice Chotardfc424682018-09-04 11:37:25 +0200121
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200122reset_err:
Patrice Chotard0ef45712022-05-06 08:22:34 +0200123 ret = reset_release_bulk(&priv->resets);
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200124 if (ret)
Patrice Chotard0ef45712022-05-06 08:22:34 +0200125 dev_err(dev, "failed to release resets (ret=%d)\n", ret);
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200126clk_err:
Patrice Chotard0ef45712022-05-06 08:22:34 +0200127 ret = clk_release_bulk(&priv->clocks);
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200128 if (ret)
Patrice Chotard0ef45712022-05-06 08:22:34 +0200129 dev_err(dev, "failed to release clocks (ret=%d)\n", ret);
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200130
131 return err;
132}
133
134static int ehci_usb_remove(struct udevice *dev)
135{
136 struct generic_ehci *priv = dev_get_priv(dev);
137 int ret;
138
139 ret = ehci_deregister(dev);
140 if (ret)
141 return ret;
142
Patrice Chotard343ff752022-09-06 08:15:28 +0200143 ret = generic_shutdown_phy(&priv->phy);
Patrice Chotard36afc032018-03-14 17:48:54 +0100144 if (ret)
145 return ret;
Patrice Chotard1a62cde2017-07-18 11:57:11 +0200146
Patrice Chotardfc424682018-09-04 11:37:25 +0200147 ret = ehci_disable_vbus_supply(priv);
148 if (ret)
149 return ret;
150
Patrice Chotard0ef45712022-05-06 08:22:34 +0200151 ret = reset_release_bulk(&priv->resets);
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200152 if (ret)
153 return ret;
154
Patrice Chotard0ef45712022-05-06 08:22:34 +0200155 return clk_release_bulk(&priv->clocks);
Alexey Brodkina6aff432015-12-02 12:32:02 +0300156}
157
Alexey Brodkina6aff432015-12-02 12:32:02 +0300158static const struct udevice_id ehci_usb_ids[] = {
159 { .compatible = "generic-ehci" },
160 { }
161};
162
163U_BOOT_DRIVER(ehci_generic) = {
164 .name = "ehci_generic",
165 .id = UCLASS_USB,
166 .of_match = ehci_usb_ids,
167 .probe = ehci_usb_probe,
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200168 .remove = ehci_usb_remove,
Alexey Brodkina6aff432015-12-02 12:32:02 +0300169 .ops = &ehci_usb_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700170 .priv_auto = sizeof(struct generic_ehci),
Alexey Brodkina6aff432015-12-02 12:32:02 +0300171 .flags = DM_FLAG_ALLOC_PRIV_DMA,
172};