ulpi.c 2.0 KB

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