linux/drivers/phy/amlogic/phy-meson-gxl-usb3.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Meson GXL USB3 PHY and OTG mode detection driver
   4 *
   5 * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
   6 */
   7
   8#include <linux/bitfield.h>
   9#include <linux/bitops.h>
  10#include <linux/clk.h>
  11#include <linux/module.h>
  12#include <linux/of_device.h>
  13#include <linux/phy/phy.h>
  14#include <linux/regmap.h>
  15#include <linux/reset.h>
  16#include <linux/platform_device.h>
  17
  18#define USB_R0                                                  0x00
  19        #define USB_R0_P30_FSEL_MASK                            GENMASK(5, 0)
  20        #define USB_R0_P30_PHY_RESET                            BIT(6)
  21        #define USB_R0_P30_TEST_POWERDOWN_HSP                   BIT(7)
  22        #define USB_R0_P30_TEST_POWERDOWN_SSP                   BIT(8)
  23        #define USB_R0_P30_ACJT_LEVEL_MASK                      GENMASK(13, 9)
  24        #define USB_R0_P30_TX_BOOST_LEVEL_MASK                  GENMASK(16, 14)
  25        #define USB_R0_P30_LANE0_TX2RX_LOOPBACK                 BIT(17)
  26        #define USB_R0_P30_LANE0_EXT_PCLK_REQ                   BIT(18)
  27        #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK             GENMASK(28, 19)
  28        #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK               GENMASK(30, 29)
  29        #define USB_R0_U2D_ACT                                  BIT(31)
  30
  31#define USB_R1                                                  0x04
  32        #define USB_R1_U3H_BIGENDIAN_GS                         BIT(0)
  33        #define USB_R1_U3H_PME_ENABLE                           BIT(1)
  34        #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK            GENMASK(6, 2)
  35        #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK            GENMASK(11, 7)
  36        #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK            GENMASK(15, 12)
  37        #define USB_R1_U3H_HOST_U3_PORT_DISABLE                 BIT(16)
  38        #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT      BIT(17)
  39        #define USB_R1_U3H_HOST_MSI_ENABLE                      BIT(18)
  40        #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK                 GENMASK(24, 19)
  41        #define USB_R1_P30_PCS_TX_SWING_FULL_MASK               GENMASK(31, 25)
  42
  43#define USB_R2                                                  0x08
  44        #define USB_R2_P30_CR_DATA_IN_MASK                      GENMASK(15, 0)
  45        #define USB_R2_P30_CR_READ                              BIT(16)
  46        #define USB_R2_P30_CR_WRITE                             BIT(17)
  47        #define USB_R2_P30_CR_CAP_ADDR                          BIT(18)
  48        #define USB_R2_P30_CR_CAP_DATA                          BIT(19)
  49        #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK             GENMASK(25, 20)
  50        #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK               GENMASK(31, 26)
  51
  52#define USB_R3                                                  0x0c
  53        #define USB_R3_P30_SSC_ENABLE                           BIT(0)
  54        #define USB_R3_P30_SSC_RANGE_MASK                       GENMASK(3, 1)
  55        #define USB_R3_P30_SSC_REF_CLK_SEL_MASK                 GENMASK(12, 4)
  56        #define USB_R3_P30_REF_SSP_EN                           BIT(13)
  57        #define USB_R3_P30_LOS_BIAS_MASK                        GENMASK(18, 16)
  58        #define USB_R3_P30_LOS_LEVEL_MASK                       GENMASK(23, 19)
  59        #define USB_R3_P30_MPLL_MULTIPLIER_MASK                 GENMASK(30, 24)
  60
  61#define USB_R4                                                  0x10
  62        #define USB_R4_P21_PORT_RESET_0                         BIT(0)
  63        #define USB_R4_P21_SLEEP_M0                             BIT(1)
  64        #define USB_R4_MEM_PD_MASK                              GENMASK(3, 2)
  65        #define USB_R4_P21_ONLY                                 BIT(4)
  66
  67#define USB_R5                                                  0x14
  68        #define USB_R5_ID_DIG_SYNC                              BIT(0)
  69        #define USB_R5_ID_DIG_REG                               BIT(1)
  70        #define USB_R5_ID_DIG_CFG_MASK                          GENMASK(3, 2)
  71        #define USB_R5_ID_DIG_EN_0                              BIT(4)
  72        #define USB_R5_ID_DIG_EN_1                              BIT(5)
  73        #define USB_R5_ID_DIG_CURR                              BIT(6)
  74        #define USB_R5_ID_DIG_IRQ                               BIT(7)
  75        #define USB_R5_ID_DIG_TH_MASK                           GENMASK(15, 8)
  76        #define USB_R5_ID_DIG_CNT_MASK                          GENMASK(23, 16)
  77
  78/* read-only register */
  79#define USB_R6                                                  0x18
  80        #define USB_R6_P30_CR_DATA_OUT_MASK                     GENMASK(15, 0)
  81        #define USB_R6_P30_CR_ACK                               BIT(16)
  82
  83struct phy_meson_gxl_usb3_priv {
  84        struct regmap           *regmap;
  85        enum phy_mode           mode;
  86        struct clk              *clk_phy;
  87        struct clk              *clk_peripheral;
  88        struct reset_control    *reset;
  89};
  90
  91static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
  92        .reg_bits = 8,
  93        .val_bits = 32,
  94        .reg_stride = 4,
  95        .max_register = USB_R6,
  96};
  97
  98static int phy_meson_gxl_usb3_power_on(struct phy *phy)
  99{
 100        struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
 101
 102        regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0,
 103                           USB_R5_ID_DIG_EN_0);
 104        regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1,
 105                           USB_R5_ID_DIG_EN_1);
 106        regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_TH_MASK,
 107                           FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
 108
 109        return 0;
 110}
 111
 112static int phy_meson_gxl_usb3_power_off(struct phy *phy)
 113{
 114        struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
 115
 116        regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0, 0);
 117        regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1, 0);
 118
 119        return 0;
 120}
 121
 122static int phy_meson_gxl_usb3_set_mode(struct phy *phy,
 123                                       enum phy_mode mode, int submode)
 124{
 125        struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
 126
 127        switch (mode) {
 128        case PHY_MODE_USB_HOST:
 129                regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT, 0);
 130                regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
 131                                   0);
 132                break;
 133
 134        case PHY_MODE_USB_DEVICE:
 135                regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT,
 136                                   USB_R0_U2D_ACT);
 137                regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
 138                                   USB_R4_P21_SLEEP_M0);
 139                break;
 140
 141        default:
 142                dev_err(&phy->dev, "unsupported PHY mode %d\n", mode);
 143                return -EINVAL;
 144        }
 145
 146        priv->mode = mode;
 147
 148        return 0;
 149}
 150
 151static int phy_meson_gxl_usb3_init(struct phy *phy)
 152{
 153        struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
 154        int ret;
 155
 156        ret = reset_control_reset(priv->reset);
 157        if (ret)
 158                goto err;
 159
 160        ret = clk_prepare_enable(priv->clk_phy);
 161        if (ret)
 162                goto err;
 163
 164        ret = clk_prepare_enable(priv->clk_peripheral);
 165        if (ret)
 166                goto err_disable_clk_phy;
 167
 168        ret = phy_meson_gxl_usb3_set_mode(phy, priv->mode, 0);
 169        if (ret)
 170                goto err_disable_clk_peripheral;
 171
 172        regmap_update_bits(priv->regmap, USB_R1,
 173                           USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
 174                           FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
 175
 176        return 0;
 177
 178err_disable_clk_peripheral:
 179        clk_disable_unprepare(priv->clk_peripheral);
 180err_disable_clk_phy:
 181        clk_disable_unprepare(priv->clk_phy);
 182err:
 183        return ret;
 184}
 185
 186static int phy_meson_gxl_usb3_exit(struct phy *phy)
 187{
 188        struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
 189
 190        clk_disable_unprepare(priv->clk_peripheral);
 191        clk_disable_unprepare(priv->clk_phy);
 192
 193        return 0;
 194}
 195
 196static const struct phy_ops phy_meson_gxl_usb3_ops = {
 197        .power_on       = phy_meson_gxl_usb3_power_on,
 198        .power_off      = phy_meson_gxl_usb3_power_off,
 199        .set_mode       = phy_meson_gxl_usb3_set_mode,
 200        .init           = phy_meson_gxl_usb3_init,
 201        .exit           = phy_meson_gxl_usb3_exit,
 202        .owner          = THIS_MODULE,
 203};
 204
 205static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
 206{
 207        struct device *dev = &pdev->dev;
 208        struct device_node *np = dev->of_node;
 209        struct phy_meson_gxl_usb3_priv *priv;
 210        struct resource *res;
 211        struct phy *phy;
 212        struct phy_provider *phy_provider;
 213        void __iomem *base;
 214        int ret;
 215
 216        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 217        if (!priv)
 218                return -ENOMEM;
 219
 220        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 221        base = devm_ioremap_resource(dev, res);
 222        if (IS_ERR(base))
 223                return PTR_ERR(base);
 224
 225        priv->regmap = devm_regmap_init_mmio(dev, base,
 226                                             &phy_meson_gxl_usb3_regmap_conf);
 227        if (IS_ERR(priv->regmap))
 228                return PTR_ERR(priv->regmap);
 229
 230        priv->clk_phy = devm_clk_get(dev, "phy");
 231        if (IS_ERR(priv->clk_phy))
 232                return PTR_ERR(priv->clk_phy);
 233
 234        priv->clk_peripheral = devm_clk_get(dev, "peripheral");
 235        if (IS_ERR(priv->clk_peripheral))
 236                return PTR_ERR(priv->clk_peripheral);
 237
 238        priv->reset = devm_reset_control_array_get_shared(dev);
 239        if (IS_ERR(priv->reset))
 240                return PTR_ERR(priv->reset);
 241
 242        /*
 243         * default to host mode as hardware defaults and/or boot-loader
 244         * behavior can result in this PHY starting up in device mode. this
 245         * default and the initialization in phy_meson_gxl_usb3_init ensure
 246         * that we reproducibly start in a known mode on all devices.
 247         */
 248        priv->mode = PHY_MODE_USB_HOST;
 249
 250        phy = devm_phy_create(dev, np, &phy_meson_gxl_usb3_ops);
 251        if (IS_ERR(phy)) {
 252                ret = PTR_ERR(phy);
 253                if (ret != -EPROBE_DEFER)
 254                        dev_err(dev, "failed to create PHY\n");
 255
 256                return ret;
 257        }
 258
 259        phy_set_drvdata(phy, priv);
 260
 261        phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 262
 263        return PTR_ERR_OR_ZERO(phy_provider);
 264}
 265
 266static const struct of_device_id phy_meson_gxl_usb3_of_match[] = {
 267        { .compatible = "amlogic,meson-gxl-usb3-phy", },
 268        { },
 269};
 270MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb3_of_match);
 271
 272static struct platform_driver phy_meson_gxl_usb3_driver = {
 273        .probe  = phy_meson_gxl_usb3_probe,
 274        .driver = {
 275                .name           = "phy-meson-gxl-usb3",
 276                .of_match_table = phy_meson_gxl_usb3_of_match,
 277        },
 278};
 279module_platform_driver(phy_meson_gxl_usb3_driver);
 280
 281MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
 282MODULE_DESCRIPTION("Meson GXL USB3 PHY and OTG detection driver");
 283MODULE_LICENSE("GPL v2");
 284