1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2015 Linaro Ltd. 4 * Copyright (c) 2015 HiSilicon Limited. 5 */ 6 7 #include <linux/mfd/syscon.h> 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <linux/phy/phy.h> 11 #include <linux/regmap.h> 12 13 #define SC_PERIPH_CTRL4 0x00c 14 15 #define CTRL4_PICO_SIDDQ BIT(6) 16 #define CTRL4_PICO_OGDISABLE BIT(8) 17 #define CTRL4_PICO_VBUSVLDEXT BIT(10) 18 #define CTRL4_PICO_VBUSVLDEXTSEL BIT(11) 19 #define CTRL4_OTG_PHY_SEL BIT(21) 20 21 #define SC_PERIPH_CTRL5 0x010 22 23 #define CTRL5_USBOTG_RES_SEL BIT(3) 24 #define CTRL5_PICOPHY_ACAENB BIT(4) 25 #define CTRL5_PICOPHY_BC_MODE BIT(5) 26 #define CTRL5_PICOPHY_CHRGSEL BIT(6) 27 #define CTRL5_PICOPHY_VDATSRCEND BIT(7) 28 #define CTRL5_PICOPHY_VDATDETENB BIT(8) 29 #define CTRL5_PICOPHY_DCDENB BIT(9) 30 #define CTRL5_PICOPHY_IDDIG BIT(10) 31 32 #define SC_PERIPH_CTRL8 0x018 33 #define SC_PERIPH_RSTEN0 0x300 34 #define SC_PERIPH_RSTDIS0 0x304 35 36 #define RST0_USBOTG_BUS BIT(4) 37 #define RST0_POR_PICOPHY BIT(5) 38 #define RST0_USBOTG BIT(6) 39 #define RST0_USBOTG_32K BIT(7) 40 41 #define EYE_PATTERN_PARA 0x7053348c 42 43 struct hi6220_priv { 44 struct regmap *reg; 45 struct device *dev; 46 }; 47 48 static void hi6220_phy_init(struct hi6220_priv *priv) 49 { 50 struct regmap *reg = priv->reg; 51 u32 val, mask; 52 53 val = RST0_USBOTG_BUS | RST0_POR_PICOPHY | 54 RST0_USBOTG | RST0_USBOTG_32K; 55 mask = val; 56 regmap_update_bits(reg, SC_PERIPH_RSTEN0, mask, val); 57 regmap_update_bits(reg, SC_PERIPH_RSTDIS0, mask, val); 58 } 59 60 static int hi6220_phy_setup(struct hi6220_priv *priv, bool on) 61 { 62 struct regmap *reg = priv->reg; 63 u32 val, mask; 64 int ret; 65 66 if (on) { 67 val = CTRL5_USBOTG_RES_SEL | CTRL5_PICOPHY_ACAENB; 68 mask = val | CTRL5_PICOPHY_BC_MODE; 69 ret = regmap_update_bits(reg, SC_PERIPH_CTRL5, mask, val); 70 if (ret) 71 goto out; 72 73 val = CTRL4_PICO_VBUSVLDEXT | CTRL4_PICO_VBUSVLDEXTSEL | 74 CTRL4_OTG_PHY_SEL; 75 mask = val | CTRL4_PICO_SIDDQ | CTRL4_PICO_OGDISABLE; 76 ret = regmap_update_bits(reg, SC_PERIPH_CTRL4, mask, val); 77 if (ret) 78 goto out; 79 80 ret = regmap_write(reg, SC_PERIPH_CTRL8, EYE_PATTERN_PARA); 81 if (ret) 82 goto out; 83 } else { 84 val = CTRL4_PICO_SIDDQ; 85 mask = val; 86 ret = regmap_update_bits(reg, SC_PERIPH_CTRL4, mask, val); 87 if (ret) 88 goto out; 89 } 90 91 return 0; 92 out: 93 dev_err(priv->dev, "failed to setup phy ret: %d\n", ret); 94 return ret; 95 } 96 97 static int hi6220_phy_start(struct phy *phy) 98 { 99 struct hi6220_priv *priv = phy_get_drvdata(phy); 100 101 return hi6220_phy_setup(priv, true); 102 } 103 104 static int hi6220_phy_exit(struct phy *phy) 105 { 106 struct hi6220_priv *priv = phy_get_drvdata(phy); 107 108 return hi6220_phy_setup(priv, false); 109 } 110 111 static const struct phy_ops hi6220_phy_ops = { 112 .init = hi6220_phy_start, 113 .exit = hi6220_phy_exit, 114 .owner = THIS_MODULE, 115 }; 116 117 static int hi6220_phy_probe(struct platform_device *pdev) 118 { 119 struct phy_provider *phy_provider; 120 struct device *dev = &pdev->dev; 121 struct phy *phy; 122 struct hi6220_priv *priv; 123 124 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 125 if (!priv) 126 return -ENOMEM; 127 128 priv->dev = dev; 129 priv->reg = syscon_regmap_lookup_by_phandle(dev->of_node, 130 "hisilicon,peripheral-syscon"); 131 if (IS_ERR(priv->reg)) { 132 dev_err(dev, "no hisilicon,peripheral-syscon\n"); 133 return PTR_ERR(priv->reg); 134 } 135 136 hi6220_phy_init(priv); 137 138 phy = devm_phy_create(dev, NULL, &hi6220_phy_ops); 139 if (IS_ERR(phy)) 140 return PTR_ERR(phy); 141 142 phy_set_drvdata(phy, priv); 143 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 144 return PTR_ERR_OR_ZERO(phy_provider); 145 } 146 147 static const struct of_device_id hi6220_phy_of_match[] = { 148 {.compatible = "hisilicon,hi6220-usb-phy",}, 149 { }, 150 }; 151 MODULE_DEVICE_TABLE(of, hi6220_phy_of_match); 152 153 static struct platform_driver hi6220_phy_driver = { 154 .probe = hi6220_phy_probe, 155 .driver = { 156 .name = "hi6220-usb-phy", 157 .of_match_table = hi6220_phy_of_match, 158 } 159 }; 160 module_platform_driver(hi6220_phy_driver); 161 162 MODULE_DESCRIPTION("HISILICON HI6220 USB PHY driver"); 163 MODULE_ALIAS("platform:hi6220-usb-phy"); 164 MODULE_LICENSE("GPL"); 165