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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [Linux for Sparc]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux