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 *clocks;
  27        struct reset_ctl *resets;
  28        struct phy phy;
  29#ifdef CONFIG_DM_REGULATOR
  30        struct udevice *vbus_supply;
  31#endif
  32        int clock_count;
  33        int reset_count;
  34};
  35
  36#ifdef CONFIG_DM_REGULATOR
  37static int ehci_enable_vbus_supply(struct udevice *dev)
  38{
  39        struct generic_ehci *priv = dev_get_priv(dev);
  40        int ret;
  41
  42        ret = device_get_supply_regulator(dev, "vbus-supply",
  43                                          &priv->vbus_supply);
  44        if (ret && ret != -ENOENT)
  45                return ret;
  46
  47        if (priv->vbus_supply) {
  48                ret = regulator_set_enable(priv->vbus_supply, true);
  49                if (ret) {
  50                        dev_err(dev, "Error enabling VBUS supply\n");
  51                        return ret;
  52                }
  53        } else {
  54                dev_dbg(dev, "No vbus supply\n");
  55        }
  56
  57        return 0;
  58}
  59
  60static int ehci_disable_vbus_supply(struct generic_ehci *priv)
  61{
  62        if (priv->vbus_supply)
  63                return regulator_set_enable(priv->vbus_supply, false);
  64        else
  65                return 0;
  66}
  67#else
  68static int ehci_enable_vbus_supply(struct udevice *dev)
  69{
  70        return 0;
  71}
  72
  73static int ehci_disable_vbus_supply(struct generic_ehci *priv)
  74{
  75        return 0;
  76}
  77#endif
  78
  79static int ehci_usb_probe(struct udevice *dev)
  80{
  81        struct generic_ehci *priv = dev_get_priv(dev);
  82        struct ehci_hccr *hccr;
  83        struct ehci_hcor *hcor;
  84        int i, err, ret, clock_nb, reset_nb;
  85
  86        err = 0;
  87        priv->clock_count = 0;
  88        clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
  89                                                  "#clock-cells");
  90        if (clock_nb > 0) {
  91                priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
  92                                            GFP_KERNEL);
  93                if (!priv->clocks)
  94                        return -ENOMEM;
  95
  96                for (i = 0; i < clock_nb; i++) {
  97                        err = clk_get_by_index(dev, i, &priv->clocks[i]);
  98
  99                        if (err < 0)
 100                                break;
 101                        err = clk_enable(&priv->clocks[i]);
 102                        if (err && err != -ENOSYS) {
 103                                dev_err(dev, "failed to enable clock %d\n", i);
 104                                clk_free(&priv->clocks[i]);
 105                                goto clk_err;
 106                        }
 107                        priv->clock_count++;
 108                }
 109        } else {
 110                if (clock_nb != -ENOENT) {
 111                        dev_err(dev, "failed to get clock phandle(%d)\n",
 112                                clock_nb);
 113                        return clock_nb;
 114                }
 115        }
 116
 117        priv->reset_count = 0;
 118        reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
 119                                                  "#reset-cells");
 120        if (reset_nb > 0) {
 121                priv->resets = devm_kcalloc(dev, reset_nb,
 122                                            sizeof(struct reset_ctl),
 123                                            GFP_KERNEL);
 124                if (!priv->resets)
 125                        return -ENOMEM;
 126
 127                for (i = 0; i < reset_nb; i++) {
 128                        err = reset_get_by_index(dev, i, &priv->resets[i]);
 129                        if (err < 0)
 130                                break;
 131
 132                        if (reset_deassert(&priv->resets[i])) {
 133                                dev_err(dev, "failed to deassert reset %d\n",
 134                                        i);
 135                                reset_free(&priv->resets[i]);
 136                                goto reset_err;
 137                        }
 138                        priv->reset_count++;
 139                }
 140        } else {
 141                if (reset_nb != -ENOENT) {
 142                        dev_err(dev, "failed to get reset phandle(%d)\n",
 143                                reset_nb);
 144                        goto clk_err;
 145                }
 146        }
 147
 148        err = ehci_enable_vbus_supply(dev);
 149        if (err)
 150                goto reset_err;
 151
 152        err = ehci_setup_phy(dev, &priv->phy, 0);
 153        if (err)
 154                goto regulator_err;
 155
 156        hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
 157        hcor = (struct ehci_hcor *)((uintptr_t)hccr +
 158                                    HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
 159
 160        err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
 161        if (err)
 162                goto phy_err;
 163
 164        return 0;
 165
 166phy_err:
 167        ret = ehci_shutdown_phy(dev, &priv->phy);
 168        if (ret)
 169                dev_err(dev, "failed to shutdown usb phy\n");
 170
 171regulator_err:
 172        ret = ehci_disable_vbus_supply(priv);
 173        if (ret)
 174                dev_err(dev, "failed to disable VBUS supply\n");
 175
 176reset_err:
 177        ret = reset_release_all(priv->resets, priv->reset_count);
 178        if (ret)
 179                dev_err(dev, "failed to assert all resets\n");
 180clk_err:
 181        ret = clk_release_all(priv->clocks, priv->clock_count);
 182        if (ret)
 183                dev_err(dev, "failed to disable all clocks\n");
 184
 185        return err;
 186}
 187
 188static int ehci_usb_remove(struct udevice *dev)
 189{
 190        struct generic_ehci *priv = dev_get_priv(dev);
 191        int ret;
 192
 193        ret = ehci_deregister(dev);
 194        if (ret)
 195                return ret;
 196
 197        ret = ehci_shutdown_phy(dev, &priv->phy);
 198        if (ret)
 199                return ret;
 200
 201        ret = ehci_disable_vbus_supply(priv);
 202        if (ret)
 203                return ret;
 204
 205        ret =  reset_release_all(priv->resets, priv->reset_count);
 206        if (ret)
 207                return ret;
 208
 209        return clk_release_all(priv->clocks, priv->clock_count);
 210}
 211
 212static const struct udevice_id ehci_usb_ids[] = {
 213        { .compatible = "generic-ehci" },
 214        { }
 215};
 216
 217U_BOOT_DRIVER(ehci_generic) = {
 218        .name   = "ehci_generic",
 219        .id     = UCLASS_USB,
 220        .of_match = ehci_usb_ids,
 221        .probe = ehci_usb_probe,
 222        .remove = ehci_usb_remove,
 223        .ops    = &ehci_usb_ops,
 224        .priv_auto_alloc_size = sizeof(struct generic_ehci),
 225        .flags  = DM_FLAG_ALLOC_PRIV_DMA,
 226};
 227