[PATCH v10 06/11] usb: dwc3: qcom: Refactor IRQ handling in QCOM Glue driver

From: Krishna Kurapati
Date: Thu Jul 27 2023 - 18:35:00 EST


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