diff --git a/drivers/phy/phy-snps-eusb2.c b/drivers/phy/phy-snps-eusb2.c index f90bf7e95463b..fe4ce9d752f71 100644 --- a/drivers/phy/phy-snps-eusb2.c +++ b/drivers/phy/phy-snps-eusb2.c @@ -597,6 +597,8 @@ static int snps_eusb2_hsphy_probe(struct platform_device *pdev) return PTR_ERR(generic_phy); } + phy_set_type(generic_phy, PHY_TYPE_EUSB2); + dev_set_drvdata(dev, phy); phy_set_drvdata(generic_phy, phy); diff --git a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c index 9434bd22ef32d..7e1b36e9d4ab9 100644 --- a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c @@ -277,6 +277,8 @@ static int m31eusb2_phy_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(phy->phy), "failed to create phy\n"); + phy_set_type(phy->phy, PHY_TYPE_EUSB2); + ret = devm_regulator_bulk_get_const(dev, M31_EUSB_NUM_VREGS, m31_eusb_phy_vregs, &phy->vregs); if (ret) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 5d131a33ae5a4..f865c922f7d3f 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -86,6 +86,7 @@ struct dwc3_qcom { struct icc_path *icc_path_apps; enum usb_role current_role; + bool has_eusb2_phy; }; #define to_dwc3_qcom(d) container_of((d), struct dwc3_qcom, dwc) @@ -273,15 +274,23 @@ static void dwc3_qcom_disable_wakeup_irq(int irq) disable_irq_nosync(irq); } -static void dwc3_qcom_disable_port_interrupts(struct dwc3_qcom_port *port) +static void dwc3_qcom_disable_port_interrupts(struct dwc3_qcom *qcom, int port_index) { + struct dwc3_qcom_port *port = &qcom->ports[port_index]; + dwc3_qcom_disable_wakeup_irq(port->qusb2_phy_irq); if (port->usb2_speed == USB_SPEED_LOW) { - dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq); + if (qcom->has_eusb2_phy) + dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq); + else + dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq); } else if ((port->usb2_speed == USB_SPEED_HIGH) || (port->usb2_speed == USB_SPEED_FULL)) { - dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq); + if (qcom->has_eusb2_phy) + dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq); + else + dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq); } else { dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq); dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq); @@ -290,26 +299,38 @@ static void dwc3_qcom_disable_port_interrupts(struct dwc3_qcom_port *port) dwc3_qcom_disable_wakeup_irq(port->ss_phy_irq); } -static void dwc3_qcom_enable_port_interrupts(struct dwc3_qcom_port *port) +static void dwc3_qcom_enable_port_interrupts(struct dwc3_qcom *qcom, int port_index) { + struct dwc3_qcom_port *port = &qcom->ports[port_index]; + dwc3_qcom_enable_wakeup_irq(port->qusb2_phy_irq, 0); /* * Configure DP/DM line interrupts based on the USB2 device attached to - * the root hub port. When HS/FS device is connected, configure the DP line - * as falling edge to detect both disconnect and remote wakeup scenarios. When - * LS device is connected, configure DM line as falling edge to detect both - * disconnect and remote wakeup. When no device is connected, configure both - * DP and DM lines as rising edge to detect HS/HS/LS device connect scenario. + * the root hub port. For non-eUSB2 targets, when HS/FS device is connected, + * configure the DP line as falling edge to detect disconnect and remote + * wakeup. When LS device is connected, configure the DM line as falling edge + * for the same. For eUSB2 targets, the lines are swapped and rising edge is + * used: DP line for LS and DM line for HS/FS device detection. When no + * device is connected, configure both DP and DM lines as rising edge to + * detect HS/FS/LS device connect scenario. */ if (port->usb2_speed == USB_SPEED_LOW) { - dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq, - IRQ_TYPE_EDGE_FALLING); + if (qcom->has_eusb2_phy) + dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq, + IRQ_TYPE_EDGE_RISING); + else + dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq, + IRQ_TYPE_EDGE_FALLING); } else if ((port->usb2_speed == USB_SPEED_HIGH) || (port->usb2_speed == USB_SPEED_FULL)) { - dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq, - IRQ_TYPE_EDGE_FALLING); + if (qcom->has_eusb2_phy) + dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq, + IRQ_TYPE_EDGE_RISING); + else + dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq, + IRQ_TYPE_EDGE_FALLING); } else { dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq, IRQ_TYPE_EDGE_RISING); @@ -325,7 +346,7 @@ static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) int i; for (i = 0; i < qcom->num_ports; i++) - dwc3_qcom_disable_port_interrupts(&qcom->ports[i]); + dwc3_qcom_disable_port_interrupts(qcom, i); } static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) @@ -333,7 +354,7 @@ static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) int i; for (i = 0; i < qcom->num_ports; i++) - dwc3_qcom_enable_port_interrupts(&qcom->ports[i]); + dwc3_qcom_enable_port_interrupts(qcom, i); } static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) @@ -620,6 +641,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev) int ret; bool ignore_pipe_clk; bool wakeup_source; + struct phy *phy; qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL); if (!qcom) @@ -686,6 +708,17 @@ static int dwc3_qcom_probe(struct platform_device *pdev) if (ignore_pipe_clk) dwc3_qcom_select_utmi_clk(qcom); + phy = devm_of_phy_get_by_index(dev, dev->of_node, 0); + if (IS_ERR(phy)) { + if (PTR_ERR(phy) != -ENODEV) { + ret = dev_err_probe(dev, PTR_ERR(phy), + "failed to get usb2 phy\n"); + goto clk_disable; + } + phy = NULL; + } + qcom->has_eusb2_phy = (phy_get_type(phy) == PHY_TYPE_EUSB2); + qcom->mode = usb_get_dr_mode(dev); if (qcom->mode == USB_DR_MODE_HOST) { diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h index 6b901b3423486..c9e8fa6975711 100644 --- a/include/dt-bindings/phy/phy.h +++ b/include/dt-bindings/phy/phy.h @@ -23,5 +23,7 @@ #define PHY_TYPE_DPHY 10 #define PHY_TYPE_CPHY 11 #define PHY_TYPE_USXGMII 12 +#define PHY_TYPE_XAUI 13 +#define PHY_TYPE_EUSB2 14 #endif /* _DT_BINDINGS_PHY */ diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 13add0c2c4072..c6003fd7b27d3 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -21,6 +21,8 @@ #include #include +#include + struct phy; enum phy_mode { @@ -141,11 +143,13 @@ struct phy_ops { * @bus_width: Data path width implemented by PHY * @max_link_rate: Maximum link rate supported by PHY (units to be decided by producer and consumer) * @mode: PHY mode + * @type: PHY type */ struct phy_attrs { u32 bus_width; u32 max_link_rate; enum phy_mode mode; + int type; }; /** @@ -251,6 +255,20 @@ static inline enum phy_mode phy_get_mode(struct phy *phy) { return phy->attrs.mode; } + +static inline int phy_get_type(struct phy *phy) +{ + if (phy) + return phy->attrs.type; + + return PHY_NONE; +} + +static inline void phy_set_type(struct phy *phy, int type) +{ + phy->attrs.type = type; +} + int phy_reset(struct phy *phy); int phy_calibrate(struct phy *phy); int phy_notify_connect(struct phy *phy, int port); @@ -384,6 +402,15 @@ static inline enum phy_mode phy_get_mode(struct phy *phy) return PHY_MODE_INVALID; } +static inline int phy_get_type(struct phy *phy) +{ + return PHY_NONE; +} + +static inline void phy_set_type(struct phy *phy, int type) +{ +} + static inline int phy_reset(struct phy *phy) { if (!phy)