ulpi.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // SPDX-License-Identifier: GPL-2.0
  2. /**
  3. * ulpi.c - DesignWare USB3 Controller's ULPI PHY interface
  4. *
  5. * Copyright (C) 2015 Intel Corporation
  6. *
  7. * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
  8. */
  9. #include <linux/ulpi/regs.h>
  10. #include "core.h"
  11. #include "io.h"
  12. #define DWC3_ULPI_ADDR(a) \
  13. ((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \
  14. DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \
  15. DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a))
  16. static int dwc3_ulpi_busyloop(struct dwc3 *dwc)
  17. {
  18. unsigned count = 1000;
  19. u32 reg;
  20. while (count--) {
  21. reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
  22. if (!(reg & DWC3_GUSB2PHYACC_BUSY))
  23. return 0;
  24. cpu_relax();
  25. }
  26. return -ETIMEDOUT;
  27. }
  28. static int dwc3_ulpi_read(struct device *dev, u8 addr)
  29. {
  30. struct dwc3 *dwc = dev_get_drvdata(dev);
  31. u32 reg;
  32. int ret;
  33. reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
  34. if (reg & DWC3_GUSB2PHYCFG_SUSPHY) {
  35. reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
  36. dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
  37. }
  38. reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
  39. dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
  40. ret = dwc3_ulpi_busyloop(dwc);
  41. if (ret)
  42. return ret;
  43. reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
  44. return DWC3_GUSB2PHYACC_DATA(reg);
  45. }
  46. static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val)
  47. {
  48. struct dwc3 *dwc = dev_get_drvdata(dev);
  49. u32 reg;
  50. reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
  51. if (reg & DWC3_GUSB2PHYCFG_SUSPHY) {
  52. reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
  53. dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
  54. }
  55. reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
  56. reg |= DWC3_GUSB2PHYACC_WRITE | val;
  57. dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
  58. return dwc3_ulpi_busyloop(dwc);
  59. }
  60. static const struct ulpi_ops dwc3_ulpi_ops = {
  61. .read = dwc3_ulpi_read,
  62. .write = dwc3_ulpi_write,
  63. };
  64. int dwc3_ulpi_init(struct dwc3 *dwc)
  65. {
  66. /* Register the interface */
  67. dwc->ulpi = ulpi_register_interface(dwc->dev, &dwc3_ulpi_ops);
  68. if (IS_ERR(dwc->ulpi)) {
  69. dev_err(dwc->dev, "failed to register ULPI interface");
  70. return PTR_ERR(dwc->ulpi);
  71. }
  72. return 0;
  73. }
  74. void dwc3_ulpi_exit(struct dwc3 *dwc)
  75. {
  76. if (dwc->ulpi) {
  77. ulpi_unregister_interface(dwc->ulpi);
  78. dwc->ulpi = NULL;
  79. }
  80. }