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