uboot/drivers/phy/bcm6318-usbh-phy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
   4 *
   5 * Derived from linux/arch/mips/bcm63xx/usb-common.c:
   6 *      Copyright 2008 Maxime Bizon <mbizon@freebox.fr>
   7 *      Copyright 2013 Florian Fainelli <florian@openwrt.org>
   8 */
   9
  10#include <common.h>
  11#include <clk.h>
  12#include <dm.h>
  13#include <generic-phy.h>
  14#include <log.h>
  15#include <malloc.h>
  16#include <power-domain.h>
  17#include <reset.h>
  18#include <asm/io.h>
  19#include <dm/device.h>
  20#include <linux/bitops.h>
  21#include <linux/delay.h>
  22
  23/* USBH Setup register */
  24#define USBH_SETUP_REG          0x00
  25#define USBH_SETUP_IOC          BIT(4)
  26
  27/* USBH PLL Control register */
  28#define USBH_PLL_REG            0x04
  29#define USBH_PLL_SUSP_EN        BIT(27)
  30#define USBH_PLL_IDDQ_PWRDN     BIT(31)
  31
  32/* USBH Swap Control register */
  33#define USBH_SWAP_REG           0x0c
  34#define USBH_SWAP_OHCI_DATA     BIT(0)
  35#define USBH_SWAP_OHCI_ENDIAN   BIT(1)
  36#define USBH_SWAP_EHCI_DATA     BIT(3)
  37#define USBH_SWAP_EHCI_ENDIAN   BIT(4)
  38
  39/* USBH Sim Control register */
  40#define USBH_SIM_REG            0x20
  41#define USBH_SIM_LADDR          BIT(5)
  42
  43struct bcm6318_usbh_priv {
  44        void __iomem *regs;
  45};
  46
  47static int bcm6318_usbh_init(struct phy *phy)
  48{
  49        struct bcm6318_usbh_priv *priv = dev_get_priv(phy->dev);
  50
  51        /* enable pll control susp */
  52        setbits_be32(priv->regs + USBH_PLL_REG, USBH_PLL_SUSP_EN);
  53
  54        /* configure to work in native cpu endian */
  55        clrsetbits_be32(priv->regs + USBH_SWAP_REG,
  56                        USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN,
  57                        USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA);
  58
  59        /* setup config */
  60        setbits_be32(priv->regs + USBH_SETUP_REG, USBH_SETUP_IOC);
  61
  62        /* disable pll control pwrdn */
  63        clrbits_be32(priv->regs + USBH_PLL_REG, USBH_PLL_IDDQ_PWRDN);
  64
  65        /* sim control config */
  66        setbits_be32(priv->regs + USBH_SIM_REG, USBH_SIM_LADDR);
  67
  68        return 0;
  69}
  70
  71static struct phy_ops bcm6318_usbh_ops = {
  72        .init = bcm6318_usbh_init,
  73};
  74
  75static const struct udevice_id bcm6318_usbh_ids[] = {
  76        { .compatible = "brcm,bcm6318-usbh" },
  77        { /* sentinel */ }
  78};
  79
  80static int bcm6318_usbh_probe(struct udevice *dev)
  81{
  82        struct bcm6318_usbh_priv *priv = dev_get_priv(dev);
  83        struct power_domain pwr_dom;
  84        struct reset_ctl rst_ctl;
  85        struct clk clk;
  86        int ret;
  87
  88        priv->regs = dev_remap_addr(dev);
  89        if (!priv->regs)
  90                return -EINVAL;
  91
  92        /* enable usbh clock */
  93        ret = clk_get_by_name(dev, "usbh", &clk);
  94        if (ret < 0)
  95                return ret;
  96
  97        ret = clk_enable(&clk);
  98        if (ret < 0)
  99                return ret;
 100
 101        ret = clk_free(&clk);
 102        if (ret < 0)
 103                return ret;
 104
 105        /* enable power domain */
 106        ret = power_domain_get(dev, &pwr_dom);
 107        if (ret < 0)
 108                return ret;
 109
 110        ret = power_domain_on(&pwr_dom);
 111        if (ret < 0)
 112                return ret;
 113
 114        ret = power_domain_free(&pwr_dom);
 115        if (ret < 0)
 116                return ret;
 117
 118        /* perform reset */
 119        ret = reset_get_by_index(dev, 0, &rst_ctl);
 120        if (ret < 0)
 121                return ret;
 122
 123        ret = reset_deassert(&rst_ctl);
 124        if (ret < 0)
 125                return ret;
 126
 127        ret = reset_free(&rst_ctl);
 128        if (ret < 0)
 129                return ret;
 130
 131        mdelay(100);
 132
 133        return 0;
 134}
 135
 136U_BOOT_DRIVER(bcm6318_usbh) = {
 137        .name = "bcm6318-usbh",
 138        .id = UCLASS_PHY,
 139        .of_match = bcm6318_usbh_ids,
 140        .ops = &bcm6318_usbh_ops,
 141        .priv_auto      = sizeof(struct bcm6318_usbh_priv),
 142        .probe = bcm6318_usbh_probe,
 143};
 144