usb: dwc3: qcom: Enable wakeup for applicable ports of multiport
authorKrishna Kurapati <quic_kriskura@quicinc.com>
Sat, 20 Apr 2024 04:49:00 +0000 (10:19 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 24 Apr 2024 02:56:09 +0000 (19:56 -0700)
DWC3 Qcom wrapper currently supports only wakeup configuration
for single port controllers. Read speed of each port connected
to the controller and enable wakeup for each of them accordingly.

Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
Reviewed-by: Johan Hovold <johan+linaro@kernel.org>
Reviewed-by: Bjorn Andersson <quic_bjorande@quicinc.com>
Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Tested-by: Johan Hovold <johan+linaro@kernel.org>
Link: https://lore.kernel.org/r/20240420044901.884098-9-quic_kriskura@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc3/dwc3-qcom.c

index 5ddb694dd8e72cb40a05c775f72aba1f23ab7d40..b6f13bb14e2cf79d1e96ab93a4b6a3bac755281e 100644 (file)
@@ -60,6 +60,7 @@ struct dwc3_qcom_port {
        int                     dp_hs_phy_irq;
        int                     dm_hs_phy_irq;
        int                     ss_phy_irq;
+       enum usb_device_speed   usb2_speed;
 };
 
 struct dwc3_qcom {
@@ -71,7 +72,6 @@ struct dwc3_qcom {
        struct reset_control    *resets;
        struct dwc3_qcom_port   ports[DWC3_QCOM_MAX_PORTS];
        u8                      num_ports;
-       enum usb_device_speed   usb2_speed;
 
        struct extcon_dev       *edev;
        struct extcon_dev       *host_edev;
@@ -310,7 +310,7 @@ static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
        return dwc->xhci;
 }
 
-static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom)
+static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom, int port_index)
 {
        struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
        struct usb_device *udev;
@@ -321,14 +321,8 @@ static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom)
         */
        hcd = platform_get_drvdata(dwc->xhci);
 
-       /*
-        * It is possible to query the speed of all children of
-        * USB2.0 root hub via usb_hub_for_each_child(). DWC3 code
-        * currently supports only 1 port per controller. So
-        * this is sufficient.
-        */
 #ifdef CONFIG_USB
-       udev = usb_hub_find_child(hcd->self.root_hub, 1);
+       udev = usb_hub_find_child(hcd->self.root_hub, port_index + 1);
 #else
        udev = NULL;
 #endif
@@ -359,26 +353,26 @@ static void dwc3_qcom_disable_wakeup_irq(int irq)
        disable_irq_nosync(irq);
 }
 
-static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
+static void dwc3_qcom_disable_port_interrupts(struct dwc3_qcom_port *port)
 {
-       dwc3_qcom_disable_wakeup_irq(qcom->ports[0].qusb2_phy_irq);
+       dwc3_qcom_disable_wakeup_irq(port->qusb2_phy_irq);
 
-       if (qcom->usb2_speed == USB_SPEED_LOW) {
-               dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq);
-       } else if ((qcom->usb2_speed == USB_SPEED_HIGH) ||
-                       (qcom->usb2_speed == USB_SPEED_FULL)) {
-               dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq);
+       if (port->usb2_speed == USB_SPEED_LOW) {
+               dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq);
+       } else if ((port->usb2_speed == USB_SPEED_HIGH) ||
+                       (port->usb2_speed == USB_SPEED_FULL)) {
+               dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq);
        } else {
-               dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq);
-               dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq);
+               dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq);
+               dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq);
        }
 
-       dwc3_qcom_disable_wakeup_irq(qcom->ports[0].ss_phy_irq);
+       dwc3_qcom_disable_wakeup_irq(port->ss_phy_irq);
 }
 
-static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
+static void dwc3_qcom_enable_port_interrupts(struct dwc3_qcom_port *port)
 {
-       dwc3_qcom_enable_wakeup_irq(qcom->ports[0].qusb2_phy_irq, 0);
+       dwc3_qcom_enable_wakeup_irq(port->qusb2_phy_irq, 0);
 
        /*
         * Configure DP/DM line interrupts based on the USB2 device attached to
@@ -389,21 +383,37 @@ static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
         * DP and DM lines as rising edge to detect HS/HS/LS device connect scenario.
         */
 
-       if (qcom->usb2_speed == USB_SPEED_LOW) {
-               dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq,
+       if (port->usb2_speed == USB_SPEED_LOW) {
+               dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq,
                                            IRQ_TYPE_EDGE_FALLING);
-       } else if ((qcom->usb2_speed == USB_SPEED_HIGH) ||
-                       (qcom->usb2_speed == USB_SPEED_FULL)) {
-               dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq,
+       } else if ((port->usb2_speed == USB_SPEED_HIGH) ||
+                       (port->usb2_speed == USB_SPEED_FULL)) {
+               dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq,
                                            IRQ_TYPE_EDGE_FALLING);
        } else {
-               dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq,
+               dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq,
                                            IRQ_TYPE_EDGE_RISING);
-               dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq,
+               dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq,
                                            IRQ_TYPE_EDGE_RISING);
        }
 
-       dwc3_qcom_enable_wakeup_irq(qcom->ports[0].ss_phy_irq, 0);
+       dwc3_qcom_enable_wakeup_irq(port->ss_phy_irq, 0);
+}
+
+static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
+{
+       int i;
+
+       for (i = 0; i < qcom->num_ports; i++)
+               dwc3_qcom_disable_port_interrupts(&qcom->ports[i]);
+}
+
+static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
+{
+       int i;
+
+       for (i = 0; i < qcom->num_ports; i++)
+               dwc3_qcom_enable_port_interrupts(&qcom->ports[i]);
 }
 
 static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
@@ -430,7 +440,8 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
         * freezable workqueue.
         */
        if (dwc3_qcom_is_host(qcom) && wakeup) {
-               qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom);
+               for (i = 0; i < qcom->num_ports; i++)
+                       qcom->ports[i].usb2_speed = dwc3_qcom_read_usb2_speed(qcom, i);
                dwc3_qcom_enable_interrupts(qcom);
        }