--- /dev/null
+From 0dbc77a99267a5efef0603a4b49ac02ece6a3f23 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Sun, 23 Oct 2022 16:47:07 +0200
+Subject: [PATCH 03/29] usb: fotg210: Compile into one module
+
+It is since ages perfectly possible to compile both of these
+modules into the same kernel, which makes no sense since it
+is one piece of hardware.
+
+Compile one module named "fotg210.ko" for both HCD and UDC
+drivers by collecting the init calls into a fotg210-core.c
+file and start to centralize things handling one and the same
+piece of hardware.
+
+Stub out the initcalls if one or the other part of the driver
+was not selected.
+
+Tested by compiling one or the other or both of the drivers
+into the kernel and as modules.
+
+Cc: Fabian Vogt <fabian@ritter-vogt.de>
+Cc: Yuan-Hsin Chen <yhchen@faraday-tech.com>
+Cc: Felipe Balbi <balbi@kernel.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Link: https://lore.kernel.org/r/20221023144708.3596563-2-linus.walleij@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+--- a/drivers/usb/fotg210/Kconfig
++++ b/drivers/usb/fotg210/Kconfig
+@@ -12,7 +12,7 @@ config USB_FOTG210
+ if USB_FOTG210
+
+ config USB_FOTG210_HCD
+- tristate "Faraday FOTG210 USB Host Controller support"
++ bool "Faraday FOTG210 USB Host Controller support"
+ depends on USB
+ help
+ Faraday FOTG210 is an OTG controller which can be configured as
+@@ -24,7 +24,7 @@ config USB_FOTG210_HCD
+
+ config USB_FOTG210_UDC
+ depends on USB_GADGET
+- tristate "Faraday FOTG210 USB Peripheral Controller support"
++ bool "Faraday FOTG210 USB Peripheral Controller support"
+ help
+ Faraday USB2.0 OTG controller which can be configured as
+ high speed or full speed USB device. This driver suppports
+--- a/drivers/usb/fotg210/Makefile
++++ b/drivers/usb/fotg210/Makefile
+@@ -1,3 +1,10 @@
+ # SPDX-License-Identifier: GPL-2.0
+-obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
+-obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
++
++# This setup links the different object files into one single
++# module so we don't have to EXPORT() a lot of internal symbols
++# or create unnecessary submodules.
++fotg210-objs-y += fotg210-core.o
++fotg210-objs-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
++fotg210-objs-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
++fotg210-objs := $(fotg210-objs-y)
++obj-$(CONFIG_USB_FOTG210) += fotg210.o
+--- /dev/null
++++ b/drivers/usb/fotg210/fotg210-core.c
+@@ -0,0 +1,79 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Central probing code for the FOTG210 dual role driver
++ * We register one driver for the hardware and then we decide
++ * whether to proceed with probing the host or the peripheral
++ * driver.
++ */
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/usb.h>
++
++#include "fotg210.h"
++
++static int fotg210_probe(struct platform_device *pdev)
++{
++ int ret;
++
++ if (IS_ENABLED(CONFIG_USB_FOTG210_HCD)) {
++ ret = fotg210_hcd_probe(pdev);
++ if (ret)
++ return ret;
++ }
++ if (IS_ENABLED(CONFIG_USB_FOTG210_UDC))
++ ret = fotg210_udc_probe(pdev);
++
++ return ret;
++}
++
++static int fotg210_remove(struct platform_device *pdev)
++{
++ if (IS_ENABLED(CONFIG_USB_FOTG210_HCD))
++ fotg210_hcd_remove(pdev);
++ if (IS_ENABLED(CONFIG_USB_FOTG210_UDC))
++ fotg210_udc_remove(pdev);
++
++ return 0;
++}
++
++#ifdef CONFIG_OF
++static const struct of_device_id fotg210_of_match[] = {
++ { .compatible = "faraday,fotg210" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, fotg210_of_match);
++#endif
++
++static struct platform_driver fotg210_driver = {
++ .driver = {
++ .name = "fotg210",
++ .of_match_table = of_match_ptr(fotg210_of_match),
++ },
++ .probe = fotg210_probe,
++ .remove = fotg210_remove,
++};
++
++static int __init fotg210_init(void)
++{
++ if (usb_disabled())
++ return -ENODEV;
++
++ if (IS_ENABLED(CONFIG_USB_FOTG210_HCD))
++ fotg210_hcd_init();
++ return platform_driver_register(&fotg210_driver);
++}
++module_init(fotg210_init);
++
++static void __exit fotg210_cleanup(void)
++{
++ platform_driver_unregister(&fotg210_driver);
++ if (IS_ENABLED(CONFIG_USB_FOTG210_HCD))
++ fotg210_hcd_cleanup();
++}
++module_exit(fotg210_cleanup);
++
++MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("FOTG210 Dual Role Controller Driver");
+--- a/drivers/usb/fotg210/fotg210-hcd.c
++++ b/drivers/usb/fotg210/fotg210-hcd.c
+@@ -39,8 +39,8 @@
+ #include <asm/irq.h>
+ #include <asm/unaligned.h>
+
+-#define DRIVER_AUTHOR "Yuan-Hsin Chen"
+-#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver"
++#include "fotg210.h"
++
+ static const char hcd_name[] = "fotg210_hcd";
+
+ #undef FOTG210_URB_TRACE
+@@ -5490,9 +5490,6 @@ static int fotg210_get_frame(struct usb_
+ * functions and in order to facilitate role switching we cannot
+ * give the fotg210 driver exclusive access to those.
+ */
+-MODULE_DESCRIPTION(DRIVER_DESC);
+-MODULE_AUTHOR(DRIVER_AUTHOR);
+-MODULE_LICENSE("GPL");
+
+ static const struct hc_driver fotg210_fotg210_hc_driver = {
+ .description = hcd_name,
+@@ -5560,7 +5557,7 @@ static void fotg210_init(struct fotg210_
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+-static int fotg210_hcd_probe(struct platform_device *pdev)
++int fotg210_hcd_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+ struct usb_hcd *hcd;
+@@ -5652,7 +5649,7 @@ fail_create_hcd:
+ * @dev: USB Host Controller being removed
+ *
+ */
+-static int fotg210_hcd_remove(struct platform_device *pdev)
++int fotg210_hcd_remove(struct platform_device *pdev)
+ {
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+@@ -5668,27 +5665,8 @@ static int fotg210_hcd_remove(struct pla
+ return 0;
+ }
+
+-#ifdef CONFIG_OF
+-static const struct of_device_id fotg210_of_match[] = {
+- { .compatible = "faraday,fotg210" },
+- {},
+-};
+-MODULE_DEVICE_TABLE(of, fotg210_of_match);
+-#endif
+-
+-static struct platform_driver fotg210_hcd_driver = {
+- .driver = {
+- .name = "fotg210-hcd",
+- .of_match_table = of_match_ptr(fotg210_of_match),
+- },
+- .probe = fotg210_hcd_probe,
+- .remove = fotg210_hcd_remove,
+-};
+-
+-static int __init fotg210_hcd_init(void)
++int __init fotg210_hcd_init(void)
+ {
+- int retval = 0;
+-
+ if (usb_disabled())
+ return -ENODEV;
+
+@@ -5704,24 +5682,11 @@ static int __init fotg210_hcd_init(void)
+
+ fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);
+
+- retval = platform_driver_register(&fotg210_hcd_driver);
+- if (retval < 0)
+- goto clean;
+- return retval;
+-
+-clean:
+- debugfs_remove(fotg210_debug_root);
+- fotg210_debug_root = NULL;
+-
+- clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+- return retval;
++ return 0;
+ }
+-module_init(fotg210_hcd_init);
+
+-static void __exit fotg210_hcd_cleanup(void)
++void __exit fotg210_hcd_cleanup(void)
+ {
+- platform_driver_unregister(&fotg210_hcd_driver);
+ debugfs_remove(fotg210_debug_root);
+ clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+ }
+-module_exit(fotg210_hcd_cleanup);
+--- a/drivers/usb/fotg210/fotg210-udc.c
++++ b/drivers/usb/fotg210/fotg210-udc.c
+@@ -16,6 +16,7 @@
+ #include <linux/usb/ch9.h>
+ #include <linux/usb/gadget.h>
+
++#include "fotg210.h"
+ #include "fotg210-udc.h"
+
+ #define DRIVER_DESC "FOTG210 USB Device Controller Driver"
+@@ -1081,7 +1082,7 @@ static const struct usb_gadget_ops fotg2
+ .udc_stop = fotg210_udc_stop,
+ };
+
+-static int fotg210_udc_remove(struct platform_device *pdev)
++int fotg210_udc_remove(struct platform_device *pdev)
+ {
+ struct fotg210_udc *fotg210 = platform_get_drvdata(pdev);
+ int i;
+@@ -1098,7 +1099,7 @@ static int fotg210_udc_remove(struct pla
+ return 0;
+ }
+
+-static int fotg210_udc_probe(struct platform_device *pdev)
++int fotg210_udc_probe(struct platform_device *pdev)
+ {
+ struct resource *res, *ires;
+ struct fotg210_udc *fotg210 = NULL;
+@@ -1223,17 +1224,3 @@ err_alloc:
+ err:
+ return ret;
+ }
+-
+-static struct platform_driver fotg210_driver = {
+- .driver = {
+- .name = udc_name,
+- },
+- .probe = fotg210_udc_probe,
+- .remove = fotg210_udc_remove,
+-};
+-
+-module_platform_driver(fotg210_driver);
+-
+-MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");
+-MODULE_LICENSE("GPL");
+-MODULE_DESCRIPTION(DRIVER_DESC);
+--- /dev/null
++++ b/drivers/usb/fotg210/fotg210.h
+@@ -0,0 +1,42 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __FOTG210_H
++#define __FOTG210_H
++
++#ifdef CONFIG_USB_FOTG210_HCD
++int fotg210_hcd_probe(struct platform_device *pdev);
++int fotg210_hcd_remove(struct platform_device *pdev);
++int fotg210_hcd_init(void);
++void fotg210_hcd_cleanup(void);
++#else
++static inline int fotg210_hcd_probe(struct platform_device *pdev)
++{
++ return 0;
++}
++static inline int fotg210_hcd_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++static inline int fotg210_hcd_init(void)
++{
++ return 0;
++}
++static inline void fotg210_hcd_cleanup(void)
++{
++}
++#endif
++
++#ifdef CONFIG_USB_FOTG210_UDC
++int fotg210_udc_probe(struct platform_device *pdev);
++int fotg210_udc_remove(struct platform_device *pdev);
++#else
++static inline int fotg210_udc_probe(struct platform_device *pdev)
++{
++ return 0;
++}
++static inline int fotg210_udc_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++#endif
++
++#endif /* __FOTG210_H */