1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Ingenic SoCs USB PHY driver 4 * Copyright (c) Paul Cercueil <paul@crapouillou.net> 5 * Copyright (c) 漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com> 6 * Copyright (c) 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com> 7 */ 8 9 #include <linux/bitfield.h> 10 #include <linux/clk.h> 11 #include <linux/delay.h> 12 #include <linux/io.h> 13 #include <linux/module.h> 14 #include <linux/phy/phy.h> 15 #include <linux/platform_device.h> 16 #include <linux/regulator/consumer.h> 17 18 /* OTGPHY register offsets */ 19 #define REG_USBPCR_OFFSET 0x00 20 #define REG_USBRDT_OFFSET 0x04 21 #define REG_USBVBFIL_OFFSET 0x08 22 #define REG_USBPCR1_OFFSET 0x0c 23 24 /* bits within the USBPCR register */ 25 #define USBPCR_USB_MODE BIT(31) 26 #define USBPCR_AVLD_REG BIT(30) 27 #define USBPCR_COMMONONN BIT(25) 28 #define USBPCR_VBUSVLDEXT BIT(24) 29 #define USBPCR_VBUSVLDEXTSEL BIT(23) 30 #define USBPCR_POR BIT(22) 31 #define USBPCR_SIDDQ BIT(21) 32 #define USBPCR_OTG_DISABLE BIT(20) 33 #define USBPCR_TXPREEMPHTUNE BIT(6) 34 35 #define USBPCR_IDPULLUP_MASK GENMASK(29, 28) 36 #define USBPCR_IDPULLUP_ALWAYS 0x2 37 #define USBPCR_IDPULLUP_SUSPEND 0x1 38 #define USBPCR_IDPULLUP_OTG 0x0 39 40 #define USBPCR_COMPDISTUNE_MASK GENMASK(19, 17) 41 #define USBPCR_COMPDISTUNE_DFT 0x4 42 43 #define USBPCR_OTGTUNE_MASK GENMASK(16, 14) 44 #define USBPCR_OTGTUNE_DFT 0x4 45 46 #define USBPCR_SQRXTUNE_MASK GENMASK(13, 11) 47 #define USBPCR_SQRXTUNE_DCR_20PCT 0x7 48 #define USBPCR_SQRXTUNE_DFT 0x3 49 50 #define USBPCR_TXFSLSTUNE_MASK GENMASK(10, 7) 51 #define USBPCR_TXFSLSTUNE_DCR_50PPT 0xf 52 #define USBPCR_TXFSLSTUNE_DCR_25PPT 0x7 53 #define USBPCR_TXFSLSTUNE_DFT 0x3 54 #define USBPCR_TXFSLSTUNE_INC_25PPT 0x1 55 #define USBPCR_TXFSLSTUNE_INC_50PPT 0x0 56 57 #define USBPCR_TXHSXVTUNE_MASK GENMASK(5, 4) 58 #define USBPCR_TXHSXVTUNE_DFT 0x3 59 #define USBPCR_TXHSXVTUNE_DCR_15MV 0x1 60 61 #define USBPCR_TXRISETUNE_MASK GENMASK(5, 4) 62 #define USBPCR_TXRISETUNE_DFT 0x3 63 64 #define USBPCR_TXVREFTUNE_MASK GENMASK(3, 0) 65 #define USBPCR_TXVREFTUNE_INC_75PPT 0xb 66 #define USBPCR_TXVREFTUNE_INC_25PPT 0x7 67 #define USBPCR_TXVREFTUNE_DFT 0x5 68 69 /* bits within the USBRDTR register */ 70 #define USBRDT_UTMI_RST BIT(27) 71 #define USBRDT_HB_MASK BIT(26) 72 #define USBRDT_VBFIL_LD_EN BIT(25) 73 #define USBRDT_IDDIG_EN BIT(24) 74 #define USBRDT_IDDIG_REG BIT(23) 75 #define USBRDT_VBFIL_EN BIT(2) 76 77 /* bits within the USBPCR1 register */ 78 #define USBPCR1_BVLD_REG BIT(31) 79 #define USBPCR1_DPPD BIT(29) 80 #define USBPCR1_DMPD BIT(28) 81 #define USBPCR1_USB_SEL BIT(28) 82 #define USBPCR1_PORT_RST BIT(21) 83 #define USBPCR1_WORD_IF_16BIT BIT(19) 84 85 struct ingenic_soc_info { 86 void (*usb_phy_init)(struct phy *phy); 87 }; 88 89 struct ingenic_usb_phy { 90 const struct ingenic_soc_info *soc_info; 91 92 struct phy *phy; 93 void __iomem *base; 94 struct clk *clk; 95 struct regulator *vcc_supply; 96 }; 97 98 static int ingenic_usb_phy_init(struct phy *phy) 99 { 100 struct ingenic_usb_phy *priv = phy_get_drvdata(phy); 101 int err; 102 u32 reg; 103 104 err = clk_prepare_enable(priv->clk); 105 if (err) { 106 dev_err(&phy->dev, "Unable to start clock: %d\n", err); 107 return err; 108 } 109 110 priv->soc_info->usb_phy_init(phy); 111 112 /* Wait for PHY to reset */ 113 usleep_range(30, 300); 114 reg = readl(priv->base + REG_USBPCR_OFFSET); 115 writel(reg & ~USBPCR_POR, priv->base + REG_USBPCR_OFFSET); 116 usleep_range(300, 1000); 117 118 return 0; 119 } 120 121 static int ingenic_usb_phy_exit(struct phy *phy) 122 { 123 struct ingenic_usb_phy *priv = phy_get_drvdata(phy); 124 125 clk_disable_unprepare(priv->clk); 126 regulator_disable(priv->vcc_supply); 127 128 return 0; 129 } 130 131 static int ingenic_usb_phy_power_on(struct phy *phy) 132 { 133 struct ingenic_usb_phy *priv = phy_get_drvdata(phy); 134 int err; 135 136 err = regulator_enable(priv->vcc_supply); 137 if (err) { 138 dev_err(&phy->dev, "Unable to enable VCC: %d\n", err); 139 return err; 140 } 141 142 return 0; 143 } 144 145 static int ingenic_usb_phy_power_off(struct phy *phy) 146 { 147 struct ingenic_usb_phy *priv = phy_get_drvdata(phy); 148 149 regulator_disable(priv->vcc_supply); 150 151 return 0; 152 } 153 154 static int ingenic_usb_phy_set_mode(struct phy *phy, 155 enum phy_mode mode, int submode) 156 { 157 struct ingenic_usb_phy *priv = phy_get_drvdata(phy); 158 u32 reg; 159 160 switch (mode) { 161 case PHY_MODE_USB_HOST: 162 reg = readl(priv->base + REG_USBPCR_OFFSET); 163 u32p_replace_bits(®, 1, USBPCR_USB_MODE); 164 u32p_replace_bits(®, 0, USBPCR_VBUSVLDEXT); 165 u32p_replace_bits(®, 0, USBPCR_VBUSVLDEXTSEL); 166 u32p_replace_bits(®, 0, USBPCR_OTG_DISABLE); 167 writel(reg, priv->base + REG_USBPCR_OFFSET); 168 169 break; 170 case PHY_MODE_USB_DEVICE: 171 reg = readl(priv->base + REG_USBPCR_OFFSET); 172 u32p_replace_bits(®, 0, USBPCR_USB_MODE); 173 u32p_replace_bits(®, 1, USBPCR_VBUSVLDEXT); 174 u32p_replace_bits(®, 1, USBPCR_VBUSVLDEXTSEL); 175 u32p_replace_bits(®, 1, USBPCR_OTG_DISABLE); 176 writel(reg, priv->base + REG_USBPCR_OFFSET); 177 178 break; 179 case PHY_MODE_USB_OTG: 180 reg = readl(priv->base + REG_USBPCR_OFFSET); 181 u32p_replace_bits(®, 1, USBPCR_USB_MODE); 182 u32p_replace_bits(®, 1, USBPCR_VBUSVLDEXT); 183 u32p_replace_bits(®, 1, USBPCR_VBUSVLDEXTSEL); 184 u32p_replace_bits(®, 0, USBPCR_OTG_DISABLE); 185 writel(reg, priv->base + REG_USBPCR_OFFSET); 186 187 break; 188 default: 189 return -EINVAL; 190 } 191 192 return 0; 193 } 194 195 static const struct phy_ops ingenic_usb_phy_ops = { 196 .init = ingenic_usb_phy_init, 197 .exit = ingenic_usb_phy_exit, 198 .power_on = ingenic_usb_phy_power_on, 199 .power_off = ingenic_usb_phy_power_off, 200 .set_mode = ingenic_usb_phy_set_mode, 201 .owner = THIS_MODULE, 202 }; 203 204 static void jz4770_usb_phy_init(struct phy *phy) 205 { 206 struct ingenic_usb_phy *priv = phy_get_drvdata(phy); 207 u32 reg; 208 209 reg = USBPCR_AVLD_REG | USBPCR_COMMONONN | USBPCR_POR | 210 FIELD_PREP(USBPCR_IDPULLUP_MASK, USBPCR_IDPULLUP_ALWAYS) | 211 FIELD_PREP(USBPCR_COMPDISTUNE_MASK, USBPCR_COMPDISTUNE_DFT) | 212 FIELD_PREP(USBPCR_OTGTUNE_MASK, USBPCR_OTGTUNE_DFT) | 213 FIELD_PREP(USBPCR_SQRXTUNE_MASK, USBPCR_SQRXTUNE_DFT) | 214 FIELD_PREP(USBPCR_TXFSLSTUNE_MASK, USBPCR_TXFSLSTUNE_DFT) | 215 FIELD_PREP(USBPCR_TXRISETUNE_MASK, USBPCR_TXRISETUNE_DFT) | 216 FIELD_PREP(USBPCR_TXVREFTUNE_MASK, USBPCR_TXVREFTUNE_DFT); 217 writel(reg, priv->base + REG_USBPCR_OFFSET); 218 } 219 220 static void jz4775_usb_phy_init(struct phy *phy) 221 { 222 struct ingenic_usb_phy *priv = phy_get_drvdata(phy); 223 u32 reg; 224 225 reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_USB_SEL | 226 USBPCR1_WORD_IF_16BIT; 227 writel(reg, priv->base + REG_USBPCR1_OFFSET); 228 229 reg = USBPCR_COMMONONN | USBPCR_POR | 230 FIELD_PREP(USBPCR_TXVREFTUNE_MASK, USBPCR_TXVREFTUNE_INC_75PPT); 231 writel(reg, priv->base + REG_USBPCR_OFFSET); 232 } 233 234 static void jz4780_usb_phy_init(struct phy *phy) 235 { 236 struct ingenic_usb_phy *priv = phy_get_drvdata(phy); 237 u32 reg; 238 239 reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_USB_SEL | 240 USBPCR1_WORD_IF_16BIT; 241 writel(reg, priv->base + REG_USBPCR1_OFFSET); 242 243 reg = USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR; 244 writel(reg, priv->base + REG_USBPCR_OFFSET); 245 } 246 247 static void x1000_usb_phy_init(struct phy *phy) 248 { 249 struct ingenic_usb_phy *priv = phy_get_drvdata(phy); 250 u32 reg; 251 252 reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT; 253 writel(reg, priv->base + REG_USBPCR1_OFFSET); 254 255 reg = USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR | 256 FIELD_PREP(USBPCR_SQRXTUNE_MASK, USBPCR_SQRXTUNE_DCR_20PCT) | 257 FIELD_PREP(USBPCR_TXHSXVTUNE_MASK, USBPCR_TXHSXVTUNE_DCR_15MV) | 258 FIELD_PREP(USBPCR_TXVREFTUNE_MASK, USBPCR_TXVREFTUNE_INC_25PPT); 259 writel(reg, priv->base + REG_USBPCR_OFFSET); 260 } 261 262 static void x1830_usb_phy_init(struct phy *phy) 263 { 264 struct ingenic_usb_phy *priv = phy_get_drvdata(phy); 265 u32 reg; 266 267 /* rdt */ 268 writel(USBRDT_VBFIL_EN | USBRDT_UTMI_RST, priv->base + REG_USBRDT_OFFSET); 269 270 reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT | 271 USBPCR1_DMPD | USBPCR1_DPPD; 272 writel(reg, priv->base + REG_USBPCR1_OFFSET); 273 274 reg = USBPCR_VBUSVLDEXT | USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR | 275 FIELD_PREP(USBPCR_IDPULLUP_MASK, USBPCR_IDPULLUP_OTG); 276 writel(reg, priv->base + REG_USBPCR_OFFSET); 277 } 278 279 static void x2000_usb_phy_init(struct phy *phy) 280 { 281 struct ingenic_usb_phy *priv = phy_get_drvdata(phy); 282 u32 reg; 283 284 reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_DPPD | USBPCR1_DMPD; 285 writel(reg & ~USBPCR1_PORT_RST, priv->base + REG_USBPCR1_OFFSET); 286 287 reg = USBPCR_POR | FIELD_PREP(USBPCR_IDPULLUP_MASK, USBPCR_IDPULLUP_OTG); 288 writel(reg, priv->base + REG_USBPCR_OFFSET); 289 } 290 291 static const struct ingenic_soc_info jz4770_soc_info = { 292 .usb_phy_init = jz4770_usb_phy_init, 293 }; 294 295 static const struct ingenic_soc_info jz4775_soc_info = { 296 .usb_phy_init = jz4775_usb_phy_init, 297 }; 298 299 static const struct ingenic_soc_info jz4780_soc_info = { 300 .usb_phy_init = jz4780_usb_phy_init, 301 }; 302 303 static const struct ingenic_soc_info x1000_soc_info = { 304 .usb_phy_init = x1000_usb_phy_init, 305 }; 306 307 static const struct ingenic_soc_info x1830_soc_info = { 308 .usb_phy_init = x1830_usb_phy_init, 309 }; 310 311 static const struct ingenic_soc_info x2000_soc_info = { 312 .usb_phy_init = x2000_usb_phy_init, 313 }; 314 315 static int ingenic_usb_phy_probe(struct platform_device *pdev) 316 { 317 struct ingenic_usb_phy *priv; 318 struct phy_provider *provider; 319 struct device *dev = &pdev->dev; 320 int err; 321 322 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 323 if (!priv) 324 return -ENOMEM; 325 326 priv->soc_info = device_get_match_data(dev); 327 if (!priv->soc_info) { 328 dev_err(dev, "Error: No device match found\n"); 329 return -ENODEV; 330 } 331 332 priv->base = devm_platform_ioremap_resource(pdev, 0); 333 if (IS_ERR(priv->base)) { 334 dev_err(dev, "Failed to map registers\n"); 335 return PTR_ERR(priv->base); 336 } 337 338 priv->clk = devm_clk_get(dev, NULL); 339 if (IS_ERR(priv->clk)) { 340 err = PTR_ERR(priv->clk); 341 if (err != -EPROBE_DEFER) 342 dev_err(dev, "Failed to get clock\n"); 343 return err; 344 } 345 346 priv->vcc_supply = devm_regulator_get(dev, "vcc"); 347 if (IS_ERR(priv->vcc_supply)) { 348 err = PTR_ERR(priv->vcc_supply); 349 if (err != -EPROBE_DEFER) 350 dev_err(dev, "Failed to get regulator\n"); 351 return err; 352 } 353 354 priv->phy = devm_phy_create(dev, NULL, &ingenic_usb_phy_ops); 355 if (IS_ERR(priv->phy)) 356 return PTR_ERR(priv->phy); 357 358 phy_set_drvdata(priv->phy, priv); 359 360 provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 361 362 return PTR_ERR_OR_ZERO(provider); 363 } 364 365 static const struct of_device_id ingenic_usb_phy_of_matches[] = { 366 { .compatible = "ingenic,jz4770-phy", .data = &jz4770_soc_info }, 367 { .compatible = "ingenic,jz4775-phy", .data = &jz4775_soc_info }, 368 { .compatible = "ingenic,jz4780-phy", .data = &jz4780_soc_info }, 369 { .compatible = "ingenic,x1000-phy", .data = &x1000_soc_info }, 370 { .compatible = "ingenic,x1830-phy", .data = &x1830_soc_info }, 371 { .compatible = "ingenic,x2000-phy", .data = &x2000_soc_info }, 372 { /* sentinel */ } 373 }; 374 MODULE_DEVICE_TABLE(of, ingenic_usb_phy_of_matches); 375 376 static struct platform_driver ingenic_usb_phy_driver = { 377 .probe = ingenic_usb_phy_probe, 378 .driver = { 379 .name = "ingenic-usb-phy", 380 .of_match_table = ingenic_usb_phy_of_matches, 381 }, 382 }; 383 module_platform_driver(ingenic_usb_phy_driver); 384 385 MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>"); 386 MODULE_AUTHOR("漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>"); 387 MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); 388 MODULE_DESCRIPTION("Ingenic SoCs USB PHY driver"); 389 MODULE_LICENSE("GPL"); 390