mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-08 10:35:54 -04:00
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: Krishna Kurapati <quic_kriskura@quicinc.com> Reviewed-by: Bjorn Andersson <quic_bjorande@quicinc.com> Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Reviewed-by: Johan Hovold <johan+linaro@kernel.org> Tested-by: Johan Hovold <johan+linaro@kernel.org> Link: https://lore.kernel.org/r/20240420044901.884098-8-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
6410c8033b
commit
2bfc9916a0
@@ -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;
|
||||
|
||||
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, irq_name);
|
||||
if (ret)
|
||||
return ret;
|
||||
qcom->ports[port_index].dp_hs_phy_irq = 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, irq_name);
|
||||
if (ret)
|
||||
return ret;
|
||||
qcom->ports[port_index].dm_hs_phy_irq = 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, irq_name);
|
||||
if (ret)
|
||||
return ret;
|
||||
qcom->ports[port_index].ss_phy_irq = 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, "qusb2_phy");
|
||||
if (ret)
|
||||
return ret;
|
||||
qcom->qusb2_phy_irq = irq;
|
||||
qcom->ports[port_index].qusb2_phy_irq = irq;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_irq");
|
||||
if (irq > 0) {
|
||||
ret = dwc3_qcom_request_irq(qcom, irq, "dp_hs_phy_irq");
|
||||
if (ret)
|
||||
return ret;
|
||||
qcom->dp_hs_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;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname_optional(pdev, "dm_hs_phy_irq");
|
||||
if (irq > 0) {
|
||||
ret = dwc3_qcom_request_irq(qcom, irq, "dm_hs_phy_irq");
|
||||
if (ret)
|
||||
return ret;
|
||||
qcom->dm_hs_phy_irq = irq;
|
||||
}
|
||||
return DWC3_QCOM_MAX_PORTS;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname_optional(pdev, "ss_phy_irq");
|
||||
if (irq > 0) {
|
||||
ret = dwc3_qcom_request_irq(qcom, irq, "ss_phy_irq");
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user