u-boot/drivers/usb/host/ehci-generic.c
Andre Przywara 9125b4b021 usb: host: ehci-generic: Fix error check
Commit 81755b8c20 ("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>
2022-07-04 08:00:36 -04:00

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,
};