mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 01:11:14 +00:00
58acb1dd2c
This adds a bunch of patches for the v6.1 Gemini kernel. For v5.15 this was down to a single upstream patch, but for kernel v6.2 I reworked the USB code for FOTG210, so instead of carrying over the half-baked and incomplete patch from v5.15 I just backported all the v6.2 patches, 31 in total, as it creates full device USB mode for e.g. D-Link DNS-313. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
159 lines
4.3 KiB
Diff
159 lines
4.3 KiB
Diff
From 03e4b585ac947e2d422bedf03179bbfec3aca3cf Mon Sep 17 00:00:00 2001
|
|
From: Linus Walleij <linus.walleij@linaro.org>
|
|
Date: Mon, 14 Nov 2022 12:51:59 +0100
|
|
Subject: [PATCH 09/29] fotg210-udc: Support optional external PHY
|
|
|
|
This adds support for an optional external PHY to the FOTG210
|
|
UDC driver.
|
|
|
|
Tested with the GPIO VBUS PHY driver on the Gemini SoC.
|
|
|
|
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
|
|
Link: https://lore.kernel.org/r/20221114115201.302887-2-linus.walleij@linaro.org
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
---
|
|
--- a/drivers/usb/fotg210/fotg210-udc.c
|
|
+++ b/drivers/usb/fotg210/fotg210-udc.c
|
|
@@ -15,6 +15,8 @@
|
|
#include <linux/platform_device.h>
|
|
#include <linux/usb/ch9.h>
|
|
#include <linux/usb/gadget.h>
|
|
+#include <linux/usb/otg.h>
|
|
+#include <linux/usb/phy.h>
|
|
|
|
#include "fotg210.h"
|
|
#include "fotg210-udc.h"
|
|
@@ -1022,10 +1024,18 @@ static int fotg210_udc_start(struct usb_
|
|
{
|
|
struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
|
|
u32 value;
|
|
+ int ret;
|
|
|
|
/* hook up the driver */
|
|
fotg210->driver = driver;
|
|
|
|
+ if (!IS_ERR_OR_NULL(fotg210->phy)) {
|
|
+ ret = otg_set_peripheral(fotg210->phy->otg,
|
|
+ &fotg210->gadget);
|
|
+ if (ret)
|
|
+ dev_err(fotg210->dev, "can't bind to phy\n");
|
|
+ }
|
|
+
|
|
/* enable device global interrupt */
|
|
value = ioread32(fotg210->reg + FOTG210_DMCR);
|
|
value |= DMCR_GLINT_EN;
|
|
@@ -1067,6 +1077,9 @@ static int fotg210_udc_stop(struct usb_g
|
|
struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
|
|
unsigned long flags;
|
|
|
|
+ if (!IS_ERR_OR_NULL(fotg210->phy))
|
|
+ return otg_set_peripheral(fotg210->phy->otg, NULL);
|
|
+
|
|
spin_lock_irqsave(&fotg210->lock, flags);
|
|
|
|
fotg210_init(fotg210);
|
|
@@ -1082,12 +1095,50 @@ static const struct usb_gadget_ops fotg2
|
|
.udc_stop = fotg210_udc_stop,
|
|
};
|
|
|
|
+/**
|
|
+ * fotg210_phy_event - Called by phy upon VBus event
|
|
+ * @nb: notifier block
|
|
+ * @action: phy action, is vbus connect or disconnect
|
|
+ * @data: the usb_gadget structure in fotg210
|
|
+ *
|
|
+ * Called by the USB Phy when a cable connect or disconnect is sensed.
|
|
+ *
|
|
+ * Returns NOTIFY_OK or NOTIFY_DONE
|
|
+ */
|
|
+static int fotg210_phy_event(struct notifier_block *nb, unsigned long action,
|
|
+ void *data)
|
|
+{
|
|
+ struct usb_gadget *gadget = data;
|
|
+
|
|
+ if (!gadget)
|
|
+ return NOTIFY_DONE;
|
|
+
|
|
+ switch (action) {
|
|
+ case USB_EVENT_VBUS:
|
|
+ usb_gadget_vbus_connect(gadget);
|
|
+ return NOTIFY_OK;
|
|
+ case USB_EVENT_NONE:
|
|
+ usb_gadget_vbus_disconnect(gadget);
|
|
+ return NOTIFY_OK;
|
|
+ default:
|
|
+ return NOTIFY_DONE;
|
|
+ }
|
|
+}
|
|
+
|
|
+static struct notifier_block fotg210_phy_notifier = {
|
|
+ .notifier_call = fotg210_phy_event,
|
|
+};
|
|
+
|
|
int fotg210_udc_remove(struct platform_device *pdev)
|
|
{
|
|
struct fotg210_udc *fotg210 = platform_get_drvdata(pdev);
|
|
int i;
|
|
|
|
usb_del_gadget_udc(&fotg210->gadget);
|
|
+ if (!IS_ERR_OR_NULL(fotg210->phy)) {
|
|
+ usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier);
|
|
+ usb_put_phy(fotg210->phy);
|
|
+ }
|
|
iounmap(fotg210->reg);
|
|
free_irq(platform_get_irq(pdev, 0), fotg210);
|
|
|
|
@@ -1127,6 +1178,22 @@ int fotg210_udc_probe(struct platform_de
|
|
if (fotg210 == NULL)
|
|
goto err;
|
|
|
|
+ fotg210->dev = dev;
|
|
+
|
|
+ fotg210->phy = devm_usb_get_phy_by_phandle(dev->parent, "usb-phy", 0);
|
|
+ if (IS_ERR(fotg210->phy)) {
|
|
+ ret = PTR_ERR(fotg210->phy);
|
|
+ if (ret == -EPROBE_DEFER)
|
|
+ goto err;
|
|
+ dev_info(dev, "no PHY found\n");
|
|
+ fotg210->phy = NULL;
|
|
+ } else {
|
|
+ ret = usb_phy_init(fotg210->phy);
|
|
+ if (ret)
|
|
+ goto err;
|
|
+ dev_info(dev, "found and initialized PHY\n");
|
|
+ }
|
|
+
|
|
for (i = 0; i < FOTG210_MAX_NUM_EP; i++) {
|
|
_ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL);
|
|
if (_ep[i] == NULL)
|
|
@@ -1200,6 +1267,9 @@ int fotg210_udc_probe(struct platform_de
|
|
goto err_req;
|
|
}
|
|
|
|
+ if (!IS_ERR_OR_NULL(fotg210->phy))
|
|
+ usb_register_notifier(fotg210->phy, &fotg210_phy_notifier);
|
|
+
|
|
ret = usb_add_gadget_udc(dev, &fotg210->gadget);
|
|
if (ret)
|
|
goto err_add_udc;
|
|
@@ -1209,6 +1279,8 @@ int fotg210_udc_probe(struct platform_de
|
|
return 0;
|
|
|
|
err_add_udc:
|
|
+ if (!IS_ERR_OR_NULL(fotg210->phy))
|
|
+ usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier);
|
|
free_irq(ires->start, fotg210);
|
|
|
|
err_req:
|
|
--- a/drivers/usb/fotg210/fotg210-udc.h
|
|
+++ b/drivers/usb/fotg210/fotg210-udc.h
|
|
@@ -234,6 +234,8 @@ struct fotg210_udc {
|
|
|
|
unsigned long irq_trigger;
|
|
|
|
+ struct device *dev;
|
|
+ struct usb_phy *phy;
|
|
struct usb_gadget gadget;
|
|
struct usb_gadget_driver *driver;
|
|
|