0005-usb-fotg2-add-Gemini-specific-handling.patch 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. From f7f6c8aca91093e2f886ec97910b1a7d9a69bf9b Mon Sep 17 00:00:00 2001
  2. From: Linus Walleij <[email protected]>
  3. Date: Wed, 9 Nov 2022 21:05:54 +0100
  4. Subject: [PATCH 05/29] usb: fotg2: add Gemini-specific handling
  5. The Cortina Systems Gemini has bolted on a PHY inside the
  6. silicon that can be handled by six bits in a MISC register in
  7. the system controller.
  8. If we are running on Gemini, look up a syscon regmap through
  9. a phandle and enable VBUS and optionally the Mini-B connector.
  10. If the device is flagged as "wakeup-source" using the standard
  11. DT bindings, we also enable this in the global controller for
  12. respective port.
  13. Signed-off-by: Linus Walleij <[email protected]>
  14. Link: https://lore.kernel.org/r/[email protected]
  15. Signed-off-by: Greg Kroah-Hartman <[email protected]>
  16. ---
  17. --- a/drivers/usb/fotg210/Kconfig
  18. +++ b/drivers/usb/fotg210/Kconfig
  19. @@ -5,6 +5,7 @@ config USB_FOTG210
  20. depends on USB || USB_GADGET
  21. depends on HAS_DMA && HAS_IOMEM
  22. default ARCH_GEMINI
  23. + select MFD_SYSCON
  24. help
  25. Faraday FOTG210 is a dual-mode USB controller that can act
  26. in both host controller and peripheral controller mode.
  27. --- a/drivers/usb/fotg210/fotg210-core.c
  28. +++ b/drivers/usb/fotg210/fotg210-core.c
  29. @@ -5,15 +5,86 @@
  30. * whether to proceed with probing the host or the peripheral
  31. * driver.
  32. */
  33. +#include <linux/bitops.h>
  34. #include <linux/device.h>
  35. +#include <linux/mfd/syscon.h>
  36. #include <linux/module.h>
  37. #include <linux/of.h>
  38. #include <linux/platform_device.h>
  39. +#include <linux/regmap.h>
  40. #include <linux/usb.h>
  41. #include <linux/usb/otg.h>
  42. #include "fotg210.h"
  43. +/*
  44. + * Gemini-specific initialization function, only executed on the
  45. + * Gemini SoC using the global misc control register.
  46. + *
  47. + * The gemini USB blocks are connected to either Mini-A (host mode) or
  48. + * Mini-B (peripheral mode) plugs. There is no role switch support on the
  49. + * Gemini SoC, just either-or.
  50. + */
  51. +#define GEMINI_GLOBAL_MISC_CTRL 0x30
  52. +#define GEMINI_MISC_USB0_WAKEUP BIT(14)
  53. +#define GEMINI_MISC_USB1_WAKEUP BIT(15)
  54. +#define GEMINI_MISC_USB0_VBUS_ON BIT(22)
  55. +#define GEMINI_MISC_USB1_VBUS_ON BIT(23)
  56. +#define GEMINI_MISC_USB0_MINI_B BIT(29)
  57. +#define GEMINI_MISC_USB1_MINI_B BIT(30)
  58. +
  59. +static int fotg210_gemini_init(struct device *dev, struct resource *res,
  60. + enum usb_dr_mode mode)
  61. +{
  62. + struct device_node *np = dev->of_node;
  63. + struct regmap *map;
  64. + bool wakeup;
  65. + u32 mask, val;
  66. + int ret;
  67. +
  68. + map = syscon_regmap_lookup_by_phandle(np, "syscon");
  69. + if (IS_ERR(map)) {
  70. + dev_err(dev, "no syscon\n");
  71. + return PTR_ERR(map);
  72. + }
  73. + wakeup = of_property_read_bool(np, "wakeup-source");
  74. +
  75. + /*
  76. + * Figure out if this is USB0 or USB1 by simply checking the
  77. + * physical base address.
  78. + */
  79. + mask = 0;
  80. + if (res->start == 0x69000000) {
  81. + mask = GEMINI_MISC_USB1_VBUS_ON | GEMINI_MISC_USB1_MINI_B |
  82. + GEMINI_MISC_USB1_WAKEUP;
  83. + if (mode == USB_DR_MODE_HOST)
  84. + val = GEMINI_MISC_USB1_VBUS_ON;
  85. + else
  86. + val = GEMINI_MISC_USB1_MINI_B;
  87. + if (wakeup)
  88. + val |= GEMINI_MISC_USB1_WAKEUP;
  89. + } else {
  90. + mask = GEMINI_MISC_USB0_VBUS_ON | GEMINI_MISC_USB0_MINI_B |
  91. + GEMINI_MISC_USB0_WAKEUP;
  92. + if (mode == USB_DR_MODE_HOST)
  93. + val = GEMINI_MISC_USB0_VBUS_ON;
  94. + else
  95. + val = GEMINI_MISC_USB0_MINI_B;
  96. + if (wakeup)
  97. + val |= GEMINI_MISC_USB0_WAKEUP;
  98. + }
  99. +
  100. + ret = regmap_update_bits(map, GEMINI_GLOBAL_MISC_CTRL, mask, val);
  101. + if (ret) {
  102. + dev_err(dev, "failed to initialize Gemini PHY\n");
  103. + return ret;
  104. + }
  105. +
  106. + dev_info(dev, "initialized Gemini PHY in %s mode\n",
  107. + (mode == USB_DR_MODE_HOST) ? "host" : "gadget");
  108. + return 0;
  109. +}
  110. +
  111. static int fotg210_probe(struct platform_device *pdev)
  112. {
  113. struct device *dev = &pdev->dev;
  114. @@ -22,6 +93,15 @@ static int fotg210_probe(struct platform
  115. mode = usb_get_dr_mode(dev);
  116. + if (of_device_is_compatible(dev->of_node, "cortina,gemini-usb")) {
  117. + struct resource *res;
  118. +
  119. + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  120. + ret = fotg210_gemini_init(dev, res, mode);
  121. + if (ret)
  122. + return ret;
  123. + }
  124. +
  125. if (mode == USB_DR_MODE_PERIPHERAL)
  126. ret = fotg210_udc_probe(pdev);
  127. else