1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Intel Keem Bay USB PHY driver 4 * Copyright (C) 2020 Intel Corporation 5 */ 6 7 #include <linux/bitfield.h> 8 #include <linux/bits.h> 9 #include <linux/clk.h> 10 #include <linux/delay.h> 11 #include <linux/module.h> 12 #include <linux/phy/phy.h> 13 #include <linux/platform_device.h> 14 #include <linux/regmap.h> 15 16 /* USS (USB Subsystem) clock control registers */ 17 #define USS_CPR_CLK_EN 0x00 18 #define USS_CPR_CLK_SET 0x04 19 #define USS_CPR_CLK_CLR 0x08 20 #define USS_CPR_RST_EN 0x10 21 #define USS_CPR_RST_SET 0x14 22 #define USS_CPR_RST_CLR 0x18 23 24 /* USS clock/reset bit fields */ 25 #define USS_CPR_PHY_TST BIT(6) 26 #define USS_CPR_LOW_JIT BIT(5) 27 #define USS_CPR_CORE BIT(4) 28 #define USS_CPR_SUSPEND BIT(3) 29 #define USS_CPR_ALT_REF BIT(2) 30 #define USS_CPR_REF BIT(1) 31 #define USS_CPR_SYS BIT(0) 32 #define USS_CPR_MASK GENMASK(6, 0) 33 34 /* USS APB slave registers */ 35 #define USS_USB_CTRL_CFG0 0x10 36 #define VCC_RESET_N_MASK BIT(31) 37 38 #define USS_USB_PHY_CFG0 0x30 39 #define POR_MASK BIT(15) 40 #define PHY_RESET_MASK BIT(14) 41 #define PHY_REF_USE_PAD_MASK BIT(5) 42 43 #define USS_USB_PHY_CFG6 0x64 44 #define PHY0_SRAM_EXT_LD_DONE_MASK BIT(23) 45 46 #define USS_USB_PARALLEL_IF_CTRL 0xa0 47 #define USB_PHY_CR_PARA_SEL_MASK BIT(2) 48 49 #define USS_USB_TSET_SIGNALS_AND_GLOB 0xac 50 #define USB_PHY_CR_PARA_CLK_EN_MASK BIT(7) 51 52 #define USS_USB_STATUS_REG 0xb8 53 #define PHY0_SRAM_INIT_DONE_MASK BIT(3) 54 55 #define USS_USB_TIEOFFS_CONSTANTS_REG1 0xc0 56 #define IDDQ_ENABLE_MASK BIT(10) 57 58 struct keembay_usb_phy { 59 struct device *dev; 60 struct regmap *regmap_cpr; 61 struct regmap *regmap_slv; 62 }; 63 64 static const struct regmap_config keembay_regmap_config = { 65 .reg_bits = 32, 66 .val_bits = 32, 67 .reg_stride = 4, 68 .max_register = USS_USB_TIEOFFS_CONSTANTS_REG1, 69 }; 70 71 static int keembay_usb_clocks_on(struct keembay_usb_phy *priv) 72 { 73 int ret; 74 75 ret = regmap_update_bits(priv->regmap_cpr, USS_CPR_CLK_SET, 76 USS_CPR_MASK, USS_CPR_MASK); 77 if (ret) { 78 dev_err(priv->dev, "error clock set: %d\n", ret); 79 return ret; 80 } 81 82 ret = regmap_update_bits(priv->regmap_cpr, USS_CPR_RST_SET, 83 USS_CPR_MASK, USS_CPR_MASK); 84 if (ret) { 85 dev_err(priv->dev, "error reset set: %d\n", ret); 86 return ret; 87 } 88 89 ret = regmap_update_bits(priv->regmap_slv, 90 USS_USB_TIEOFFS_CONSTANTS_REG1, 91 IDDQ_ENABLE_MASK, 92 FIELD_PREP(IDDQ_ENABLE_MASK, 0)); 93 if (ret) { 94 dev_err(priv->dev, "error iddq disable: %d\n", ret); 95 return ret; 96 } 97 98 /* Wait 30us to ensure all analog blocks are powered up. */ 99 usleep_range(30, 60); 100 101 ret = regmap_update_bits(priv->regmap_slv, USS_USB_PHY_CFG0, 102 PHY_REF_USE_PAD_MASK, 103 FIELD_PREP(PHY_REF_USE_PAD_MASK, 1)); 104 if (ret) 105 dev_err(priv->dev, "error ref clock select: %d\n", ret); 106 107 return ret; 108 } 109 110 static int keembay_usb_core_off(struct keembay_usb_phy *priv) 111 { 112 int ret; 113 114 ret = regmap_update_bits(priv->regmap_slv, USS_USB_CTRL_CFG0, 115 VCC_RESET_N_MASK, 116 FIELD_PREP(VCC_RESET_N_MASK, 0)); 117 if (ret) 118 dev_err(priv->dev, "error core reset: %d\n", ret); 119 120 return ret; 121 } 122 123 static int keembay_usb_core_on(struct keembay_usb_phy *priv) 124 { 125 int ret; 126 127 ret = regmap_update_bits(priv->regmap_slv, USS_USB_CTRL_CFG0, 128 VCC_RESET_N_MASK, 129 FIELD_PREP(VCC_RESET_N_MASK, 1)); 130 if (ret) 131 dev_err(priv->dev, "error core on: %d\n", ret); 132 133 return ret; 134 } 135 136 static int keembay_usb_phys_on(struct keembay_usb_phy *priv) 137 { 138 int ret; 139 140 ret = regmap_update_bits(priv->regmap_slv, USS_USB_PHY_CFG0, 141 POR_MASK | PHY_RESET_MASK, 142 FIELD_PREP(POR_MASK | PHY_RESET_MASK, 0)); 143 if (ret) 144 dev_err(priv->dev, "error phys on: %d\n", ret); 145 146 return ret; 147 } 148 149 static int keembay_usb_phy_init(struct phy *phy) 150 { 151 struct keembay_usb_phy *priv = phy_get_drvdata(phy); 152 u32 val; 153 int ret; 154 155 ret = keembay_usb_core_off(priv); 156 if (ret) 157 return ret; 158 159 /* 160 * According to Keem Bay datasheet, wait minimum 20us after clock 161 * enable before bringing PHYs out of reset. 162 */ 163 usleep_range(20, 40); 164 165 ret = keembay_usb_phys_on(priv); 166 if (ret) 167 return ret; 168 169 ret = regmap_update_bits(priv->regmap_slv, 170 USS_USB_TSET_SIGNALS_AND_GLOB, 171 USB_PHY_CR_PARA_CLK_EN_MASK, 172 FIELD_PREP(USB_PHY_CR_PARA_CLK_EN_MASK, 0)); 173 if (ret) { 174 dev_err(priv->dev, "error cr clock disable: %d\n", ret); 175 return ret; 176 } 177 178 /* 179 * According to Keem Bay datasheet, wait 2us after disabling the 180 * clock into the USB 3.x parallel interface. 181 */ 182 udelay(2); 183 184 ret = regmap_update_bits(priv->regmap_slv, 185 USS_USB_PARALLEL_IF_CTRL, 186 USB_PHY_CR_PARA_SEL_MASK, 187 FIELD_PREP(USB_PHY_CR_PARA_SEL_MASK, 1)); 188 if (ret) { 189 dev_err(priv->dev, "error cr select: %d\n", ret); 190 return ret; 191 } 192 193 ret = regmap_update_bits(priv->regmap_slv, 194 USS_USB_TSET_SIGNALS_AND_GLOB, 195 USB_PHY_CR_PARA_CLK_EN_MASK, 196 FIELD_PREP(USB_PHY_CR_PARA_CLK_EN_MASK, 1)); 197 if (ret) { 198 dev_err(priv->dev, "error cr clock enable: %d\n", ret); 199 return ret; 200 } 201 202 ret = regmap_read_poll_timeout(priv->regmap_slv, USS_USB_STATUS_REG, 203 val, val & PHY0_SRAM_INIT_DONE_MASK, 204 USEC_PER_MSEC, 10 * USEC_PER_MSEC); 205 if (ret) { 206 dev_err(priv->dev, "SRAM init not done: %d\n", ret); 207 return ret; 208 } 209 210 ret = regmap_update_bits(priv->regmap_slv, USS_USB_PHY_CFG6, 211 PHY0_SRAM_EXT_LD_DONE_MASK, 212 FIELD_PREP(PHY0_SRAM_EXT_LD_DONE_MASK, 1)); 213 if (ret) { 214 dev_err(priv->dev, "error SRAM init done set: %d\n", ret); 215 return ret; 216 } 217 218 /* 219 * According to Keem Bay datasheet, wait 20us after setting the 220 * SRAM load done bit, before releasing the controller reset. 221 */ 222 usleep_range(20, 40); 223 224 return keembay_usb_core_on(priv); 225 } 226 227 static const struct phy_ops ops = { 228 .init = keembay_usb_phy_init, 229 .owner = THIS_MODULE, 230 }; 231 232 static int keembay_usb_phy_probe(struct platform_device *pdev) 233 { 234 struct device *dev = &pdev->dev; 235 struct keembay_usb_phy *priv; 236 struct phy *generic_phy; 237 struct phy_provider *phy_provider; 238 void __iomem *base; 239 int ret; 240 241 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 242 if (!priv) 243 return -ENOMEM; 244 245 base = devm_platform_ioremap_resource_byname(pdev, "cpr-apb-base"); 246 if (IS_ERR(base)) 247 return PTR_ERR(base); 248 249 priv->regmap_cpr = devm_regmap_init_mmio(dev, base, 250 &keembay_regmap_config); 251 if (IS_ERR(priv->regmap_cpr)) 252 return PTR_ERR(priv->regmap_cpr); 253 254 base = devm_platform_ioremap_resource_byname(pdev, "slv-apb-base"); 255 if (IS_ERR(base)) 256 return PTR_ERR(base); 257 258 priv->regmap_slv = devm_regmap_init_mmio(dev, base, 259 &keembay_regmap_config); 260 if (IS_ERR(priv->regmap_slv)) 261 return PTR_ERR(priv->regmap_slv); 262 263 generic_phy = devm_phy_create(dev, dev->of_node, &ops); 264 if (IS_ERR(generic_phy)) 265 return dev_err_probe(dev, PTR_ERR(generic_phy), 266 "failed to create PHY\n"); 267 268 phy_set_drvdata(generic_phy, priv); 269 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 270 if (IS_ERR(phy_provider)) 271 return dev_err_probe(dev, PTR_ERR(phy_provider), 272 "failed to register phy provider\n"); 273 274 /* Setup USB subsystem clocks */ 275 ret = keembay_usb_clocks_on(priv); 276 if (ret) 277 return ret; 278 279 /* and turn on the DWC3 core, prior to DWC3 driver init. */ 280 return keembay_usb_core_on(priv); 281 } 282 283 static const struct of_device_id keembay_usb_phy_dt_ids[] = { 284 { .compatible = "intel,keembay-usb-phy" }, 285 {} 286 }; 287 MODULE_DEVICE_TABLE(of, keembay_usb_phy_dt_ids); 288 289 static struct platform_driver keembay_usb_phy_driver = { 290 .probe = keembay_usb_phy_probe, 291 .driver = { 292 .name = "keembay-usb-phy", 293 .of_match_table = keembay_usb_phy_dt_ids, 294 }, 295 }; 296 module_platform_driver(keembay_usb_phy_driver); 297 298 MODULE_AUTHOR("Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad@intel.com>"); 299 MODULE_DESCRIPTION("Intel Keem Bay USB PHY driver"); 300 MODULE_LICENSE("GPL v2"); 301