dwc3-apple.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Apple Silicon DWC3 Glue driver
  4. * Copyright (C) The Asahi Linux Contributors
  5. *
  6. * Based on:
  7. * - dwc3-qcom.c Copyright (c) 2018, The Linux Foundation. All rights reserved.
  8. * - dwc3-of-simple.c Copyright (c) 2015 Texas Instruments Incorporated - https://www.ti.com
  9. */
  10. #include <linux/of.h>
  11. #include <linux/module.h>
  12. #include <linux/mutex.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/reset.h>
  15. #include "glue.h"
  16. /*
  17. * This platform requires a very specific sequence of operations to bring up dwc3 and its USB3 PHY:
  18. *
  19. * 1) The PHY itself has to be brought up; for this we need to know the mode (USB3,
  20. * USB3+DisplayPort, USB4, etc) and the lane orientation. This happens through typec_mux_set.
  21. * 2) DWC3 has to be brought up but we must not touch the gadget area or start xhci yet.
  22. * 3) The PHY bring-up has to be finalized and dwc3's PIPE interface has to be switched to the
  23. * USB3 PHY, this is done inside phy_set_mode.
  24. * 4) We can now initialize xhci or gadget mode.
  25. *
  26. * We can switch 1 and 2 but 3 has to happen after (1 and 2) and 4 has to happen after 3.
  27. *
  28. * And then to bring this all down again:
  29. *
  30. * 1) DWC3 has to exit host or gadget mode and must no longer touch those registers
  31. * 2) The PHY has to switch dwc3's PIPE interface back to the dummy backend
  32. * 3) The PHY itself can be shut down, this happens from typec_mux_set
  33. *
  34. * We also can't transition the PHY from one mode to another while dwc3 is up and running (this is
  35. * slightly wrong, some transitions are possible, others aren't but because we have no documentation
  36. * for this I'd rather play it safe).
  37. *
  38. * After both the PHY and dwc3 are initialized we will only ever see a single "new device connected"
  39. * event. If we just keep them running only the first device plugged in will ever work. XHCI's port
  40. * status register actually does show the correct state but no interrupt ever comes in. In gadget
  41. * mode we don't even get a USBDisconnected event and everything looks like there's still something
  42. * connected on the other end.
  43. * This can be partially explained because the USB2 D+/D- lines are connected through a stateful
  44. * eUSB2 repeater which in turn is controlled by a variant of the TI TPS6598x USB PD chip which
  45. * resets the repeater out-of-band everytime the CC lines are (dis)connected. This then requires a
  46. * PHY reset to make sure the PHY and the eUSB2 repeater state are synchronized again.
  47. *
  48. * And to make this all extra fun: If we get the order of some of this wrong either the port is just
  49. * broken until a phy+dwc3 reset, or it's broken until a full SoC reset (likely because we can't
  50. * reset some parts of the PHY), or some watchdog kicks in after a few seconds and forces a full SoC
  51. * reset (mostly seen this with USB4/Thunderbolt but there's clearly some watchdog that hates
  52. * invalid states).
  53. *
  54. * Hence there's really no good way to keep dwc3 fully up and running after we disconnect a cable
  55. * because then we can't shut down the PHY anymore. And if we kept the PHY running in whatever mode
  56. * it was until the next cable is connected we'd need to tear it all down and bring it back up again
  57. * anyway to detect and use the next device.
  58. *
  59. * Instead, we just shut down everything when a cable is disconnected and transition to
  60. * DWC3_APPLE_NO_CABLE.
  61. * During initial probe we don't have any information about the connected cable and can't bring up
  62. * the PHY properly and thus also can't fully bring up dwc3. Instead, we just keep everything off
  63. * and defer the first dwc3 probe until we get the first cable connected event. Until then we stay
  64. * in DWC3_APPLE_PROBE_PENDING.
  65. * Once a cable is connected we then keep track of the controller mode here by transitioning to
  66. * DWC3_APPLE_HOST or DWC3_APPLE_DEVICE.
  67. */
  68. enum dwc3_apple_state {
  69. DWC3_APPLE_PROBE_PENDING, /* Before first cable connection, dwc3_core_probe not called */
  70. DWC3_APPLE_NO_CABLE, /* No cable connected, dwc3 suspended after dwc3_core_exit */
  71. DWC3_APPLE_HOST, /* Cable connected, dwc3 in host mode */
  72. DWC3_APPLE_DEVICE, /* Cable connected, dwc3 in device mode */
  73. };
  74. /**
  75. * struct dwc3_apple - Apple-specific DWC3 USB controller
  76. * @dwc: Core DWC3 structure
  77. * @dev: Pointer to the device structure
  78. * @mmio_resource: Resource to be passed to dwc3_core_probe
  79. * @apple_regs: Apple-specific DWC3 registers
  80. * @reset: Reset control
  81. * @role_sw: USB role switch
  82. * @lock: Mutex for synchronizing access
  83. * @state: Current state of the controller, see documentation for the enum for details
  84. */
  85. struct dwc3_apple {
  86. struct dwc3 dwc;
  87. struct device *dev;
  88. struct resource *mmio_resource;
  89. void __iomem *apple_regs;
  90. struct reset_control *reset;
  91. struct usb_role_switch *role_sw;
  92. struct mutex lock;
  93. enum dwc3_apple_state state;
  94. };
  95. #define to_dwc3_apple(d) container_of((d), struct dwc3_apple, dwc)
  96. /*
  97. * Apple Silicon dwc3 vendor-specific registers
  98. *
  99. * These registers were identified by tracing XNU's memory access patterns and correlating them with
  100. * debug output over serial to determine their names. We don't exactly know what these do but
  101. * without these USB3 devices sometimes don't work.
  102. */
  103. #define APPLE_DWC3_REGS_START 0xcd00
  104. #define APPLE_DWC3_REGS_END 0xcdff
  105. #define APPLE_DWC3_CIO_LFPS_OFFSET 0xcd38
  106. #define APPLE_DWC3_CIO_LFPS_OFFSET_VALUE 0xf800f80
  107. #define APPLE_DWC3_CIO_BW_NGT_OFFSET 0xcd3c
  108. #define APPLE_DWC3_CIO_BW_NGT_OFFSET_VALUE 0xfc00fc0
  109. #define APPLE_DWC3_CIO_LINK_TIMER 0xcd40
  110. #define APPLE_DWC3_CIO_PENDING_HP_TIMER GENMASK(23, 16)
  111. #define APPLE_DWC3_CIO_PENDING_HP_TIMER_VALUE 0x14
  112. #define APPLE_DWC3_CIO_PM_LC_TIMER GENMASK(15, 8)
  113. #define APPLE_DWC3_CIO_PM_LC_TIMER_VALUE 0xa
  114. #define APPLE_DWC3_CIO_PM_ENTRY_TIMER GENMASK(7, 0)
  115. #define APPLE_DWC3_CIO_PM_ENTRY_TIMER_VALUE 0x10
  116. static inline void dwc3_apple_writel(struct dwc3_apple *appledwc, u32 offset, u32 value)
  117. {
  118. writel(value, appledwc->apple_regs + offset - APPLE_DWC3_REGS_START);
  119. }
  120. static inline u32 dwc3_apple_readl(struct dwc3_apple *appledwc, u32 offset)
  121. {
  122. return readl(appledwc->apple_regs + offset - APPLE_DWC3_REGS_START);
  123. }
  124. static inline void dwc3_apple_mask(struct dwc3_apple *appledwc, u32 offset, u32 mask, u32 value)
  125. {
  126. u32 reg;
  127. reg = dwc3_apple_readl(appledwc, offset);
  128. reg &= ~mask;
  129. reg |= value;
  130. dwc3_apple_writel(appledwc, offset, reg);
  131. }
  132. static void dwc3_apple_setup_cio(struct dwc3_apple *appledwc)
  133. {
  134. dwc3_apple_writel(appledwc, APPLE_DWC3_CIO_LFPS_OFFSET, APPLE_DWC3_CIO_LFPS_OFFSET_VALUE);
  135. dwc3_apple_writel(appledwc, APPLE_DWC3_CIO_BW_NGT_OFFSET,
  136. APPLE_DWC3_CIO_BW_NGT_OFFSET_VALUE);
  137. dwc3_apple_mask(appledwc, APPLE_DWC3_CIO_LINK_TIMER, APPLE_DWC3_CIO_PENDING_HP_TIMER,
  138. FIELD_PREP(APPLE_DWC3_CIO_PENDING_HP_TIMER,
  139. APPLE_DWC3_CIO_PENDING_HP_TIMER_VALUE));
  140. dwc3_apple_mask(appledwc, APPLE_DWC3_CIO_LINK_TIMER, APPLE_DWC3_CIO_PM_LC_TIMER,
  141. FIELD_PREP(APPLE_DWC3_CIO_PM_LC_TIMER, APPLE_DWC3_CIO_PM_LC_TIMER_VALUE));
  142. dwc3_apple_mask(appledwc, APPLE_DWC3_CIO_LINK_TIMER, APPLE_DWC3_CIO_PM_ENTRY_TIMER,
  143. FIELD_PREP(APPLE_DWC3_CIO_PM_ENTRY_TIMER,
  144. APPLE_DWC3_CIO_PM_ENTRY_TIMER_VALUE));
  145. }
  146. static void dwc3_apple_set_ptrcap(struct dwc3_apple *appledwc, u32 mode)
  147. {
  148. guard(spinlock_irqsave)(&appledwc->dwc.lock);
  149. dwc3_set_prtcap(&appledwc->dwc, mode, false);
  150. }
  151. static int dwc3_apple_core_probe(struct dwc3_apple *appledwc)
  152. {
  153. struct dwc3_probe_data probe_data = {};
  154. int ret;
  155. lockdep_assert_held(&appledwc->lock);
  156. WARN_ON_ONCE(appledwc->state != DWC3_APPLE_PROBE_PENDING);
  157. appledwc->dwc.dev = appledwc->dev;
  158. probe_data.dwc = &appledwc->dwc;
  159. probe_data.res = appledwc->mmio_resource;
  160. probe_data.ignore_clocks_and_resets = true;
  161. probe_data.skip_core_init_mode = true;
  162. probe_data.properties = DWC3_DEFAULT_PROPERTIES;
  163. ret = dwc3_core_probe(&probe_data);
  164. if (ret)
  165. return ret;
  166. appledwc->state = DWC3_APPLE_NO_CABLE;
  167. return 0;
  168. }
  169. static int dwc3_apple_core_init(struct dwc3_apple *appledwc)
  170. {
  171. int ret;
  172. lockdep_assert_held(&appledwc->lock);
  173. switch (appledwc->state) {
  174. case DWC3_APPLE_PROBE_PENDING:
  175. ret = dwc3_apple_core_probe(appledwc);
  176. if (ret)
  177. dev_err(appledwc->dev, "Failed to probe DWC3 Core, err=%d\n", ret);
  178. break;
  179. case DWC3_APPLE_NO_CABLE:
  180. ret = dwc3_core_init(&appledwc->dwc);
  181. if (ret)
  182. dev_err(appledwc->dev, "Failed to initialize DWC3 Core, err=%d\n", ret);
  183. break;
  184. default:
  185. /* Unreachable unless there's a bug in this driver */
  186. WARN_ON_ONCE(1);
  187. ret = -EINVAL;
  188. break;
  189. }
  190. return ret;
  191. }
  192. static int dwc3_apple_init(struct dwc3_apple *appledwc, enum dwc3_apple_state state)
  193. {
  194. int ret, ret_reset;
  195. lockdep_assert_held(&appledwc->lock);
  196. /*
  197. * The USB2 PHY on this platform must be configured for host or device mode while it is
  198. * still powered off and before dwc3 tries to access it. Otherwise, the new configuration
  199. * will sometimes only take affect after the *next* time dwc3 is brought up which causes
  200. * the connected device to just not work.
  201. * The USB3 PHY must be configured later after dwc3 has already been initialized.
  202. */
  203. switch (state) {
  204. case DWC3_APPLE_HOST:
  205. phy_set_mode(appledwc->dwc.usb2_generic_phy[0], PHY_MODE_USB_HOST);
  206. break;
  207. case DWC3_APPLE_DEVICE:
  208. phy_set_mode(appledwc->dwc.usb2_generic_phy[0], PHY_MODE_USB_DEVICE);
  209. break;
  210. default:
  211. /* Unreachable unless there's a bug in this driver */
  212. return -EINVAL;
  213. }
  214. ret = reset_control_deassert(appledwc->reset);
  215. if (ret) {
  216. dev_err(appledwc->dev, "Failed to deassert reset, err=%d\n", ret);
  217. return ret;
  218. }
  219. ret = dwc3_apple_core_init(appledwc);
  220. if (ret)
  221. goto reset_assert;
  222. /*
  223. * Now that the core is initialized and already went through dwc3_core_soft_reset we can
  224. * configure some unknown Apple-specific settings and then bring up xhci or gadget mode.
  225. */
  226. dwc3_apple_setup_cio(appledwc);
  227. switch (state) {
  228. case DWC3_APPLE_HOST:
  229. appledwc->dwc.dr_mode = USB_DR_MODE_HOST;
  230. dwc3_apple_set_ptrcap(appledwc, DWC3_GCTL_PRTCAP_HOST);
  231. /*
  232. * This platform requires SUSPHY to be enabled here already in order to properly
  233. * configure the PHY and switch dwc3's PIPE interface to USB3 PHY. The USB2 PHY
  234. * has already been configured to the correct mode earlier.
  235. */
  236. dwc3_enable_susphy(&appledwc->dwc, true);
  237. phy_set_mode(appledwc->dwc.usb3_generic_phy[0], PHY_MODE_USB_HOST);
  238. ret = dwc3_host_init(&appledwc->dwc);
  239. if (ret) {
  240. dev_err(appledwc->dev, "Failed to initialize host, ret=%d\n", ret);
  241. goto core_exit;
  242. }
  243. break;
  244. case DWC3_APPLE_DEVICE:
  245. appledwc->dwc.dr_mode = USB_DR_MODE_PERIPHERAL;
  246. dwc3_apple_set_ptrcap(appledwc, DWC3_GCTL_PRTCAP_DEVICE);
  247. /*
  248. * This platform requires SUSPHY to be enabled here already in order to properly
  249. * configure the PHY and switch dwc3's PIPE interface to USB3 PHY. The USB2 PHY
  250. * has already been configured to the correct mode earlier.
  251. */
  252. dwc3_enable_susphy(&appledwc->dwc, true);
  253. phy_set_mode(appledwc->dwc.usb3_generic_phy[0], PHY_MODE_USB_DEVICE);
  254. ret = dwc3_gadget_init(&appledwc->dwc);
  255. if (ret) {
  256. dev_err(appledwc->dev, "Failed to initialize gadget, ret=%d\n", ret);
  257. goto core_exit;
  258. }
  259. break;
  260. default:
  261. /* Unreachable unless there's a bug in this driver */
  262. WARN_ON_ONCE(1);
  263. ret = -EINVAL;
  264. goto core_exit;
  265. }
  266. appledwc->state = state;
  267. return 0;
  268. core_exit:
  269. dwc3_core_exit(&appledwc->dwc);
  270. reset_assert:
  271. ret_reset = reset_control_assert(appledwc->reset);
  272. if (ret_reset)
  273. dev_warn(appledwc->dev, "Failed to assert reset, err=%d\n", ret_reset);
  274. return ret;
  275. }
  276. static int dwc3_apple_exit(struct dwc3_apple *appledwc)
  277. {
  278. int ret = 0;
  279. lockdep_assert_held(&appledwc->lock);
  280. switch (appledwc->state) {
  281. case DWC3_APPLE_PROBE_PENDING:
  282. case DWC3_APPLE_NO_CABLE:
  283. /* Nothing to do if we're already off */
  284. return 0;
  285. case DWC3_APPLE_DEVICE:
  286. dwc3_gadget_exit(&appledwc->dwc);
  287. break;
  288. case DWC3_APPLE_HOST:
  289. dwc3_host_exit(&appledwc->dwc);
  290. break;
  291. }
  292. /*
  293. * This platform requires SUSPHY to be enabled in order to properly power down the PHY
  294. * and switch dwc3's PIPE interface back to a dummy PHY (i.e. no USB3 support and USB2 via
  295. * a different PHY connected through ULPI).
  296. */
  297. dwc3_enable_susphy(&appledwc->dwc, true);
  298. dwc3_core_exit(&appledwc->dwc);
  299. appledwc->state = DWC3_APPLE_NO_CABLE;
  300. ret = reset_control_assert(appledwc->reset);
  301. if (ret) {
  302. dev_err(appledwc->dev, "Failed to assert reset, err=%d\n", ret);
  303. return ret;
  304. }
  305. return 0;
  306. }
  307. static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, enum usb_role role)
  308. {
  309. struct dwc3_apple *appledwc = usb_role_switch_get_drvdata(sw);
  310. int ret;
  311. guard(mutex)(&appledwc->lock);
  312. /*
  313. * Skip role switches if appledwc is already in the desired state. The
  314. * USB-C port controller on M2 and M1/M2 Pro/Max/Ultra devices issues
  315. * additional interrupts which results in usb_role_switch_set_role()
  316. * calls with the current role.
  317. * Ignore those calls here to ensure the USB-C port controller and
  318. * appledwc are in a consistent state.
  319. * This matches the behaviour in __dwc3_set_mode().
  320. * Do no handle USB_ROLE_NONE for DWC3_APPLE_NO_CABLE and
  321. * DWC3_APPLE_PROBE_PENDING since that is no-op anyway.
  322. */
  323. if (appledwc->state == DWC3_APPLE_HOST && role == USB_ROLE_HOST)
  324. return 0;
  325. if (appledwc->state == DWC3_APPLE_DEVICE && role == USB_ROLE_DEVICE)
  326. return 0;
  327. /*
  328. * We need to tear all of dwc3 down and re-initialize it every time a cable is
  329. * connected or disconnected or when the mode changes. See the documentation for enum
  330. * dwc3_apple_state for details.
  331. */
  332. ret = dwc3_apple_exit(appledwc);
  333. if (ret)
  334. return ret;
  335. switch (role) {
  336. case USB_ROLE_NONE:
  337. /* Nothing to do if no cable is connected */
  338. return 0;
  339. case USB_ROLE_HOST:
  340. return dwc3_apple_init(appledwc, DWC3_APPLE_HOST);
  341. case USB_ROLE_DEVICE:
  342. return dwc3_apple_init(appledwc, DWC3_APPLE_DEVICE);
  343. default:
  344. dev_err(appledwc->dev, "Invalid target role: %d\n", role);
  345. return -EINVAL;
  346. }
  347. }
  348. static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw)
  349. {
  350. struct dwc3_apple *appledwc = usb_role_switch_get_drvdata(sw);
  351. guard(mutex)(&appledwc->lock);
  352. switch (appledwc->state) {
  353. case DWC3_APPLE_HOST:
  354. return USB_ROLE_HOST;
  355. case DWC3_APPLE_DEVICE:
  356. return USB_ROLE_DEVICE;
  357. case DWC3_APPLE_NO_CABLE:
  358. case DWC3_APPLE_PROBE_PENDING:
  359. return USB_ROLE_NONE;
  360. default:
  361. /* Unreachable unless there's a bug in this driver */
  362. dev_err(appledwc->dev, "Invalid internal state: %d\n", appledwc->state);
  363. return USB_ROLE_NONE;
  364. }
  365. }
  366. static int dwc3_apple_setup_role_switch(struct dwc3_apple *appledwc)
  367. {
  368. struct usb_role_switch_desc dwc3_role_switch = { NULL };
  369. dwc3_role_switch.fwnode = dev_fwnode(appledwc->dev);
  370. dwc3_role_switch.set = dwc3_usb_role_switch_set;
  371. dwc3_role_switch.get = dwc3_usb_role_switch_get;
  372. dwc3_role_switch.driver_data = appledwc;
  373. appledwc->role_sw = usb_role_switch_register(appledwc->dev, &dwc3_role_switch);
  374. if (IS_ERR(appledwc->role_sw))
  375. return PTR_ERR(appledwc->role_sw);
  376. return 0;
  377. }
  378. static int dwc3_apple_probe(struct platform_device *pdev)
  379. {
  380. struct device *dev = &pdev->dev;
  381. struct dwc3_apple *appledwc;
  382. int ret;
  383. appledwc = devm_kzalloc(&pdev->dev, sizeof(*appledwc), GFP_KERNEL);
  384. if (!appledwc)
  385. return -ENOMEM;
  386. appledwc->dev = &pdev->dev;
  387. mutex_init(&appledwc->lock);
  388. appledwc->reset = devm_reset_control_get_exclusive(dev, NULL);
  389. if (IS_ERR(appledwc->reset))
  390. return dev_err_probe(&pdev->dev, PTR_ERR(appledwc->reset),
  391. "Failed to get reset control\n");
  392. ret = reset_control_assert(appledwc->reset);
  393. if (ret) {
  394. dev_err(&pdev->dev, "Failed to assert reset, err=%d\n", ret);
  395. return ret;
  396. }
  397. appledwc->mmio_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dwc3-core");
  398. if (!appledwc->mmio_resource) {
  399. dev_err(dev, "Failed to get DWC3 MMIO\n");
  400. return -EINVAL;
  401. }
  402. appledwc->apple_regs = devm_platform_ioremap_resource_byname(pdev, "dwc3-apple");
  403. if (IS_ERR(appledwc->apple_regs))
  404. return dev_err_probe(dev, PTR_ERR(appledwc->apple_regs),
  405. "Failed to map Apple-specific MMIO\n");
  406. /*
  407. * On this platform, DWC3 can only be brought up after parts of the PHY have been
  408. * initialized with knowledge of the target mode and cable orientation from typec_set_mux.
  409. * Since this has not happened here we cannot setup DWC3 yet and instead defer this until
  410. * the first cable is connected. See the documentation for enum dwc3_apple_state for
  411. * details.
  412. */
  413. appledwc->state = DWC3_APPLE_PROBE_PENDING;
  414. ret = dwc3_apple_setup_role_switch(appledwc);
  415. if (ret)
  416. return dev_err_probe(&pdev->dev, ret, "Failed to setup role switch\n");
  417. return 0;
  418. }
  419. static void dwc3_apple_remove(struct platform_device *pdev)
  420. {
  421. struct dwc3 *dwc = platform_get_drvdata(pdev);
  422. struct dwc3_apple *appledwc = to_dwc3_apple(dwc);
  423. guard(mutex)(&appledwc->lock);
  424. usb_role_switch_unregister(appledwc->role_sw);
  425. /*
  426. * If we're still in DWC3_APPLE_PROBE_PENDING we never got any cable connected event and
  427. * dwc3_core_probe was never called and there's hence no need to call dwc3_core_remove.
  428. * dwc3_apple_exit can be called unconditionally because it checks the state itself.
  429. */
  430. dwc3_apple_exit(appledwc);
  431. if (appledwc->state != DWC3_APPLE_PROBE_PENDING)
  432. dwc3_core_remove(&appledwc->dwc);
  433. }
  434. static const struct of_device_id dwc3_apple_of_match[] = {
  435. { .compatible = "apple,t8103-dwc3" },
  436. {}
  437. };
  438. MODULE_DEVICE_TABLE(of, dwc3_apple_of_match);
  439. static struct platform_driver dwc3_apple_driver = {
  440. .probe = dwc3_apple_probe,
  441. .remove = dwc3_apple_remove,
  442. .driver = {
  443. .name = "dwc3-apple",
  444. .of_match_table = dwc3_apple_of_match,
  445. },
  446. };
  447. module_platform_driver(dwc3_apple_driver);
  448. MODULE_LICENSE("GPL");
  449. MODULE_AUTHOR("Sven Peter <sven@kernel.org>");
  450. MODULE_DESCRIPTION("DesignWare DWC3 Apple Silicon Glue Driver");