Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: phy: Add LED mode driver for Microsemi PHYs.

LED Mode:
Microsemi PHY support 2 LEDs (LED[0] and LED[1]) to display different
status information that can be selected by setting LED mode.

LED Mode parameter (vsc8531, led-0-mode) and (vsc8531, led-1-mode) get
from Device Tree.

Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microsemi.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Raju Lakkaraju and committed by
David S. Miller
04d8a0a5 ff4cf0e5

+123 -1
+10
Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
··· 27 27 'vddmac'. 28 28 Default value is 0%. 29 29 Ref: Table:1 - Edge rate change (below). 30 + - vsc8531,led-0-mode : LED mode. Specify how the LED[0] should behave. 31 + Allowed values are define in 32 + "include/dt-bindings/net/mscc-phy-vsc8531.h". 33 + Default value is VSC8531_LINK_1000_ACTIVITY (1). 34 + - vsc8531,led-1-mode : LED mode. Specify how the LED[1] should behave. 35 + Allowed values are define in 36 + "include/dt-bindings/net/mscc-phy-vsc8531.h". 37 + Default value is VSC8531_LINK_100_ACTIVITY (2). 30 38 31 39 Table: 1 - Edge rate change 32 40 ----------------------------------------------------------------| ··· 68 60 compatible = "ethernet-phy-id0007.0570"; 69 61 vsc8531,vddmac = <3300>; 70 62 vsc8531,edge-slowdown = <7>; 63 + vsc8531,led-0-mode = <LINK_1000_ACTIVITY>; 64 + vsc8531,led-1-mode = <LINK_100_ACTIVITY>; 71 65 };
+84 -1
drivers/net/phy/mscc.c
··· 13 13 #include <linux/phy.h> 14 14 #include <linux/of.h> 15 15 #include <linux/netdevice.h> 16 + #include <dt-bindings/net/mscc-phy-vsc8531.h> 16 17 17 18 enum rgmii_rx_clock_delay { 18 19 RGMII_RX_CLK_DELAY_0_2_NS = 0, ··· 52 51 53 52 #define MSCC_PHY_DEV_AUX_CNTL 28 54 53 #define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000 54 + 55 + #define MSCC_PHY_LED_MODE_SEL 29 56 + #define LED_1_MODE_SEL_MASK 0x00F0 57 + #define LED_0_MODE_SEL_MASK 0x000F 58 + #define LED_1_MODE_SEL_POS 4 55 59 56 60 #define MSCC_EXT_PAGE_ACCESS 31 57 61 #define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */ ··· 105 99 106 100 struct vsc8531_private { 107 101 int rate_magic; 102 + u8 led_0_mode; 103 + u8 led_1_mode; 108 104 }; 109 105 110 106 #ifdef CONFIG_OF_MDIO ··· 128 120 int rc; 129 121 130 122 rc = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page); 123 + return rc; 124 + } 125 + 126 + static int vsc85xx_led_cntl_set(struct phy_device *phydev, 127 + u8 led_num, 128 + u8 mode) 129 + { 130 + int rc; 131 + u16 reg_val; 132 + 133 + mutex_lock(&phydev->lock); 134 + reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL); 135 + if (led_num) { 136 + reg_val &= ~LED_1_MODE_SEL_MASK; 137 + reg_val |= (((u16)mode << LED_1_MODE_SEL_POS) & 138 + LED_1_MODE_SEL_MASK); 139 + } else { 140 + reg_val &= ~LED_0_MODE_SEL_MASK; 141 + reg_val |= ((u16)mode & LED_0_MODE_SEL_MASK); 142 + } 143 + rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val); 144 + mutex_unlock(&phydev->lock); 145 + 131 146 return rc; 132 147 } 133 148 ··· 401 370 402 371 return -EINVAL; 403 372 } 373 + 374 + static int vsc85xx_dt_led_mode_get(struct phy_device *phydev, 375 + char *led, 376 + u8 default_mode) 377 + { 378 + struct device *dev = &phydev->mdio.dev; 379 + struct device_node *of_node = dev->of_node; 380 + u8 led_mode; 381 + int err; 382 + 383 + if (!of_node) 384 + return -ENODEV; 385 + 386 + led_mode = default_mode; 387 + err = of_property_read_u8(of_node, led, &led_mode); 388 + if (!err && (led_mode > 15 || led_mode == 7 || led_mode == 11)) { 389 + phydev_err(phydev, "DT %s invalid\n", led); 390 + return -EINVAL; 391 + } 392 + 393 + return led_mode; 394 + } 395 + 404 396 #else 405 397 static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev) 406 398 { 407 399 return 0; 400 + } 401 + 402 + static int vsc85xx_dt_led_mode_get(struct phy_device *phydev, 403 + char *led, 404 + u8 default_mode) 405 + { 406 + return default_mode; 408 407 } 409 408 #endif /* CONFIG_OF_MDIO */ 410 409 ··· 560 499 if (rc) 561 500 return rc; 562 501 502 + rc = vsc85xx_led_cntl_set(phydev, 1, vsc8531->led_1_mode); 503 + if (rc) 504 + return rc; 505 + 506 + rc = vsc85xx_led_cntl_set(phydev, 0, vsc8531->led_0_mode); 507 + if (rc) 508 + return rc; 509 + 563 510 rc = genphy_config_init(phydev); 564 511 565 512 return rc; ··· 624 555 625 556 static int vsc85xx_probe(struct phy_device *phydev) 626 557 { 627 - int rate_magic; 628 558 struct vsc8531_private *vsc8531; 559 + int rate_magic; 560 + int led_mode; 629 561 630 562 rate_magic = vsc85xx_edge_rate_magic_get(phydev); 631 563 if (rate_magic < 0) ··· 639 569 phydev->priv = vsc8531; 640 570 641 571 vsc8531->rate_magic = rate_magic; 572 + 573 + /* LED[0] and LED[1] mode */ 574 + led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-0-mode", 575 + VSC8531_LINK_1000_ACTIVITY); 576 + if (led_mode < 0) 577 + return led_mode; 578 + vsc8531->led_0_mode = led_mode; 579 + 580 + led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-1-mode", 581 + VSC8531_LINK_100_ACTIVITY); 582 + if (led_mode < 0) 583 + return led_mode; 584 + vsc8531->led_1_mode = led_mode; 642 585 643 586 return 0; 644 587 }
+29
include/dt-bindings/net/mscc-phy-vsc8531.h
··· 1 + /* 2 + * Device Tree constants for Microsemi VSC8531 PHY 3 + * 4 + * Author: Nagaraju Lakkaraju 5 + * 6 + * License: Dual MIT/GPL 7 + * Copyright (c) 2017 Microsemi Corporation 8 + */ 9 + 10 + #ifndef _DT_BINDINGS_MSCC_VSC8531_H 11 + #define _DT_BINDINGS_MSCC_VSC8531_H 12 + 13 + /* PHY LED Modes */ 14 + #define VSC8531_LINK_ACTIVITY 0 15 + #define VSC8531_LINK_1000_ACTIVITY 1 16 + #define VSC8531_LINK_100_ACTIVITY 2 17 + #define VSC8531_LINK_10_ACTIVITY 3 18 + #define VSC8531_LINK_100_1000_ACTIVITY 4 19 + #define VSC8531_LINK_10_1000_ACTIVITY 5 20 + #define VSC8531_LINK_10_100_ACTIVITY 6 21 + #define VSC8531_DUPLEX_COLLISION 8 22 + #define VSC8531_COLLISION 9 23 + #define VSC8531_ACTIVITY 10 24 + #define VSC8531_AUTONEG_FAULT 12 25 + #define VSC8531_SERIAL_MODE 13 26 + #define VSC8531_FORCE_LED_OFF 14 27 + #define VSC8531_FORCE_LED_ON 15 28 + 29 + #endif