root/drivers/phy/amlogic/phy-meson-gxl-usb3.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. phy_meson_gxl_usb3_power_on
  2. phy_meson_gxl_usb3_power_off
  3. phy_meson_gxl_usb3_set_mode
  4. phy_meson_gxl_usb3_init
  5. phy_meson_gxl_usb3_exit
  6. phy_meson_gxl_usb3_probe

   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 
  83 struct 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 
  91 static 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 
  98 static 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 
 112 static 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 
 122 static 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 
 151 static 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 
 178 err_disable_clk_peripheral:
 179         clk_disable_unprepare(priv->clk_peripheral);
 180 err_disable_clk_phy:
 181         clk_disable_unprepare(priv->clk_phy);
 182 err:
 183         return ret;
 184 }
 185 
 186 static 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 
 196 static 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 
 205 static 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 
 266 static const struct of_device_id phy_meson_gxl_usb3_of_match[] = {
 267         { .compatible = "amlogic,meson-gxl-usb3-phy", },
 268         { },
 269 };
 270 MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb3_of_match);
 271 
 272 static 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 };
 279 module_platform_driver(phy_meson_gxl_usb3_driver);
 280 
 281 MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
 282 MODULE_DESCRIPTION("Meson GXL USB3 PHY and OTG detection driver");
 283 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */