Commit 2bfc9916 authored by Krishna Kurapati's avatar Krishna Kurapati Committed by Greg Kroah-Hartman

usb: dwc3: qcom: Refactor IRQ handling in glue driver

On multiport supported controllers, each port has its own DP/DM and
SuperSpeed (if super speed capable) interrupts. As per the bindings,
their interrupt names differ from single-port ones by having a "_x"
added as suffix (x being the port number). Identify from the interrupt
names whether the controller is a multiport controller or not.
Refactor dwc3_qcom_setup_irq() call to parse multiportinterrupts along
with non-multiport ones accordingly.
Signed-off-by: default avatarKrishna Kurapati <quic_kriskura@quicinc.com>
Reviewed-by: default avatarBjorn Andersson <quic_bjorande@quicinc.com>
Acked-by: default avatarThinh Nguyen <Thinh.Nguyen@synopsys.com>
Reviewed-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Tested-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Link: https://lore.kernel.org/r/20240420044901.884098-8-quic_kriskura@quicinc.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6410c803
......@@ -52,6 +52,16 @@
#define APPS_USB_AVG_BW 0
#define APPS_USB_PEAK_BW MBps_to_icc(40)
/* Qualcomm SoCs with multiport support has up to 4 ports */
#define DWC3_QCOM_MAX_PORTS 4
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 +69,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_QCOM_MAX_PORTS];
u8 num_ports;
enum usb_device_speed usb2_speed;
struct extcon_dev *edev;
......@@ -354,24 +361,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 +390,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 +524,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_index, 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_index + 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_index].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_index + 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_index].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_index + 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_index].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_index].qusb2_phy_irq = irq;
}
return 0;
}
static int dwc3_qcom_find_num_ports(struct platform_device *pdev)
{
char irq_name[14];
int port_num;
int irq;
irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_1");
if (irq <= 0)
return 1;
for (port_num = 2; port_num <= DWC3_QCOM_MAX_PORTS; port_num++) {
sprintf(irq_name, "dp_hs_phy_%d", port_num);
irq = platform_get_irq_byname_optional(pdev, irq_name);
if (irq <= 0)
return port_num - 1;
}
return DWC3_QCOM_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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment