This makes it possible to configure the behavior of the LEDs connected to a PHY. The LEDs are controlled by the chip, this makes it possible to configure the behavior when the hardware should activate and deactivate the LEDs. Signed-off-by: Hauke Mehrtens <hauke@xxxxxxxxxx> --- .../devicetree/bindings/phy/intel-xway.txt | 77 +++++++++++ drivers/net/phy/intel-xway.c | 152 +++++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/intel-xway.txt diff --git a/Documentation/devicetree/bindings/phy/intel-xway.txt b/Documentation/devicetree/bindings/phy/intel-xway.txt new file mode 100644 index 0000000..02891c4 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/intel-xway.txt @@ -0,0 +1,77 @@ +Intel XWAY Ethernet PHY binding +------------------------------ + +This supports the Intel XWAY (former Lantiq) 11G and 22E PHYs. These +PHYs are also named PEF 7061, PEF 7071 and PEF 7072. + +Required properties: + - compatible: should be "ethernet-phy-ieee802.3-c22" + - reg: MDIO address of this PHY + + +LEDs: +The PEF 7071 PHY supports 3 LEDs, the PEF 7072 PHY supports 4 LEDs. Use +one subnode for each LED. By default the LEDs 0, 1 and 2 are switched +to be constant on when a 10MBit/s, 100MBit/s or 1000MBit/s link is +detected and they blink when TX or RX traffic is detected. All 3 LEDs +are doing the same as most known devices only have one LED. + +To change the behavior create a subnode with the following attributes: + +Required properties: + - compatible: should be: "phy,led" + - reg: led number + +optional properties: + - led-const-on: Conditions when being constant on + Possible options are one of these: + LED_LINK10, LED_LINK100 and LED_LINK1000, or + some of these 3 values connected with OR. + PHY_LED_PDOWN, PHY_LED_EEE, PHY_LED_ANEG, + PHY_LED_ABIST, PHY_LED_CDIAG, PHY_LED_COPPER, + PHY_LED_FIBER. + - led-pulse: Conditions when led is pulsed + The following values can be connected with OR: + PHY_LED_TXACT, PHY_LED_RXACT, PHY_LED_COL + - led-blink-slow: Conditions when led should blink with 2Hz: + Possible options are one of these: + LED_LINK10, LED_LINK100 and LED_LINK1000, or + some of these 3 values connected with OR. + PHY_LED_PDOWN, PHY_LED_EEE, PHY_LED_ANEG, + PHY_LED_ABIST, PHY_LED_CDIAG. + - led-blink-fast: Conditions when led should blink with 16Hz: + Possible options are one of these: + LED_LINK10, LED_LINK100 and LED_LINK1000, or + some of these 3 values connected with OR. + PHY_LED_PDOWN, PHY_LED_EEE, PHY_LED_ANEG, + PHY_LED_ABIST, PHY_LED_CDIAG. + +When multiple properties are set they are applied with the following priority: + 1. led-pulse + 2. led-blink-fast + 3. led-blink-slow + 4. led-const-on + 5. off + + +Example: + +#include <dt-bindings/phy/phy-leds.h> +phy@0 { + compatible = "intel,phy11g", "ethernet-phy-ieee802.3-c22"; + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + led@0 { + compatible = "phy,led"; + reg = <0>; + led-const-on = <(PHY_LED_LINK10 | PHY_LED_LINK100 | PHY_LED_LINK1000)>; + led-pulse = <(PHY_LED_TXACT | PHY_LED_RXACT)>; + }; + led@2 { + compatible = "phy,led"; + reg = <2>; + led-blink-slow = <PHY_LED_EEE>; + led-blink-fast = <PHY_LED_PDOWN>; + }; +}; diff --git a/drivers/net/phy/intel-xway.c b/drivers/net/phy/intel-xway.c index c789462..0c707b6 100644 --- a/drivers/net/phy/intel-xway.c +++ b/drivers/net/phy/intel-xway.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/phy.h> #include <linux/of.h> +#include <dt-bindings/phy/phy-leds.h> #define XWAY_MDIO_IMASK 0x19 /* interrupt mask */ #define XWAY_MDIO_ISTAT 0x1A /* interrupt status */ @@ -152,11 +153,158 @@ #define PHY_ID_PHY11G_VR9 0xD565A409 #define PHY_ID_PHY22F_VR9 0xD565A419 +static void xway_gphy_config_led(struct phy_device *phydev, + struct device_node *led_np) +{ + const __be32 *addr, *blink_fast_p, *const_on_p, *pulse_p, *blink_slow_p; + u32 num, blink_fast, const_on, pulse, blink_slow; + u32 ledxl; + u32 ledxh; + + addr = of_get_property(led_np, "reg", NULL); + if (!addr) + return; + num = be32_to_cpu(*addr); + + if (num < 0 || num > 3) + return; + + ledxh = XWAY_MMD_LEDxH_BLINKF_NONE | XWAY_MMD_LEDxH_CON_LINK10XX; + blink_fast_p = of_get_property(led_np, "led-blink-fast", NULL); + if (blink_fast_p) { + ledxh &= ~XWAY_MMD_LEDxH_BLINKF_MASK; + blink_fast = be32_to_cpu(*blink_fast_p); + if ((blink_fast & PHY_LED_LINK10) && + (blink_fast & PHY_LED_LINK100) && + (blink_fast & PHY_LED_LINK1000)) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_LINK10XX; + } else if ((blink_fast & PHY_LED_LINK10) && + (blink_fast & PHY_LED_LINK1000)) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_LINK10_0; + } else if ((blink_fast & PHY_LED_LINK10) && + (blink_fast & PHY_LED_LINK100)) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_LINK10X; + } else if ((blink_fast & PHY_LED_LINK100) && + (blink_fast & PHY_LED_LINK1000)) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_LINK100X; + } else if (blink_fast & PHY_LED_LINK10) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_LINK10; + } else if (blink_fast & PHY_LED_LINK100) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_LINK100; + } else if (blink_fast & PHY_LED_LINK1000) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_LINK1000; + } else if (blink_fast & PHY_LED_PDOWN) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_PDOWN; + } else if (blink_fast & PHY_LED_EEE) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_EEE; + } else if (blink_fast & PHY_LED_ANEG) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_ANEG; + } else if (blink_fast & PHY_LED_ABIST) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_ABIST; + } else if (blink_fast & PHY_LED_CDIAG) { + ledxh |= XWAY_MMD_LEDxH_BLINKF_CDIAG; + } + } + const_on_p = of_get_property(led_np, "led-const-on", NULL); + if (const_on_p) { + ledxh &= ~XWAY_MMD_LEDxH_CON_MASK; + const_on = be32_to_cpu(*const_on_p); + if ((const_on & PHY_LED_LINK10) && + (const_on & PHY_LED_LINK100) && + (const_on & PHY_LED_LINK1000)) { + ledxh |= XWAY_MMD_LEDxH_CON_LINK10XX; + } else if ((const_on & PHY_LED_LINK10) && + (const_on & PHY_LED_LINK1000)) { + ledxh |= XWAY_MMD_LEDxH_CON_LINK10_0; + } else if ((const_on & PHY_LED_LINK10) && + (const_on & PHY_LED_LINK100)) { + ledxh |= XWAY_MMD_LEDxH_CON_LINK10X; + } else if ((const_on & PHY_LED_LINK100) && + (const_on & PHY_LED_LINK1000)) { + ledxh |= XWAY_MMD_LEDxH_CON_LINK100X; + } else if (const_on & PHY_LED_LINK10) { + ledxh |= XWAY_MMD_LEDxH_CON_LINK10; + } else if (const_on & PHY_LED_LINK100) { + ledxh |= XWAY_MMD_LEDxH_CON_LINK100; + } else if (const_on & PHY_LED_LINK1000) { + ledxh |= XWAY_MMD_LEDxH_CON_LINK1000; + } else if (const_on & PHY_LED_PDOWN) { + ledxh |= XWAY_MMD_LEDxH_CON_PDOWN; + } else if (const_on & PHY_LED_EEE) { + ledxh |= XWAY_MMD_LEDxH_CON_EEE; + } else if (const_on & PHY_LED_ANEG) { + ledxh |= XWAY_MMD_LEDxH_CON_ANEG; + } else if (const_on & PHY_LED_ABIST) { + ledxh |= XWAY_MMD_LEDxH_CON_ABIST; + } else if (const_on & PHY_LED_CDIAG) { + ledxh |= XWAY_MMD_LEDxH_CON_CDIAG; + } else if (const_on & PHY_LED_COPPER) { + ledxh |= XWAY_MMD_LEDxH_CON_COPPER; + } else if (const_on & PHY_LED_FIBER) { + ledxh |= XWAY_MMD_LEDxH_CON_FIBER; + } + } + phy_write_mmd_indirect(phydev, XWAY_MMD_LED0H + (num * 2), + MDIO_MMD_VEND2, ledxh); + + ledxl = XWAY_MMD_LEDxL_PULSE_TXACT | XWAY_MMD_LEDxL_PULSE_RXACT | + XWAY_MMD_LEDxL_BLINKS_NONE; + pulse_p = of_get_property(led_np, "led-pulse", NULL); + if (pulse_p) { + ledxl &= ~XWAY_MMD_LEDxL_PULSE_MASK; + pulse = be32_to_cpu(*pulse_p); + if (pulse & PHY_LED_TXACT) + ledxl |= XWAY_MMD_LEDxL_PULSE_TXACT; + if (pulse & PHY_LED_RXACT) + ledxl |= XWAY_MMD_LEDxL_PULSE_RXACT; + if (pulse & PHY_LED_COL) + ledxl |= XWAY_MMD_LEDxL_PULSE_COL; + } + blink_slow_p = of_get_property(led_np, "led-blink-slow", NULL); + if (blink_slow_p) { + ledxl &= ~XWAY_MMD_LEDxL_BLINKS_MASK; + blink_slow = be32_to_cpu(*blink_slow_p); + if ((blink_slow & PHY_LED_LINK10) && + (blink_slow & PHY_LED_LINK100) && + (blink_slow & PHY_LED_LINK1000)) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_LINK10XX; + } else if ((blink_slow & PHY_LED_LINK10) && + (blink_slow & PHY_LED_LINK1000)) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_LINK10_0; + } else if ((blink_slow & PHY_LED_LINK10) && + (blink_slow & PHY_LED_LINK100)) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_LINK10X; + } else if ((blink_slow & PHY_LED_LINK100) && + (blink_slow & PHY_LED_LINK1000)) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_LINK100X; + } else if (blink_slow & PHY_LED_LINK10) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_LINK10; + } else if (blink_slow & PHY_LED_LINK100) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_LINK100; + } else if (blink_slow & PHY_LED_LINK1000) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_LINK1000; + } else if (blink_slow & PHY_LED_PDOWN) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_PDOWN; + } else if (blink_slow & PHY_LED_EEE) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_EEE; + } else if (blink_slow & PHY_LED_ANEG) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_ANEG; + } else if (blink_slow & PHY_LED_ABIST) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_ABIST; + } else if (blink_slow & PHY_LED_CDIAG) { + ledxl |= XWAY_MMD_LEDxL_BLINKS_CDIAG; + } + } + phy_write_mmd_indirect(phydev, XWAY_MMD_LED0L + (num * 2), + MDIO_MMD_VEND2, ledxl); +} + static int xway_gphy_config_init(struct phy_device *phydev) { int err; u32 ledxh; u32 ledxl; + struct device_node *led_np; /* Mask all interrupts */ err = phy_write(phydev, XWAY_MDIO_IMASK, 0); @@ -190,6 +338,10 @@ static int xway_gphy_config_init(struct phy_device *phydev) phy_write_mmd_indirect(phydev, XWAY_MMD_LED2H, MDIO_MMD_VEND2, ledxh); phy_write_mmd_indirect(phydev, XWAY_MMD_LED2L, MDIO_MMD_VEND2, ledxl); + for_each_child_of_node(phydev->mdio.dev.of_node, led_np) + if (of_device_is_compatible(led_np, "phy,led")) + xway_gphy_config_led(phydev, led_np); + return 0; } -- 2.8.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html