uboot/drivers/usb/host/ohci-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 <dm.h>
   9#include <log.h>
  10#include <dm/device_compat.h>
  11#include <dm/devres.h>
  12#include <dm/ofnode.h>
  13#include <generic-phy.h>
  14#include <reset.h>
  15#include "ohci.h"
  16
  17#if !defined(CONFIG_USB_OHCI_NEW)
  18# error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW"
  19#endif
  20
  21struct generic_ohci {
  22        ohci_t ohci;
  23        struct clk *clocks;     /* clock list */
  24        struct reset_ctl *resets; /* reset list */
  25        struct phy phy;
  26        int clock_count;        /* number of clock in clock list */
  27        int reset_count;        /* number of reset in reset list */
  28};
  29
  30static int ohci_setup_phy(struct udevice *dev, int index)
  31{
  32        struct generic_ohci *priv = dev_get_priv(dev);
  33        int ret;
  34
  35        ret = generic_phy_get_by_index(dev, index, &priv->phy);
  36        if (ret) {
  37                if (ret != -ENOENT) {
  38                        dev_err(dev, "failed to get usb phy\n");
  39                        return ret;
  40                }
  41        } else {
  42                ret = generic_phy_init(&priv->phy);
  43                if (ret) {
  44                        dev_dbg(dev, "failed to init usb phy\n");
  45                        return ret;
  46                }
  47
  48                ret = generic_phy_power_on(&priv->phy);
  49                if (ret) {
  50                        dev_dbg(dev, "failed to power on usb phy\n");
  51                        return generic_phy_exit(&priv->phy);
  52                }
  53        }
  54
  55        return 0;
  56}
  57
  58static int ohci_shutdown_phy(struct udevice *dev)
  59{
  60        struct generic_ohci *priv = dev_get_priv(dev);
  61        int ret = 0;
  62
  63        if (generic_phy_valid(&priv->phy)) {
  64                ret = generic_phy_power_off(&priv->phy);
  65                if (ret) {
  66                        dev_dbg(dev, "failed to power off usb phy\n");
  67                        return ret;
  68                }
  69
  70                ret = generic_phy_exit(&priv->phy);
  71                if (ret) {
  72                        dev_dbg(dev, "failed to power off usb phy\n");
  73                        return ret;
  74                }
  75        }
  76
  77        return 0;
  78}
  79
  80static int ohci_usb_probe(struct udevice *dev)
  81{
  82        struct ohci_regs *regs = dev_read_addr_ptr(dev);
  83        struct generic_ohci *priv = dev_get_priv(dev);
  84        int i, err, ret, clock_nb, reset_nb;
  85
  86        err = 0;
  87        priv->clock_count = 0;
  88        clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells",
  89                                               0);
  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                        if (err < 0)
  99                                break;
 100
 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 if (clock_nb != -ENOENT) {
 110                dev_err(dev, "failed to get clock phandle(%d)\n", clock_nb);
 111                return clock_nb;
 112        }
 113
 114        priv->reset_count = 0;
 115        reset_nb = dev_count_phandle_with_args(dev, "resets", "#reset-cells",
 116                                               0);
 117        if (reset_nb > 0) {
 118                priv->resets = devm_kcalloc(dev, reset_nb,
 119                                            sizeof(struct reset_ctl),
 120                                            GFP_KERNEL);
 121                if (!priv->resets)
 122                        return -ENOMEM;
 123
 124                for (i = 0; i < reset_nb; i++) {
 125                        err = reset_get_by_index(dev, i, &priv->resets[i]);
 126                        if (err < 0)
 127                                break;
 128
 129                        err = reset_deassert(&priv->resets[i]);
 130                        if (err) {
 131                                dev_err(dev, "failed to deassert reset %d\n", i);
 132                                reset_free(&priv->resets[i]);
 133                                goto reset_err;
 134                        }
 135                        priv->reset_count++;
 136                }
 137        } else if (reset_nb != -ENOENT) {
 138                dev_err(dev, "failed to get reset phandle(%d)\n", reset_nb);
 139                goto clk_err;
 140        }
 141
 142        err = ohci_setup_phy(dev, 0);
 143        if (err)
 144                goto reset_err;
 145
 146        err = ohci_register(dev, regs);
 147        if (err)
 148                goto phy_err;
 149
 150        return 0;
 151
 152phy_err:
 153        ret = ohci_shutdown_phy(dev);
 154        if (ret)
 155                dev_err(dev, "failed to shutdown usb phy\n");
 156
 157reset_err:
 158        ret = reset_release_all(priv->resets, priv->reset_count);
 159        if (ret)
 160                dev_err(dev, "failed to assert all resets\n");
 161clk_err:
 162        ret = clk_release_all(priv->clocks, priv->clock_count);
 163        if (ret)
 164                dev_err(dev, "failed to disable all clocks\n");
 165
 166        return err;
 167}
 168
 169static int ohci_usb_remove(struct udevice *dev)
 170{
 171        struct generic_ohci *priv = dev_get_priv(dev);
 172        int ret;
 173
 174        ret = ohci_deregister(dev);
 175        if (ret)
 176                return ret;
 177
 178        ret = ohci_shutdown_phy(dev);
 179        if (ret)
 180                return ret;
 181
 182        ret = reset_release_all(priv->resets, priv->reset_count);
 183        if (ret)
 184                return ret;
 185
 186        return clk_release_all(priv->clocks, priv->clock_count);
 187}
 188
 189static const struct udevice_id ohci_usb_ids[] = {
 190        { .compatible = "generic-ohci" },
 191        { }
 192};
 193
 194U_BOOT_DRIVER(ohci_generic) = {
 195        .name   = "ohci_generic",
 196        .id     = UCLASS_USB,
 197        .of_match = ohci_usb_ids,
 198        .probe = ohci_usb_probe,
 199        .remove = ohci_usb_remove,
 200        .ops    = &ohci_usb_ops,
 201        .priv_auto      = sizeof(struct generic_ohci),
 202        .flags  = DM_FLAG_ALLOC_PRIV_DMA,
 203};
 204