uboot/drivers/usb/host/ohci-da8xx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2012 Sughosh Ganu <urwithsughosh@gmail.com>
   4 */
   5
   6#include <common.h>
   7#include <malloc.h>
   8#include <asm/io.h>
   9#include <clk.h>
  10#include <dm.h>
  11#include <dm/device_compat.h>
  12#include <dm/devres.h>
  13#include <dm/ofnode.h>
  14#include <generic-phy.h>
  15#include <reset.h>
  16#include "ohci.h"
  17#include <asm/arch/da8xx-usb.h>
  18
  19struct da8xx_ohci {
  20        ohci_t ohci;
  21        struct clk *clocks;     /* clock list */
  22        struct phy phy;
  23        int clock_count;        /* number of clock in clock list */
  24};
  25
  26static int usb_phy_on(void)
  27{
  28        unsigned long timeout;
  29
  30        clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
  31                        (CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN |
  32                        CFGCHIP2_OTGPWRDN | CFGCHIP2_OTGMODE |
  33                        CFGCHIP2_REFFREQ | CFGCHIP2_USB1PHYCLKMUX),
  34                        (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN |
  35                        CFGCHIP2_PHY_PLLON | CFGCHIP2_REFFREQ_24MHZ |
  36                        CFGCHIP2_USB2PHYCLKMUX | CFGCHIP2_USB1SUSPENDM));
  37
  38        /* wait until the usb phy pll locks */
  39        timeout = get_timer(0);
  40        while (get_timer(timeout) < 10) {
  41                if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD)
  42                        return 1;
  43        }
  44
  45        /* USB phy was not turned on */
  46        return 0;
  47}
  48
  49static void usb_phy_off(void)
  50{
  51        /* Power down the on-chip PHY. */
  52        clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
  53                        CFGCHIP2_PHY_PLLON | CFGCHIP2_USB1SUSPENDM,
  54                        CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN |
  55                        CFGCHIP2_RESET);
  56}
  57
  58int usb_cpu_init(void)
  59{
  60        /* enable psc for usb2.0 */
  61        lpsc_on(DAVINCI_LPSC_USB20);
  62
  63        /* enable psc for usb1.0 */
  64        lpsc_on(DAVINCI_LPSC_USB11);
  65
  66        /* start the on-chip usb phy and its pll */
  67        if (usb_phy_on())
  68                return 0;
  69
  70        return 1;
  71}
  72
  73int usb_cpu_stop(void)
  74{
  75        usb_phy_off();
  76
  77        /* turn off the usb clock and assert the module reset */
  78        lpsc_disable(DAVINCI_LPSC_USB11);
  79        lpsc_disable(DAVINCI_LPSC_USB20);
  80
  81        return 0;
  82}
  83
  84int usb_cpu_init_fail(void)
  85{
  86        return usb_cpu_stop();
  87}
  88
  89#if CONFIG_IS_ENABLED(DM_USB)
  90static int ohci_da8xx_probe(struct udevice *dev)
  91{
  92        struct ohci_regs *regs = dev_read_addr_ptr(dev);
  93        struct da8xx_ohci *priv = dev_get_priv(dev);
  94        int i, err, ret, clock_nb;
  95
  96        err = 0;
  97        priv->clock_count = 0;
  98        clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells",
  99                                               0);
 100
 101        if (clock_nb < 0)
 102                return clock_nb;
 103
 104        if (clock_nb > 0) {
 105                priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
 106                                            GFP_KERNEL);
 107                if (!priv->clocks)
 108                        return -ENOMEM;
 109
 110                for (i = 0; i < clock_nb; i++) {
 111                        err = clk_get_by_index(dev, i, &priv->clocks[i]);
 112                        if (err < 0)
 113                                break;
 114
 115                        err = clk_enable(&priv->clocks[i]);
 116                        if (err) {
 117                                dev_err(dev, "failed to enable clock %d\n", i);
 118                                clk_free(&priv->clocks[i]);
 119                                goto clk_err;
 120                        }
 121                        priv->clock_count++;
 122                }
 123        }
 124
 125        err = usb_cpu_init();
 126
 127        if (err)
 128                goto clk_err;
 129
 130        err = ohci_register(dev, regs);
 131        if (err)
 132                goto phy_err;
 133
 134        return 0;
 135
 136phy_err:
 137        ret = usb_cpu_stop();
 138        if (ret)
 139                dev_err(dev, "failed to shutdown usb phy\n");
 140
 141clk_err:
 142        ret = clk_release_all(priv->clocks, priv->clock_count);
 143        if (ret)
 144                dev_err(dev, "failed to disable all clocks\n");
 145
 146        return err;
 147}
 148
 149static int ohci_da8xx_remove(struct udevice *dev)
 150{
 151        struct da8xx_ohci *priv = dev_get_priv(dev);
 152        int ret;
 153
 154        ret = ohci_deregister(dev);
 155        if (ret)
 156                return ret;
 157
 158        ret = usb_cpu_stop();
 159        if (ret)
 160                return ret;
 161
 162        return clk_release_all(priv->clocks, priv->clock_count);
 163}
 164
 165static const struct udevice_id da8xx_ohci_ids[] = {
 166        { .compatible = "ti,da830-ohci" },
 167        { }
 168};
 169
 170U_BOOT_DRIVER(ohci_generic) = {
 171        .name   = "ohci-da8xx",
 172        .id     = UCLASS_USB,
 173        .of_match = da8xx_ohci_ids,
 174        .probe = ohci_da8xx_probe,
 175        .remove = ohci_da8xx_remove,
 176        .ops    = &ohci_usb_ops,
 177        .priv_auto      = sizeof(struct da8xx_ohci),
 178        .flags  = DM_FLAG_ALLOC_PRIV_DMA | DM_FLAG_OS_PREPARE,
 179};
 180#endif
 181