[PATCH v17 7/9] usb: dwc3: qcom: Refactor IRQ handling in glue driver

From: Krishna Kurapati
Date: Tue Mar 26 2024 - 06:31:06 EST


On multiport supported controllers, each port has its own DP/DM
and SS (if super speed capable) interrupts. As per the bindings,
their interrupt names differ from standard ones having "_x" added
as suffix (x indicates port number). Identify from the interrupt
names whether the controller is a multiport controller or not.
Refactor dwc3_qcom_setup_irq() call to parse multiport interrupts
along with non-multiport ones accordingly..

Signed-off-by: Krishna Kurapati <quic_kriskura@xxxxxxxxxxx>
Reviewed-by: Johan Hovold <johan+linaro@xxxxxxxxxx>
---
drivers/usb/dwc3/dwc3-qcom.c | 137 ++++++++++++++++++++++++++---------
1 file changed, 103 insertions(+), 34 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index cae5dab8fcfc..38452104337c 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -52,6 +52,13 @@
#define APPS_USB_AVG_BW 0
#define APPS_USB_PEAK_BW MBps_to_icc(40)

+struct dwc3_qcom_port {
+ int qusb2_phy_irq;
+ int dp_hs_phy_irq;
+ int dm_hs_phy_irq;
+ int ss_phy_irq;
+};
+
struct dwc3_qcom {
struct device *dev;
void __iomem *qscratch_base;
@@ -59,11 +66,8 @@ struct dwc3_qcom {
struct clk **clks;
int num_clocks;
struct reset_control *resets;
-
- int qusb2_phy_irq;
- int dp_hs_phy_irq;
- int dm_hs_phy_irq;
- int ss_phy_irq;
+ struct dwc3_qcom_port ports[DWC3_MAX_PORTS];
+ u8 num_ports;
enum usb_device_speed usb2_speed;

struct extcon_dev *edev;
@@ -354,24 +358,24 @@ static void dwc3_qcom_disable_wakeup_irq(int irq)

static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
{
- dwc3_qcom_disable_wakeup_irq(qcom->qusb2_phy_irq);
+ dwc3_qcom_disable_wakeup_irq(qcom->ports[0].qusb2_phy_irq);

if (qcom->usb2_speed == USB_SPEED_LOW) {
- dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
+ 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->dp_hs_phy_irq);
+ dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq);
} else {
- dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
- dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
+ 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(qcom->ss_phy_irq);
+ dwc3_qcom_disable_wakeup_irq(qcom->ports[0].ss_phy_irq);
}

static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
{
- dwc3_qcom_enable_wakeup_irq(qcom->qusb2_phy_irq, 0);
+ dwc3_qcom_enable_wakeup_irq(qcom->ports[0].qusb2_phy_irq, 0);

/*
* Configure DP/DM line interrupts based on the USB2 device attached to
@@ -383,20 +387,20 @@ static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
*/

if (qcom->usb2_speed == USB_SPEED_LOW) {
- dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq,
- IRQ_TYPE_EDGE_FALLING);
+ dwc3_qcom_enable_wakeup_irq(qcom->ports[0].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->dp_hs_phy_irq,
- IRQ_TYPE_EDGE_FALLING);
+ dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq,
+ IRQ_TYPE_EDGE_FALLING);
} else {
- dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq,
- IRQ_TYPE_EDGE_RISING);
- dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq,
- IRQ_TYPE_EDGE_RISING);
+ dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq,
+ IRQ_TYPE_EDGE_RISING);
+ dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq,
+ IRQ_TYPE_EDGE_RISING);
}

- dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0);
+ dwc3_qcom_enable_wakeup_irq(qcom->ports[0].ss_phy_irq, 0);
}

static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
@@ -517,42 +521,107 @@ static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq,
return ret;
}

-static int dwc3_qcom_setup_irq(struct platform_device *pdev)
+static int dwc3_qcom_setup_port_irq(struct platform_device *pdev, int port_num, bool is_multiport)
{
struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+ const char *irq_name;
int irq;
int ret;

- irq = platform_get_irq_byname_optional(pdev, "qusb2_phy");
+ if (is_multiport)
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_%d", port_num + 1);
+ else
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_irq");
+ if (!irq_name)
+ return -ENOMEM;
+
+ irq = platform_get_irq_byname_optional(pdev, irq_name);
if (irq > 0) {
- ret = dwc3_qcom_request_irq(qcom, irq, "qusb2_phy");
+ ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
if (ret)
return ret;
- qcom->qusb2_phy_irq = irq;
+ qcom->ports[port_num].dp_hs_phy_irq = irq;
}

- irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_irq");
+ if (is_multiport)
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_%d", port_num + 1);
+ else
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_irq");
+ if (!irq_name)
+ return -ENOMEM;
+
+ irq = platform_get_irq_byname_optional(pdev, irq_name);
if (irq > 0) {
- ret = dwc3_qcom_request_irq(qcom, irq, "dp_hs_phy_irq");
+ ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
if (ret)
return ret;
- qcom->dp_hs_phy_irq = irq;
+ qcom->ports[port_num].dm_hs_phy_irq = irq;
}

- irq = platform_get_irq_byname_optional(pdev, "dm_hs_phy_irq");
+ if (is_multiport)
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_%d", port_num + 1);
+ else
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_irq");
+ if (!irq_name)
+ return -ENOMEM;
+
+ irq = platform_get_irq_byname_optional(pdev, irq_name);
if (irq > 0) {
- ret = dwc3_qcom_request_irq(qcom, irq, "dm_hs_phy_irq");
+ ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
if (ret)
return ret;
- qcom->dm_hs_phy_irq = irq;
+ qcom->ports[port_num].ss_phy_irq = irq;
}

- irq = platform_get_irq_byname_optional(pdev, "ss_phy_irq");
+ if (is_multiport)
+ return 0;
+
+ irq = platform_get_irq_byname_optional(pdev, "qusb2_phy");
if (irq > 0) {
- ret = dwc3_qcom_request_irq(qcom, irq, "ss_phy_irq");
+ ret = dwc3_qcom_request_irq(qcom, irq, "qusb2_phy");
+ if (ret)
+ return ret;
+ qcom->ports[port_num].qusb2_phy_irq = irq;
+ }
+
+ return 0;
+}
+
+static int dwc3_qcom_find_num_ports(struct platform_device *pdev)
+{
+ char irq_name[14];
+ int port_index;
+ int irq;
+
+ irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_1");
+ if (irq <= 0)
+ return 1;
+
+ for (port_index = 2; port_index <= DWC3_MAX_PORTS; port_index++) {
+ sprintf(irq_name, "dp_hs_phy_%d", port_index);
+
+ irq = platform_get_irq_byname_optional(pdev, irq_name);
+ if (irq <= 0)
+ return port_index - 1;
+ }
+
+ return DWC3_MAX_PORTS;
+}
+
+static int dwc3_qcom_setup_irq(struct platform_device *pdev)
+{
+ struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+ bool is_multiport;
+ int ret;
+ int i;
+
+ qcom->num_ports = dwc3_qcom_find_num_ports(pdev);
+ is_multiport = (qcom->num_ports > 1);
+
+ for (i = 0; i < qcom->num_ports; i++) {
+ ret = dwc3_qcom_setup_port_irq(pdev, i, is_multiport);
if (ret)
return ret;
- qcom->ss_phy_irq = irq;
}

return 0;
--
2.34.1