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> --- drivers/usb/dwc3/dwc3-qcom.c | 146 +++++++++++++++++++++++++++-------- 1 file changed, 112 insertions(+), 34 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index cae5dab8fcfc..dcb3b3ded205 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,116 @@ 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) +{ + const char *irq_name; + int port_index; + int irq; + + irq = platform_get_irq_byname_optional(pdev, "qusb2_phy"); + if (irq > 0) + return 1; + + irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_irq"); + if (irq > 0) + return 1; + + for (port_index = 0; port_index < DWC3_MAX_PORTS; port_index++) { + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_%d", port_index + 1); + if (!irq_name) + return -ENOMEM; + + irq = platform_get_irq_byname_optional(pdev, irq_name); + if (irq <= 0) + return port_index; + } + + return port_index; +} + +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); + if (qcom->num_ports < 0) + return -ENOMEM; + + is_multiport = (qcom->num_ports > 1) ? true : false; + + 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