blob: 75c73bfe4e836f846353385598f16a0b150b1dc7 [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
42 if (priv->vbus_supply) {
43 ret = regulator_set_enable(priv->vbus_supply, true);
44 if (ret) {
Patrice Chotard0ef45712022-05-06 08:22:34 +020045 dev_err(dev, "Error enabling VBUS supply (ret=%d)\n", ret);
Patrice Chotardfc424682018-09-04 11:37:25 +020046 return ret;
47 }
48 } else {
49 dev_dbg(dev, "No vbus supply\n");
50 }
51
52 return 0;
53}
54
55static int ehci_disable_vbus_supply(struct generic_ehci *priv)
56{
57 if (priv->vbus_supply)
58 return regulator_set_enable(priv->vbus_supply, false);
59 else
60 return 0;
61}
Patrice Chotardfc424682018-09-04 11:37:25 +020062
Alexey Brodkina6aff432015-12-02 12:32:02 +030063static int ehci_usb_probe(struct udevice *dev)
64{
Patrice Chotarda0809dc2017-07-18 11:57:10 +020065 struct generic_ehci *priv = dev_get_priv(dev);
Marek Vasut851fecc2016-01-23 21:04:46 +010066 struct ehci_hccr *hccr;
Alexey Brodkina6aff432015-12-02 12:32:02 +030067 struct ehci_hcor *hcor;
Patrice Chotard0ef45712022-05-06 08:22:34 +020068 int err, ret;
Masahiro Yamadafbb66bf2016-01-25 15:00:36 +090069
Patrice Chotarda0809dc2017-07-18 11:57:10 +020070 err = 0;
Patrice Chotard0ef45712022-05-06 08:22:34 +020071 ret = clk_get_bulk(dev, &priv->clocks);
Andre Przywarafbcb8f02022-06-08 00:42:22 +010072 if (ret && ret != -ENOENT) {
Patrice Chotard0ef45712022-05-06 08:22:34 +020073 dev_err(dev, "Failed to get clocks (ret=%d)\n", ret);
74 return ret;
Masahiro Yamadafbb66bf2016-01-25 15:00:36 +090075 }
Alexey Brodkina6aff432015-12-02 12:32:02 +030076
Patrice Chotard0ef45712022-05-06 08:22:34 +020077 err = clk_enable_bulk(&priv->clocks);
78 if (err) {
79 dev_err(dev, "Failed to enable clocks (err=%d)\n", err);
80 goto clk_err;
81 }
Masahiro Yamada8a5a1802016-09-21 11:29:02 +090082
Patrice Chotard0ef45712022-05-06 08:22:34 +020083 err = reset_get_bulk(dev, &priv->resets);
Andre Przywara47bb0dc2022-07-02 01:45:10 +010084 if (err && err != -ENOENT) {
Patrice Chotard0ef45712022-05-06 08:22:34 +020085 dev_err(dev, "Failed to get resets (err=%d)\n", err);
86 goto clk_err;
87 }
Patrice Chotarda0809dc2017-07-18 11:57:10 +020088
Patrice Chotard0ef45712022-05-06 08:22:34 +020089 err = reset_deassert_bulk(&priv->resets);
90 if (err) {
91 dev_err(dev, "Failed to get deassert resets (err=%d)\n", err);
92 goto reset_err;
Masahiro Yamada8a5a1802016-09-21 11:29:02 +090093 }
94
Patrice Chotardfc424682018-09-04 11:37:25 +020095 err = ehci_enable_vbus_supply(dev);
Patrice Chotard36afc032018-03-14 17:48:54 +010096 if (err)
Patrice Chotard36afc032018-03-14 17:48:54 +010097 goto reset_err;
Patrice Chotard1a62cde2017-07-18 11:57:11 +020098
Patrice Chotardfc424682018-09-04 11:37:25 +020099 err = ehci_setup_phy(dev, &priv->phy, 0);
100 if (err)
101 goto regulator_err;
102
Philipp Tomsich9f3f4232017-09-12 17:32:28 +0200103 hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
Alexey Brodkina6aff432015-12-02 12:32:02 +0300104 hcor = (struct ehci_hcor *)((uintptr_t)hccr +
105 HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
106
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200107 err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
108 if (err)
Patrice Chotard1a62cde2017-07-18 11:57:11 +0200109 goto phy_err;
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200110
111 return 0;
112
Patrice Chotard1a62cde2017-07-18 11:57:11 +0200113phy_err:
Marek Vasutd9af6cd2018-08-08 14:29:55 +0200114 ret = ehci_shutdown_phy(dev, &priv->phy);
Patrice Chotard36afc032018-03-14 17:48:54 +0100115 if (ret)
Patrice Chotard0ef45712022-05-06 08:22:34 +0200116 dev_err(dev, "failed to shutdown usb phy (ret=%d)\n", ret);
Patrice Chotard1a62cde2017-07-18 11:57:11 +0200117
Patrice Chotardfc424682018-09-04 11:37:25 +0200118regulator_err:
119 ret = ehci_disable_vbus_supply(priv);
120 if (ret)
Patrice Chotard0ef45712022-05-06 08:22:34 +0200121 dev_err(dev, "failed to disable VBUS supply (ret=%d)\n", ret);
Patrice Chotardfc424682018-09-04 11:37:25 +0200122
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200123reset_err:
Patrice Chotard0ef45712022-05-06 08:22:34 +0200124 ret = reset_release_bulk(&priv->resets);
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200125 if (ret)
Patrice Chotard0ef45712022-05-06 08:22:34 +0200126 dev_err(dev, "failed to release resets (ret=%d)\n", ret);
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200127clk_err:
Patrice Chotard0ef45712022-05-06 08:22:34 +0200128 ret = clk_release_bulk(&priv->clocks);
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200129 if (ret)
Patrice Chotard0ef45712022-05-06 08:22:34 +0200130 dev_err(dev, "failed to release clocks (ret=%d)\n", ret);
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200131
132 return err;
133}
134
135static int ehci_usb_remove(struct udevice *dev)
136{
137 struct generic_ehci *priv = dev_get_priv(dev);
138 int ret;
139
140 ret = ehci_deregister(dev);
141 if (ret)
142 return ret;
143
Marek Vasutd9af6cd2018-08-08 14:29:55 +0200144 ret = ehci_shutdown_phy(dev, &priv->phy);
Patrice Chotard36afc032018-03-14 17:48:54 +0100145 if (ret)
146 return ret;
Patrice Chotard1a62cde2017-07-18 11:57:11 +0200147
Patrice Chotardfc424682018-09-04 11:37:25 +0200148 ret = ehci_disable_vbus_supply(priv);
149 if (ret)
150 return ret;
151
Patrice Chotard0ef45712022-05-06 08:22:34 +0200152 ret = reset_release_bulk(&priv->resets);
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200153 if (ret)
154 return ret;
155
Patrice Chotard0ef45712022-05-06 08:22:34 +0200156 return clk_release_bulk(&priv->clocks);
Alexey Brodkina6aff432015-12-02 12:32:02 +0300157}
158
Alexey Brodkina6aff432015-12-02 12:32:02 +0300159static const struct udevice_id ehci_usb_ids[] = {
160 { .compatible = "generic-ehci" },
161 { }
162};
163
164U_BOOT_DRIVER(ehci_generic) = {
165 .name = "ehci_generic",
166 .id = UCLASS_USB,
167 .of_match = ehci_usb_ids,
168 .probe = ehci_usb_probe,
Patrice Chotarda0809dc2017-07-18 11:57:10 +0200169 .remove = ehci_usb_remove,
Alexey Brodkina6aff432015-12-02 12:32:02 +0300170 .ops = &ehci_usb_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700171 .priv_auto = sizeof(struct generic_ehci),
Alexey Brodkina6aff432015-12-02 12:32:02 +0300172 .flags = DM_FLAG_ALLOC_PRIV_DMA,
173};