diff options
Diffstat (limited to 'target/linux/gemini/patches-6.1/0009-fotg210-udc-Support-optional-external-PHY.patch')
-rw-r--r-- | target/linux/gemini/patches-6.1/0009-fotg210-udc-Support-optional-external-PHY.patch | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/target/linux/gemini/patches-6.1/0009-fotg210-udc-Support-optional-external-PHY.patch b/target/linux/gemini/patches-6.1/0009-fotg210-udc-Support-optional-external-PHY.patch new file mode 100644 index 0000000000..498875c535 --- /dev/null +++ b/target/linux/gemini/patches-6.1/0009-fotg210-udc-Support-optional-external-PHY.patch @@ -0,0 +1,158 @@ +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; + |