mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-23 19:43:33 +00:00
9125b4b021
Commit81755b8c20
("usb: host: ehci-generic: Make resets and clocks optional") improved the error check to cover the reset property being optional. However this was using the wrong error variable for the check, so would now never fail. Use the correct error variable for checking the result of reset_get_bulk(), to actually report genuine errors. Fixes:81755b8c20
("usb: host: ehci-generic: Make resets and clocks optional") Signed-off-by: Andre Przywara <andre.przywara@arm.com>
173 lines
3.7 KiB
C
173 lines
3.7 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <clk.h>
|
|
#include <log.h>
|
|
#include <dm/device_compat.h>
|
|
#include <dm/devres.h>
|
|
#include <dm/ofnode.h>
|
|
#include <generic-phy.h>
|
|
#include <reset.h>
|
|
#include <asm/io.h>
|
|
#include <dm.h>
|
|
#include "ehci.h"
|
|
#include <power/regulator.h>
|
|
|
|
/*
|
|
* Even though here we don't explicitly use "struct ehci_ctrl"
|
|
* ehci_register() expects it to be the first thing that resides in
|
|
* device's private data.
|
|
*/
|
|
struct generic_ehci {
|
|
struct ehci_ctrl ctrl;
|
|
struct clk_bulk clocks;
|
|
struct reset_ctl_bulk resets;
|
|
struct phy phy;
|
|
struct udevice *vbus_supply;
|
|
};
|
|
|
|
static int ehci_enable_vbus_supply(struct udevice *dev)
|
|
{
|
|
struct generic_ehci *priv = dev_get_priv(dev);
|
|
int ret;
|
|
|
|
ret = device_get_supply_regulator(dev, "vbus-supply",
|
|
&priv->vbus_supply);
|
|
if (ret && ret != -ENOENT)
|
|
return ret;
|
|
|
|
if (priv->vbus_supply) {
|
|
ret = regulator_set_enable(priv->vbus_supply, true);
|
|
if (ret) {
|
|
dev_err(dev, "Error enabling VBUS supply (ret=%d)\n", ret);
|
|
return ret;
|
|
}
|
|
} else {
|
|
dev_dbg(dev, "No vbus supply\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ehci_disable_vbus_supply(struct generic_ehci *priv)
|
|
{
|
|
if (priv->vbus_supply)
|
|
return regulator_set_enable(priv->vbus_supply, false);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static int ehci_usb_probe(struct udevice *dev)
|
|
{
|
|
struct generic_ehci *priv = dev_get_priv(dev);
|
|
struct ehci_hccr *hccr;
|
|
struct ehci_hcor *hcor;
|
|
int err, ret;
|
|
|
|
err = 0;
|
|
ret = clk_get_bulk(dev, &priv->clocks);
|
|
if (ret && ret != -ENOENT) {
|
|
dev_err(dev, "Failed to get clocks (ret=%d)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
err = clk_enable_bulk(&priv->clocks);
|
|
if (err) {
|
|
dev_err(dev, "Failed to enable clocks (err=%d)\n", err);
|
|
goto clk_err;
|
|
}
|
|
|
|
err = reset_get_bulk(dev, &priv->resets);
|
|
if (err && err != -ENOENT) {
|
|
dev_err(dev, "Failed to get resets (err=%d)\n", err);
|
|
goto clk_err;
|
|
}
|
|
|
|
err = reset_deassert_bulk(&priv->resets);
|
|
if (err) {
|
|
dev_err(dev, "Failed to get deassert resets (err=%d)\n", err);
|
|
goto reset_err;
|
|
}
|
|
|
|
err = ehci_enable_vbus_supply(dev);
|
|
if (err)
|
|
goto reset_err;
|
|
|
|
err = ehci_setup_phy(dev, &priv->phy, 0);
|
|
if (err)
|
|
goto regulator_err;
|
|
|
|
hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
|
|
hcor = (struct ehci_hcor *)((uintptr_t)hccr +
|
|
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
|
|
|
|
err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
|
|
if (err)
|
|
goto phy_err;
|
|
|
|
return 0;
|
|
|
|
phy_err:
|
|
ret = ehci_shutdown_phy(dev, &priv->phy);
|
|
if (ret)
|
|
dev_err(dev, "failed to shutdown usb phy (ret=%d)\n", ret);
|
|
|
|
regulator_err:
|
|
ret = ehci_disable_vbus_supply(priv);
|
|
if (ret)
|
|
dev_err(dev, "failed to disable VBUS supply (ret=%d)\n", ret);
|
|
|
|
reset_err:
|
|
ret = reset_release_bulk(&priv->resets);
|
|
if (ret)
|
|
dev_err(dev, "failed to release resets (ret=%d)\n", ret);
|
|
clk_err:
|
|
ret = clk_release_bulk(&priv->clocks);
|
|
if (ret)
|
|
dev_err(dev, "failed to release clocks (ret=%d)\n", ret);
|
|
|
|
return err;
|
|
}
|
|
|
|
static int ehci_usb_remove(struct udevice *dev)
|
|
{
|
|
struct generic_ehci *priv = dev_get_priv(dev);
|
|
int ret;
|
|
|
|
ret = ehci_deregister(dev);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = ehci_shutdown_phy(dev, &priv->phy);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = ehci_disable_vbus_supply(priv);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = reset_release_bulk(&priv->resets);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return clk_release_bulk(&priv->clocks);
|
|
}
|
|
|
|
static const struct udevice_id ehci_usb_ids[] = {
|
|
{ .compatible = "generic-ehci" },
|
|
{ }
|
|
};
|
|
|
|
U_BOOT_DRIVER(ehci_generic) = {
|
|
.name = "ehci_generic",
|
|
.id = UCLASS_USB,
|
|
.of_match = ehci_usb_ids,
|
|
.probe = ehci_usb_probe,
|
|
.remove = ehci_usb_remove,
|
|
.ops = &ehci_usb_ops,
|
|
.priv_auto = sizeof(struct generic_ehci),
|
|
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
|
};
|