[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1669860811-171746-3-git-send-email-dh10.jung@samsung.com>
Date: Thu, 1 Dec 2022 11:13:31 +0900
From: Daehwan Jung <dh10.jung@...sung.com>
To: Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Rob Herring <robh+dt@...nel.org>,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@...aro.org>,
Alim Akhtar <alim.akhtar@...sung.com>,
Mathias Nyman <mathias.nyman@...el.com>,
Arnd Bergmann <arnd@...db.de>,
Linus Walleij <linus.walleij@...aro.org>,
Colin Ian King <colin.i.king@...il.com>,
Daehwan Jung <dh10.jung@...sung.com>,
Artur Bujdoso <artur.bujdoso@...il.com>,
Juergen Gross <jgross@...e.com>,
Tomer Maimon <tmaimon77@...il.com>
Cc: linux-usb@...r.kernel.org (open list:USB SUBSYSTEM),
devicetree@...r.kernel.org (open list:OPEN FIRMWARE AND FLATTENED
DEVICE TREE BINDINGS),
linux-arm-kernel@...ts.infradead.org (moderated list:ARM/SAMSUNG S3C,
S5P AND EXYNOS ARM ARCHITECTURES),
linux-samsung-soc@...r.kernel.org (open list:ARM/SAMSUNG S3C, S5P AND
EXYNOS ARM ARCHITECTURES),
linux-kernel@...r.kernel.org (open list), sc.suh@...sung.com,
taehyun.cho@...sung.com, jh0801.jung@...sung.com,
eomji.oh@...sung.com
Subject: [RFC PATCH v1 2/2] usb: host: add xhci-exynos to support Exynos
SOCs
This driver works with xhci platform driver. It needs to override
functions of xhci_plat_hc_driver. Wakelocks are used for sleep/wakeup
scenario of system.
Signed-off-by: Daehwan Jung <dh10.jung@...sung.com>
---
drivers/usb/host/Kconfig | 8 ++
drivers/usb/host/Makefile | 1 +
drivers/usb/host/xhci-exynos.c | 154 +++++++++++++++++++++++++++++++++
drivers/usb/host/xhci-hub.c | 2 +
drivers/usb/host/xhci-plat.c | 6 ++
drivers/usb/host/xhci-plat.h | 2 +
drivers/usb/host/xhci.c | 4 +
drivers/usb/host/xhci.h | 2 +
8 files changed, 179 insertions(+)
create mode 100644 drivers/usb/host/xhci-exynos.c
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 8d799d23c476..007c7706ddeb 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -104,6 +104,14 @@ config USB_XHCI_TEGRA
Say 'Y' to enable the support for the xHCI host controller
found in NVIDIA Tegra124 and later SoCs.
+config USB_XHCI_EXYNOS
+ tristate "xHCI support for Samsung Exynos SoC Series"
+ depends on USB_XHCI_PLATFORM
+ depends on ARCH_EXYNOS || COMPILE_TEST
+ help
+ Say 'Y' to enable the support for the xHCI host controller
+ found in Samsung Exynos SoCs.
+
endif # USB_XHCI_HCD
config USB_EHCI_BRCMSTB
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 6d8ee264c9b2..c682834f4260 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -86,3 +86,4 @@ obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
obj-$(CONFIG_USB_MAX3421_HCD) += max3421-hcd.o
obj-$(CONFIG_USB_XEN_HCD) += xen-hcd.o
+obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos.o
diff --git a/drivers/usb/host/xhci-exynos.c b/drivers/usb/host/xhci-exynos.c
new file mode 100644
index 000000000000..5e2323aee996
--- /dev/null
+++ b/drivers/usb/host/xhci-exynos.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xhci-exynos.c - xHCI host controller driver platform Bus Glue for Exynos.
+ *
+ * Copyright (C) 2022 Samsung Electronics Incorporated - http://www.samsung.com
+ * Author: Daehwan Jung <dh10.jung@...sung.com>
+ *
+ */
+#include <linux/platform_device.h>
+
+#include "xhci.h"
+#include "xhci-plat.h"
+
+struct xhci_hcd_exynos {
+ struct wakeup_source *main_wakelock; /* Wakelock for HS HCD */
+ struct wakeup_source *shared_wakelock; /* Wakelock for SS HCD */
+};
+
+static struct xhci_hcd_exynos xhci_exynos_data;
+
+static int xhci_exynos_start(struct usb_hcd *hcd);
+static int xhci_exynos_setup(struct usb_hcd *hcd);
+static int xhci_exynos_bus_suspend(struct usb_hcd *hcd);
+static int xhci_exynos_bus_resume(struct usb_hcd *hcd);
+
+static const struct xhci_driver_overrides xhci_exynos_overrides = {
+ .extra_priv_size = sizeof(struct xhci_plat_priv),
+ .reset = xhci_exynos_setup,
+ .start = xhci_exynos_start,
+ .bus_suspend = xhci_exynos_bus_suspend,
+ .bus_resume = xhci_exynos_bus_resume,
+};
+
+static void xhci_exynos_quirks(struct device *dev, struct xhci_hcd *xhci)
+{
+ xhci->quirks |= XHCI_PLAT;
+}
+
+static int xhci_exynos_setup(struct usb_hcd *hcd)
+{
+ return xhci_gen_setup(hcd, xhci_exynos_quirks);
+}
+
+static int xhci_exynos_start(struct usb_hcd *hcd)
+{
+ __pm_stay_awake(xhci_exynos_data.main_wakelock);
+ __pm_stay_awake(xhci_exynos_data.shared_wakelock);
+
+ return xhci_run(hcd);
+}
+
+static void xhci_exynos_wake_lock(struct xhci_hcd *xhci, int is_main_hcd, int is_lock)
+{
+ struct wakeup_source *main_wakelock, *shared_wakelock;
+
+ main_wakelock = xhci_exynos_data.main_wakelock;
+ shared_wakelock = xhci_exynos_data.shared_wakelock;
+
+ if (xhci->xhc_state & XHCI_STATE_REMOVING)
+ return;
+
+ if (is_lock) {
+ if (is_main_hcd)
+ __pm_stay_awake(main_wakelock);
+ else
+ __pm_stay_awake(shared_wakelock);
+ } else {
+ if (is_main_hcd)
+ __pm_relax(main_wakelock);
+ else
+ __pm_relax(shared_wakelock);
+ }
+}
+
+static int xhci_exynos_bus_suspend(struct usb_hcd *hcd)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ int ret, main_hcd;
+
+ ret = xhci_bus_suspend(hcd);
+
+ if (!ret) {
+ main_hcd = (hcd == xhci->main_hcd) ? 1 : 0;
+ xhci_exynos_wake_lock(xhci, main_hcd, 0);
+ }
+
+ return ret;
+}
+
+static int xhci_exynos_bus_resume(struct usb_hcd *hcd)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ int ret, main_hcd;
+
+ ret = xhci_bus_resume(hcd);
+
+ if (!ret) {
+ main_hcd = (hcd == xhci->main_hcd) ? 1 : 0;
+ xhci_exynos_wake_lock(xhci, main_hcd, 1);
+ }
+
+ return ret;
+}
+
+static int xhci_exynos_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ xhci_exynos_data.main_wakelock = wakeup_source_register(dev, dev_name(dev));
+ xhci_exynos_data.shared_wakelock = wakeup_source_register(dev, dev_name(dev));
+
+ xhci_plat_override_driver(&xhci_exynos_overrides);
+
+ return 0;
+}
+
+static int xhci_exynos_remove(struct platform_device *dev)
+{
+ wakeup_source_unregister(xhci_exynos_data.main_wakelock);
+ wakeup_source_unregister(xhci_exynos_data.shared_wakelock);
+
+ return 0;
+}
+
+static const struct of_device_id exynos_xhci_of_match[] = {
+ { .compatible = "samsung,exynos-xhci"},
+ { },
+};
+MODULE_DEVICE_TABLE(of, exynos_xhci_of_match);
+
+static struct platform_driver exynos_xhci_driver = {
+ .probe = xhci_exynos_probe,
+ .remove = xhci_exynos_remove,
+ .driver = {
+ .name = "xhci-exynos",
+ .of_match_table = exynos_xhci_of_match,
+ },
+};
+
+static int __init xhci_exynos_init(void)
+{
+ return platform_driver_register(&exynos_xhci_driver);
+}
+module_init(xhci_exynos_init);
+
+static void __exit xhci_exynos_exit(void)
+{
+ platform_driver_unregister(&exynos_xhci_driver);
+}
+module_exit(xhci_exynos_exit);
+
+MODULE_AUTHOR("Daehwan Jung <dh10.jung@...sung.com>");
+MODULE_DESCRIPTION("xHCI Exynos Host Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 4619d5e89d5b..878c2c05055a 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1824,6 +1824,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
return 0;
}
+EXPORT_SYMBOL_GPL(xhci_bus_suspend);
/*
* Workaround for missing Cold Attach Status (CAS) if device re-plugged in S3.
@@ -1968,6 +1969,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
spin_unlock_irqrestore(&xhci->lock, flags);
return 0;
}
+EXPORT_SYMBOL_GPL(xhci_bus_resume);
unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd)
{
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 5fb55bf19493..1cb24f8e0153 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -173,6 +173,12 @@ static const struct of_device_id usb_xhci_of_match[] = {
MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
#endif
+void xhci_plat_override_driver(const struct xhci_driver_overrides *xhci_hc_driver_overrides)
+{
+ xhci_init_driver(&xhci_plat_hc_driver, xhci_hc_driver_overrides);
+}
+EXPORT_SYMBOL_GPL(xhci_plat_override_driver);
+
static int xhci_plat_probe(struct platform_device *pdev)
{
const struct xhci_plat_priv *priv_match;
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
index 1fb149d1fbce..16436f72c5c4 100644
--- a/drivers/usb/host/xhci-plat.h
+++ b/drivers/usb/host/xhci-plat.h
@@ -21,4 +21,6 @@ struct xhci_plat_priv {
#define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
#define xhci_to_priv(x) ((struct xhci_plat_priv *)(x)->priv)
+
+void xhci_plat_override_driver(const struct xhci_driver_overrides *xhci_hc_driver_overrides);
#endif /* _XHCI_PLAT_H */
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 79d7931c048a..693495054001 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -5502,6 +5502,10 @@ void xhci_init_driver(struct hc_driver *drv,
drv->check_bandwidth = over->check_bandwidth;
if (over->reset_bandwidth)
drv->reset_bandwidth = over->reset_bandwidth;
+ if (over->bus_suspend)
+ drv->bus_suspend = over->bus_suspend;
+ if (over->bus_resume)
+ drv->bus_resume = over->bus_resume;
}
}
EXPORT_SYMBOL_GPL(xhci_init_driver);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index cc084d9505cd..30e60c752c28 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1943,6 +1943,8 @@ struct xhci_driver_overrides {
struct usb_host_endpoint *ep);
int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
+ int (*bus_suspend)(struct usb_hcd *hcd);
+ int (*bus_resume)(struct usb_hcd *hcd);
};
#define XHCI_CFC_DELAY 10
--
2.31.1
Powered by blists - more mailing lists