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