uboot/drivers/usb/host/ehci-generic.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
   4 */
   5
   6#include <common.h>
   7#include <clk.h>
   8#include <log.h>
   9#include <dm/device_compat.h>
  10#include <dm/devres.h>
  11#include <dm/ofnode.h>
  12#include <generic-phy.h>
  13#include <reset.h>
  14#include <asm/io.h>
  15#include <dm.h>
  16#include "ehci.h"
  17#include <power/regulator.h>
  18
  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;
  26        struct clk_bulk clocks;
  27        struct reset_ctl_bulk resets;
  28        struct phy phy;
  29        struct udevice *vbus_supply;
  30};
  31
  32static 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) {
  45                        dev_err(dev, "Error enabling VBUS supply (ret=%d)\n", ret);
  46                        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}
  62
  63static int ehci_usb_probe(struct udevice *dev)
  64{
  65        struct generic_ehci *priv = dev_get_priv(dev);
  66        struct ehci_hccr *hccr;
  67        struct ehci_hcor *hcor;
  68        int err, ret;
  69
  70        err = 0;
  71        ret = clk_get_bulk(dev, &priv->clocks);
  72        if (ret && ret != -ENOENT) {
  73                dev_err(dev, "Failed to get clocks (ret=%d)\n", ret);
  74                return ret;
  75        }
  76
  77        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        }
  82
  83        err = reset_get_bulk(dev, &priv->resets);
  84        if (err && err != -ENOENT) {
  85                dev_err(dev, "Failed to get resets (err=%d)\n", err);
  86                goto clk_err;
  87        }
  88
  89        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;
  93        }
  94
  95        err = ehci_enable_vbus_supply(dev);
  96        if (err)
  97                goto reset_err;
  98
  99        err = generic_setup_phy(dev, &priv->phy, 0);
 100        if (err)
 101                goto regulator_err;
 102
 103        hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
 104        hcor = (struct ehci_hcor *)((uintptr_t)hccr +
 105                                    HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
 106
 107        err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
 108        if (err)
 109                goto phy_err;
 110
 111        return 0;
 112
 113phy_err:
 114        ret = generic_shutdown_phy(&priv->phy);
 115        if (ret)
 116                dev_err(dev, "failed to shutdown usb phy (ret=%d)\n", ret);
 117
 118regulator_err:
 119        ret = ehci_disable_vbus_supply(priv);
 120        if (ret)
 121                dev_err(dev, "failed to disable VBUS supply (ret=%d)\n", ret);
 122
 123reset_err:
 124        ret = reset_release_bulk(&priv->resets);
 125        if (ret)
 126                dev_err(dev, "failed to release resets (ret=%d)\n", ret);
 127clk_err:
 128        ret = clk_release_bulk(&priv->clocks);
 129        if (ret)
 130                dev_err(dev, "failed to release clocks (ret=%d)\n", ret);
 131
 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
 144        ret = generic_shutdown_phy(&priv->phy);
 145        if (ret)
 146                return ret;
 147
 148        ret = ehci_disable_vbus_supply(priv);
 149        if (ret)
 150                return ret;
 151
 152        ret = reset_release_bulk(&priv->resets);
 153        if (ret)
 154                return ret;
 155
 156        return clk_release_bulk(&priv->clocks);
 157}
 158
 159static 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,
 169        .remove = ehci_usb_remove,
 170        .ops    = &ehci_usb_ops,
 171        .priv_auto      = sizeof(struct generic_ehci),
 172        .flags  = DM_FLAG_ALLOC_PRIV_DMA,
 173};
 174