Refactor setup_irq call to facilitate reading multiport IRQ's along with non mulitport ones. For SA8295, there are 4-DP/4-DM and 2-SS IRQ's. Check whether device is multiport capable or not and read all interrupts for DP/DM/SS on each port accordingly. Signed-off-by: Krishna Kurapati <quic_kriskura@xxxxxxxxxxx> --- drivers/usb/dwc3/dwc3-qcom.c | 277 ++++++++++++++++++++++++----------- 1 file changed, 190 insertions(+), 87 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 3de43df6bbe8..ad89ded116d3 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -64,33 +64,61 @@ struct dwc3_acpi_pdata { bool is_urs; }; +struct dwc3_qcom_of_match_data { + u8 num_ports; +}; + struct dwc3_qcom { - struct device *dev; - void __iomem *qscratch_base; - struct platform_device *dwc3; - struct platform_device *urs_usb; - struct clk **clks; - int num_clocks; - struct reset_control *resets; - - int hs_phy_irq; - int dp_hs_phy_irq; - int dm_hs_phy_irq; - int ss_phy_irq; - enum usb_device_speed usb2_speed; - - struct extcon_dev *edev; - struct extcon_dev *host_edev; - struct notifier_block vbus_nb; - struct notifier_block host_nb; + struct device *dev; + void __iomem *qscratch_base; + struct platform_device *dwc3; + struct platform_device *urs_usb; + struct clk **clks; + int num_clocks; + struct reset_control *resets; + + int hs_phy_irq; + int dp_hs_phy_irq[DWC3_MAX_PORTS]; + int dm_hs_phy_irq[DWC3_MAX_PORTS]; + int ss_phy_irq[DWC3_MAX_PORTS]; + enum usb_device_speed usb2_speed; + + struct extcon_dev *edev; + struct extcon_dev *host_edev; + struct notifier_block vbus_nb; + struct notifier_block host_nb; + + const struct dwc3_acpi_pdata *acpi_pdata; + + enum usb_dr_mode mode; + bool is_suspended; + bool pm_suspended; + struct icc_path *icc_path_ddr; + struct icc_path *icc_path_apps; + const struct dwc3_qcom_of_match_data *data; +}; + +static const struct dwc3_qcom_of_match_data qcom_dwc3 = { + .num_ports = 1, +}; - const struct dwc3_acpi_pdata *acpi_pdata; +static const struct dwc3_qcom_of_match_data sx8280xp_qcom_dwc3 = { + .num_ports = 4, +}; - enum usb_dr_mode mode; - bool is_suspended; - bool pm_suspended; - struct icc_path *icc_path_ddr; - struct icc_path *icc_path_apps; +/* + * Driver needs to read HS/DP_HS/DM_HS/SS IRQ's. Currently, for + * SA8295 which supports mutliport, thre are 4 DP/ 4 DM/ 2 SS IRQ's + * and 1 HS IRQ present. So avoid trying to read HS_PHY_IRQ for 4 + * ports of SA8295. + */ +#define MAX_PHY_IRQ 4 + +enum dwc3_qcom_phy_irq_identifier { + HS_PHY_IRQ = 0, + DP_HS_PHY_IRQ, + DM_HS_PHY_IRQ, + SS_PHY_IRQ, }; static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val) @@ -375,16 +403,16 @@ static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) dwc3_qcom_disable_wakeup_irq(qcom->hs_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->dm_hs_phy_irq[0]); } 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->dp_hs_phy_irq[0]); } 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->dp_hs_phy_irq[0]); + dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq[0]); } - dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq); + dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq[0]); } static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) @@ -401,20 +429,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, + dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq[0], 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, + dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq[0], IRQ_TYPE_EDGE_FALLING); } else { - dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq, + dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq[0], IRQ_TYPE_EDGE_RISING); - dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq, + dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq[0], IRQ_TYPE_EDGE_RISING); } - dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0); + dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq[0], 0); } static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) @@ -535,72 +563,138 @@ static int dwc3_qcom_get_irq(struct platform_device *pdev, return ret; } -static int dwc3_qcom_setup_irq(struct platform_device *pdev) +static int dwc3_qcom_prep_irq(struct dwc3_qcom *qcom, char *irq_name, + char *disp_name, int irq) { - struct dwc3_qcom *qcom = platform_get_drvdata(pdev); - const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata; - int irq; int ret; - irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq", - pdata ? pdata->hs_phy_irq_index : -1); - if (irq > 0) { - /* Keep wakeup interrupts disabled until suspend */ - irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, + /* Keep wakeup interrupts disabled until suspend */ + irq_set_status_flags(irq, IRQ_NOAUTOEN); + ret = devm_request_threaded_irq(qcom->dev, irq, NULL, qcom_dwc3_resume_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "qcom_dwc3 HS", qcom); - if (ret) { - dev_err(qcom->dev, "hs_phy_irq failed: %d\n", ret); - return ret; + disp_name, qcom); + if (ret) + dev_err(qcom->dev, "%s failed: %d\n", irq_name, ret); + + return ret; +} + +static int dwc3_get_acpi_index(const struct dwc3_acpi_pdata *pdata, int irq_index) +{ + int acpi_index = -1; + + if (!pdata) + return -1; + + if (irq_index == DP_HS_PHY_IRQ) + acpi_index = pdata->dp_hs_phy_irq_index; + else if (irq_index == DM_HS_PHY_IRQ) + acpi_index = pdata->dm_hs_phy_irq_index; + else if (irq_index == SS_PHY_IRQ) + acpi_index = pdata->ss_phy_irq_index; + + return acpi_index; +} + +static int dwc3_get_port_irq(struct platform_device *pdev, u8 port_index) +{ + struct dwc3_qcom *qcom = platform_get_drvdata(pdev); + bool is_mp_supported = (qcom->data->num_ports > 1) ? true : false; + const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata; + char *disp_name; + int acpi_index; + char *dt_name; + int ret; + int irq; + int i; + + /* + * We need to read only DP/DM/SS IRQ's here. + * So loop over from 1->3 and accordingly modify respective phy_irq[]. + */ + for (i = 1; i < MAX_PHY_IRQ; i++) { + + if (!is_mp_supported && (port_index == 0)) { + if (i == DP_HS_PHY_IRQ) { + dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "dp_hs_phy_irq"); + disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "qcom_dwc3 DP_HS"); + } else if (i == DM_HS_PHY_IRQ) { + dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "dm_hs_phy_irq"); + disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "qcom_dwc3 DM_HS"); + } else if (i == SS_PHY_IRQ) { + dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "ss_phy_irq"); + disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "qcom_dwc3 SS"); + } + } else { + if (i == DP_HS_PHY_IRQ) { + dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "dp_hs_phy_%d", port_index + 1); + disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "qcom_dwc3 DP_HS%d", port_index + 1); + } else if (i == DM_HS_PHY_IRQ) { + dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "dm_hs_phy_%d", port_index + 1); + disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "qcom_dwc3 DM_HS%d", port_index + 1); + } else if (i == SS_PHY_IRQ) { + dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "ss_phy_%d", port_index + 1); + disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "qcom_dwc3 SS%d", port_index + 1); + } } - qcom->hs_phy_irq = irq; - } - irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq", - pdata ? pdata->dp_hs_phy_irq_index : -1); - if (irq > 0) { - irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, - qcom_dwc3_resume_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "qcom_dwc3 DP_HS", qcom); - if (ret) { - dev_err(qcom->dev, "dp_hs_phy_irq failed: %d\n", ret); - return ret; + if (!dt_name || !disp_name) + return -ENOMEM; + + acpi_index = !is_mp_supported ? dwc3_get_acpi_index(pdata, i) : -1; + + irq = dwc3_qcom_get_irq(pdev, dt_name, acpi_index); + if (irq > 0) { + ret = dwc3_qcom_prep_irq(qcom, dt_name, disp_name, irq); + if (ret) + return ret; + + if (i == DP_HS_PHY_IRQ) + qcom->dp_hs_phy_irq[port_index] = irq; + else if (i == DM_HS_PHY_IRQ) + qcom->dm_hs_phy_irq[port_index] = irq; + else if (i == SS_PHY_IRQ) + qcom->ss_phy_irq[port_index] = irq; } - qcom->dp_hs_phy_irq = irq; } - irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq", - pdata ? pdata->dm_hs_phy_irq_index : -1); + return 0; +} + +static int dwc3_qcom_setup_irq(struct platform_device *pdev) +{ + struct dwc3_qcom *qcom = platform_get_drvdata(pdev); + const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata; + int irq; + int ret; + int i; + + irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq", + pdata ? pdata->hs_phy_irq_index : -1); if (irq > 0) { - irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, - qcom_dwc3_resume_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "qcom_dwc3 DM_HS", qcom); - if (ret) { - dev_err(qcom->dev, "dm_hs_phy_irq failed: %d\n", ret); + ret = dwc3_qcom_prep_irq(qcom, "hs_phy_irq", "qcom_dwc3 HS",irq); + if (ret) return ret; - } - qcom->dm_hs_phy_irq = irq; + qcom->hs_phy_irq = irq; } - irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq", - pdata ? pdata->ss_phy_irq_index : -1); - if (irq > 0) { - irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, - qcom_dwc3_resume_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "qcom_dwc3 SS", qcom); - if (ret) { - dev_err(qcom->dev, "ss_phy_irq failed: %d\n", ret); + for (i = 0; i < qcom->data->num_ports; i++) { + ret = dwc3_get_port_irq(pdev, i); + if (ret) return ret; - } - qcom->ss_phy_irq = irq; } return 0; @@ -811,6 +905,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev) platform_set_drvdata(pdev, qcom); qcom->dev = &pdev->dev; + qcom->data = of_device_get_match_data(qcom->dev); + if (has_acpi_companion(dev)) { qcom->acpi_pdata = acpi_device_get_match_data(dev); if (!qcom->acpi_pdata) { @@ -1023,8 +1119,15 @@ static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = { }; static const struct of_device_id dwc3_qcom_of_match[] = { - { .compatible = "qcom,dwc3" }, - { } + { + .compatible = "qcom,dwc3", + .data = &qcom_dwc3, + }, + { + .compatible = "qcom,sc8280xp-dwc3-mp", + .data = &sx8280xp_qcom_dwc3, + }, + { }, }; MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match); -- 2.40.0