uboot/drivers/phy/meson-g12a-usb2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Meson G12A USB2 PHY driver
   4 *
   5 * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
   6 * Copyright (C) 2019 BayLibre, SAS
   7 * Author: Neil Armstrong <narmstron@baylibre.com>
   8 */
   9
  10#include <common.h>
  11#include <log.h>
  12#include <malloc.h>
  13#include <asm/io.h>
  14#include <bitfield.h>
  15#include <dm.h>
  16#include <errno.h>
  17#include <generic-phy.h>
  18#include <regmap.h>
  19#include <linux/delay.h>
  20#include <power/regulator.h>
  21#include <reset.h>
  22#include <clk.h>
  23
  24#include <linux/bitops.h>
  25#include <linux/compat.h>
  26
  27#define PHY_CTRL_R0                                             0x0
  28#define PHY_CTRL_R1                                             0x4
  29#define PHY_CTRL_R2                                             0x8
  30#define PHY_CTRL_R3                                             0xc
  31#define PHY_CTRL_R4                                             0x10
  32#define PHY_CTRL_R5                                             0x14
  33#define PHY_CTRL_R6                                             0x18
  34#define PHY_CTRL_R7                                             0x1c
  35#define PHY_CTRL_R8                                             0x20
  36#define PHY_CTRL_R9                                             0x24
  37#define PHY_CTRL_R10                                            0x28
  38#define PHY_CTRL_R11                                            0x2c
  39#define PHY_CTRL_R12                                            0x30
  40#define PHY_CTRL_R13                                            0x34
  41#define PHY_CTRL_R14                                            0x38
  42#define PHY_CTRL_R15                                            0x3c
  43#define PHY_CTRL_R16                                            0x40
  44#define PHY_CTRL_R17                                            0x44
  45#define PHY_CTRL_R18                                            0x48
  46#define PHY_CTRL_R19                                            0x4c
  47#define PHY_CTRL_R20                                            0x50
  48#define PHY_CTRL_R21                                            0x54
  49#define PHY_CTRL_R22                                            0x58
  50#define PHY_CTRL_R23                                            0x5c
  51
  52#define RESET_COMPLETE_TIME                                     1000
  53#define PLL_RESET_COMPLETE_TIME                                 100
  54
  55struct phy_meson_g12a_usb2_priv {
  56        struct regmap           *regmap;
  57#if CONFIG_IS_ENABLED(DM_REGULATOR)
  58        struct udevice          *phy_supply;
  59#endif
  60#if CONFIG_IS_ENABLED(CLK)
  61        struct clk              clk;
  62#endif
  63        struct reset_ctl        reset;
  64};
  65
  66
  67static int phy_meson_g12a_usb2_power_on(struct phy *phy)
  68{
  69#if CONFIG_IS_ENABLED(DM_REGULATOR)
  70        struct udevice *dev = phy->dev;
  71        struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
  72
  73        if (priv->phy_supply) {
  74                int ret = regulator_set_enable(priv->phy_supply, true);
  75                if (ret)
  76                        return ret;
  77        }
  78#endif
  79
  80        return 0;
  81}
  82
  83static int phy_meson_g12a_usb2_power_off(struct phy *phy)
  84{
  85#if CONFIG_IS_ENABLED(DM_REGULATOR)
  86        struct udevice *dev = phy->dev;
  87        struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
  88
  89        if (priv->phy_supply) {
  90                int ret = regulator_set_enable(priv->phy_supply, false);
  91                if (ret) {
  92                        pr_err("Error disabling PHY supply\n");
  93                        return ret;
  94                }
  95        }
  96#endif
  97
  98        return 0;
  99}
 100
 101static int phy_meson_g12a_usb2_init(struct phy *phy)
 102{
 103        struct udevice *dev = phy->dev;
 104        struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
 105        int ret;
 106
 107        ret = reset_assert(&priv->reset);
 108        udelay(1);
 109        ret |= reset_deassert(&priv->reset);
 110        if (ret)
 111                return ret;
 112
 113        udelay(RESET_COMPLETE_TIME);
 114
 115        /* usb2_otg_aca_en == 0 */
 116        regmap_update_bits(priv->regmap, PHY_CTRL_R21, BIT(2), 0);
 117
 118        /* PLL Setup : 24MHz * 20 / 1 = 480MHz */
 119        regmap_write(priv->regmap, PHY_CTRL_R16, 0x39400414);
 120        regmap_write(priv->regmap, PHY_CTRL_R17, 0x927e0000);
 121        regmap_write(priv->regmap, PHY_CTRL_R18, 0xac5f49e5);
 122
 123        udelay(PLL_RESET_COMPLETE_TIME);
 124
 125        /* UnReset PLL */
 126        regmap_write(priv->regmap, PHY_CTRL_R16, 0x19400414);
 127
 128        /* PHY Tuning */
 129        regmap_write(priv->regmap, PHY_CTRL_R20, 0xfe18);
 130        regmap_write(priv->regmap, PHY_CTRL_R4, 0x8000fff);
 131
 132        /* Tuning Disconnect Threshold */
 133        regmap_write(priv->regmap, PHY_CTRL_R3, 0x34);
 134
 135        /* Analog Settings */
 136        regmap_write(priv->regmap, PHY_CTRL_R14, 0);
 137        regmap_write(priv->regmap, PHY_CTRL_R13, 0x78000);
 138
 139        return 0;
 140}
 141
 142static int phy_meson_g12a_usb2_exit(struct phy *phy)
 143{
 144        struct udevice *dev = phy->dev;
 145        struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
 146        int ret;
 147
 148        ret = reset_assert(&priv->reset);
 149        if (ret)
 150                return ret;
 151
 152        return 0;
 153}
 154
 155struct phy_ops meson_g12a_usb2_phy_ops = {
 156        .init = phy_meson_g12a_usb2_init,
 157        .exit = phy_meson_g12a_usb2_exit,
 158        .power_on = phy_meson_g12a_usb2_power_on,
 159        .power_off = phy_meson_g12a_usb2_power_off,
 160};
 161
 162int meson_g12a_usb2_phy_probe(struct udevice *dev)
 163{
 164        struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
 165        int ret;
 166
 167        ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
 168        if (ret)
 169                return ret;
 170
 171        ret = reset_get_by_index(dev, 0, &priv->reset);
 172        if (ret == -ENOTSUPP)
 173                return 0;
 174        else if (ret)
 175                return ret;
 176
 177        ret = reset_deassert(&priv->reset);
 178        if (ret) {
 179                reset_release_all(&priv->reset, 1);
 180                return ret;
 181        }
 182
 183#if CONFIG_IS_ENABLED(CLK)
 184        ret = clk_get_by_index(dev, 0, &priv->clk);
 185        if (ret < 0)
 186                return ret;
 187
 188        ret = clk_enable(&priv->clk);
 189        if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
 190                pr_err("failed to enable PHY clock\n");
 191                clk_free(&priv->clk);
 192                return ret;
 193        }
 194#endif
 195
 196#if CONFIG_IS_ENABLED(DM_REGULATOR)
 197        ret = device_get_supply_regulator(dev, "phy-supply", &priv->phy_supply);
 198        if (ret && ret != -ENOENT) {
 199                pr_err("Failed to get PHY regulator\n");
 200                return ret;
 201        }
 202#endif
 203
 204        return 0;
 205}
 206
 207static const struct udevice_id meson_g12a_usb2_phy_ids[] = {
 208        { .compatible = "amlogic,g12a-usb2-phy" },
 209        { }
 210};
 211
 212U_BOOT_DRIVER(meson_g12a_usb2_phy) = {
 213        .name = "meson_g12a_usb2_phy",
 214        .id = UCLASS_PHY,
 215        .of_match = meson_g12a_usb2_phy_ids,
 216        .probe = meson_g12a_usb2_phy_probe,
 217        .ops = &meson_g12a_usb2_phy_ops,
 218        .priv_auto_alloc_size = sizeof(struct phy_meson_g12a_usb2_priv),
 219};
 220