summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/net/maxlinear,gpy2xx.yaml47
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.yaml2
-rw-r--r--drivers/net/phy/mxl-gpy.c5
-rw-r--r--drivers/net/phy/phy_device.c7
-rw-r--r--include/linux/phy.h3
5 files changed, 64 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/net/maxlinear,gpy2xx.yaml b/Documentation/devicetree/bindings/net/maxlinear,gpy2xx.yaml
new file mode 100644
index 000000000000..d71fa9de2b64
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/maxlinear,gpy2xx.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/maxlinear,gpy2xx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MaxLinear GPY2xx PHY
+
+maintainers:
+ - Andrew Lunn <andrew@lunn.ch>
+ - Michael Walle <michael@walle.cc>
+
+allOf:
+ - $ref: ethernet-phy.yaml#
+
+properties:
+ maxlinear,use-broken-interrupts:
+ description: |
+ Interrupts are broken on some GPY2xx PHYs in that they keep the
+ interrupt line asserted even after the interrupt status register is
+ cleared. Thus it is blocking the interrupt line which is usually bad
+ for shared lines. By default interrupts are disabled for this PHY and
+ polling mode is used. If one can live with the consequences, this
+ property can be used to enable interrupt handling.
+
+ Affected PHYs (as far as known) are GPY215B and GPY215C.
+ type: boolean
+
+dependencies:
+ maxlinear,use-broken-interrupts: [ interrupts ]
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ ethernet {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethernet-phy@0 {
+ reg = <0>;
+ interrupts-extended = <&intc 0>;
+ maxlinear,use-broken-interrupts;
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 70ffb3780621..161766b1de50 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -775,6 +775,8 @@ patternProperties:
description: MaxBotix Inc.
"^maxim,.*":
description: Maxim Integrated Products
+ "^maxlinear,.*":
+ description: MaxLinear Inc.
"^mbvl,.*":
description: Mobiveil Inc.
"^mcube,.*":
diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c
index 147d7a5a9b35..e5972b4ef6e8 100644
--- a/drivers/net/phy/mxl-gpy.c
+++ b/drivers/net/phy/mxl-gpy.c
@@ -12,6 +12,7 @@
#include <linux/mutex.h>
#include <linux/phy.h>
#include <linux/polynomial.h>
+#include <linux/property.h>
#include <linux/netdevice.h>
/* PHY ID */
@@ -292,6 +293,10 @@ static int gpy_probe(struct phy_device *phydev)
phydev->priv = priv;
mutex_init(&priv->mbox_lock);
+ if (gpy_has_broken_mdint(phydev) &&
+ !device_property_present(dev, "maxlinear,use-broken-interrupts"))
+ phydev->dev_flags |= PHY_F_NO_IRQ;
+
fw_version = phy_read(phydev, PHY_FWV);
if (fw_version < 0)
return fw_version;
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 716870a4499c..e4562859ac00 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1487,6 +1487,13 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
phydev->interrupts = PHY_INTERRUPT_DISABLED;
+ /* PHYs can request to use poll mode even though they have an
+ * associated interrupt line. This could be the case if they
+ * detect a broken interrupt handling.
+ */
+ if (phydev->dev_flags & PHY_F_NO_IRQ)
+ phydev->irq = PHY_POLL;
+
/* Port is set to PORT_TP by default and the actual PHY driver will set
* it to different value depending on the PHY configuration. If we have
* the generic PHY driver we can't figure it out, thus set the old
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 6378c997ded5..742754d72fc0 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -739,6 +739,9 @@ struct phy_device {
#endif
};
+/* Generic phy_device::dev_flags */
+#define PHY_F_NO_IRQ 0x80000000
+
static inline struct phy_device *to_phy_device(const struct device *dev)
{
return container_of(to_mdio_device(dev), struct phy_device, mdio);