Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.6 283 lines 8.3 kB view raw
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");