gemini: Add kernel v6.1 patches
[openwrt/staging/mans0n.git] / target / linux / gemini / patches-6.1 / 0009-fotg210-udc-Support-optional-external-PHY.patch
1 From 03e4b585ac947e2d422bedf03179bbfec3aca3cf Mon Sep 17 00:00:00 2001
2 From: Linus Walleij <linus.walleij@linaro.org>
3 Date: Mon, 14 Nov 2022 12:51:59 +0100
4 Subject: [PATCH 09/29] fotg210-udc: Support optional external PHY
5
6 This adds support for an optional external PHY to the FOTG210
7 UDC driver.
8
9 Tested with the GPIO VBUS PHY driver on the Gemini SoC.
10
11 Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
12 Link: https://lore.kernel.org/r/20221114115201.302887-2-linus.walleij@linaro.org
13 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
14 ---
15 --- a/drivers/usb/fotg210/fotg210-udc.c
16 +++ b/drivers/usb/fotg210/fotg210-udc.c
17 @@ -15,6 +15,8 @@
18 #include <linux/platform_device.h>
19 #include <linux/usb/ch9.h>
20 #include <linux/usb/gadget.h>
21 +#include <linux/usb/otg.h>
22 +#include <linux/usb/phy.h>
23
24 #include "fotg210.h"
25 #include "fotg210-udc.h"
26 @@ -1022,10 +1024,18 @@ static int fotg210_udc_start(struct usb_
27 {
28 struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
29 u32 value;
30 + int ret;
31
32 /* hook up the driver */
33 fotg210->driver = driver;
34
35 + if (!IS_ERR_OR_NULL(fotg210->phy)) {
36 + ret = otg_set_peripheral(fotg210->phy->otg,
37 + &fotg210->gadget);
38 + if (ret)
39 + dev_err(fotg210->dev, "can't bind to phy\n");
40 + }
41 +
42 /* enable device global interrupt */
43 value = ioread32(fotg210->reg + FOTG210_DMCR);
44 value |= DMCR_GLINT_EN;
45 @@ -1067,6 +1077,9 @@ static int fotg210_udc_stop(struct usb_g
46 struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
47 unsigned long flags;
48
49 + if (!IS_ERR_OR_NULL(fotg210->phy))
50 + return otg_set_peripheral(fotg210->phy->otg, NULL);
51 +
52 spin_lock_irqsave(&fotg210->lock, flags);
53
54 fotg210_init(fotg210);
55 @@ -1082,12 +1095,50 @@ static const struct usb_gadget_ops fotg2
56 .udc_stop = fotg210_udc_stop,
57 };
58
59 +/**
60 + * fotg210_phy_event - Called by phy upon VBus event
61 + * @nb: notifier block
62 + * @action: phy action, is vbus connect or disconnect
63 + * @data: the usb_gadget structure in fotg210
64 + *
65 + * Called by the USB Phy when a cable connect or disconnect is sensed.
66 + *
67 + * Returns NOTIFY_OK or NOTIFY_DONE
68 + */
69 +static int fotg210_phy_event(struct notifier_block *nb, unsigned long action,
70 + void *data)
71 +{
72 + struct usb_gadget *gadget = data;
73 +
74 + if (!gadget)
75 + return NOTIFY_DONE;
76 +
77 + switch (action) {
78 + case USB_EVENT_VBUS:
79 + usb_gadget_vbus_connect(gadget);
80 + return NOTIFY_OK;
81 + case USB_EVENT_NONE:
82 + usb_gadget_vbus_disconnect(gadget);
83 + return NOTIFY_OK;
84 + default:
85 + return NOTIFY_DONE;
86 + }
87 +}
88 +
89 +static struct notifier_block fotg210_phy_notifier = {
90 + .notifier_call = fotg210_phy_event,
91 +};
92 +
93 int fotg210_udc_remove(struct platform_device *pdev)
94 {
95 struct fotg210_udc *fotg210 = platform_get_drvdata(pdev);
96 int i;
97
98 usb_del_gadget_udc(&fotg210->gadget);
99 + if (!IS_ERR_OR_NULL(fotg210->phy)) {
100 + usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier);
101 + usb_put_phy(fotg210->phy);
102 + }
103 iounmap(fotg210->reg);
104 free_irq(platform_get_irq(pdev, 0), fotg210);
105
106 @@ -1127,6 +1178,22 @@ int fotg210_udc_probe(struct platform_de
107 if (fotg210 == NULL)
108 goto err;
109
110 + fotg210->dev = dev;
111 +
112 + fotg210->phy = devm_usb_get_phy_by_phandle(dev->parent, "usb-phy", 0);
113 + if (IS_ERR(fotg210->phy)) {
114 + ret = PTR_ERR(fotg210->phy);
115 + if (ret == -EPROBE_DEFER)
116 + goto err;
117 + dev_info(dev, "no PHY found\n");
118 + fotg210->phy = NULL;
119 + } else {
120 + ret = usb_phy_init(fotg210->phy);
121 + if (ret)
122 + goto err;
123 + dev_info(dev, "found and initialized PHY\n");
124 + }
125 +
126 for (i = 0; i < FOTG210_MAX_NUM_EP; i++) {
127 _ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL);
128 if (_ep[i] == NULL)
129 @@ -1200,6 +1267,9 @@ int fotg210_udc_probe(struct platform_de
130 goto err_req;
131 }
132
133 + if (!IS_ERR_OR_NULL(fotg210->phy))
134 + usb_register_notifier(fotg210->phy, &fotg210_phy_notifier);
135 +
136 ret = usb_add_gadget_udc(dev, &fotg210->gadget);
137 if (ret)
138 goto err_add_udc;
139 @@ -1209,6 +1279,8 @@ int fotg210_udc_probe(struct platform_de
140 return 0;
141
142 err_add_udc:
143 + if (!IS_ERR_OR_NULL(fotg210->phy))
144 + usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier);
145 free_irq(ires->start, fotg210);
146
147 err_req:
148 --- a/drivers/usb/fotg210/fotg210-udc.h
149 +++ b/drivers/usb/fotg210/fotg210-udc.h
150 @@ -234,6 +234,8 @@ struct fotg210_udc {
151
152 unsigned long irq_trigger;
153
154 + struct device *dev;
155 + struct usb_phy *phy;
156 struct usb_gadget gadget;
157 struct usb_gadget_driver *driver;
158