8
8
*/
9
9
#include <linux/ethtool_netlink.h>
10
10
#include <linux/marvell_phy.h>
11
+ #include <linux/of.h>
11
12
#include <linux/phy.h>
12
13
#include <linux/hwmon.h>
13
14
27
28
#define MDIO_MMD_AN_MV_STAT2_100BT1 0x2000
28
29
#define MDIO_MMD_AN_MV_STAT2_1000BT1 0x4000
29
30
31
+ #define MDIO_MMD_PCS_MV_RESET_CTRL 32768
32
+ #define MDIO_MMD_PCS_MV_RESET_CTRL_TX_DISABLE 0x8
33
+
30
34
#define MDIO_MMD_PCS_MV_INT_EN 32784
31
35
#define MDIO_MMD_PCS_MV_INT_EN_LINK_UP 0x0040
32
36
#define MDIO_MMD_PCS_MV_INT_EN_LINK_DOWN 0x0080
40
44
#define MDIO_MMD_PCS_MV_GPIO_INT_CTRL 32787
41
45
#define MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS 0x0800
42
46
47
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL 32790
48
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_1_MASK GENMASK(7, 4)
49
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_0_MASK GENMASK(3, 0)
50
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK 0x0 /* Link established */
51
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_RX_TX 0x1 /* Link established, blink for rx or tx activity */
52
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_1000BT1 0x2 /* Blink 3x for 1000BT1 link established */
53
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_RX_TX_ON 0x3 /* Receive or transmit activity */
54
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_RX_TX 0x4 /* Blink on receive or transmit activity */
55
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_TX 0x5 /* Transmit activity */
56
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_COPPER 0x6 /* Copper Link established */
57
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_1000BT1_ON 0x7 /* 1000BT1 link established */
58
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_OFF 0x8 /* Force off */
59
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_ON 0x9 /* Force on */
60
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_HIGHZ 0xa /* Force Hi-Z */
61
+ #define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_BLINK 0xb /* Force blink */
62
+
43
63
#define MDIO_MMD_PCS_MV_TEMP_SENSOR1 32833
44
64
#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_RAW_INT 0x0001
45
65
#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_INT 0x0040
95
115
96
116
#define MDIO_MMD_PCS_MV_TDR_OFF_CUTOFF 65246
97
117
118
+ #define MV88Q2XXX_LED_INDEX_TX_ENABLE 0
119
+ #define MV88Q2XXX_LED_INDEX_GPIO 1
120
+
98
121
struct mv88q2xxx_priv {
99
122
bool enable_temp ;
123
+ bool enable_led0 ;
100
124
};
101
125
102
126
struct mmd_val {
@@ -460,6 +484,9 @@ static int mv88q2xxx_config_aneg(struct phy_device *phydev)
460
484
461
485
static int mv88q2xxx_config_init (struct phy_device * phydev )
462
486
{
487
+ struct mv88q2xxx_priv * priv = phydev -> priv ;
488
+ int ret ;
489
+
463
490
/* The 88Q2XXX PHYs do have the extended ability register available, but
464
491
* register MDIO_PMA_EXTABLE where they should signalize it does not
465
492
* work according to specification. Therefore, we force it here.
@@ -469,10 +496,22 @@ static int mv88q2xxx_config_init(struct phy_device *phydev)
469
496
/* Configure interrupt with default settings, output is driven low for
470
497
* active interrupt and high for inactive.
471
498
*/
472
- if (phy_interrupt_is_valid (phydev ))
473
- return phy_set_bits_mmd (phydev , MDIO_MMD_PCS ,
474
- MDIO_MMD_PCS_MV_GPIO_INT_CTRL ,
475
- MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS );
499
+ if (phy_interrupt_is_valid (phydev )) {
500
+ ret = phy_set_bits_mmd (phydev , MDIO_MMD_PCS ,
501
+ MDIO_MMD_PCS_MV_GPIO_INT_CTRL ,
502
+ MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS );
503
+ if (ret < 0 )
504
+ return ret ;
505
+ }
506
+
507
+ /* Enable LED function and disable TX disable feature on LED/TX_ENABLE */
508
+ if (priv -> enable_led0 ) {
509
+ ret = phy_clear_bits_mmd (phydev , MDIO_MMD_PCS ,
510
+ MDIO_MMD_PCS_MV_RESET_CTRL ,
511
+ MDIO_MMD_PCS_MV_RESET_CTRL_TX_DISABLE );
512
+ if (ret < 0 )
513
+ return ret ;
514
+ }
476
515
477
516
return 0 ;
478
517
}
@@ -740,15 +779,62 @@ static int mv88q2xxx_hwmon_probe(struct phy_device *phydev)
740
779
}
741
780
#endif
742
781
782
+ #if IS_ENABLED (CONFIG_OF_MDIO )
783
+ static int mv88q2xxx_leds_probe (struct phy_device * phydev )
784
+ {
785
+ struct device_node * node = phydev -> mdio .dev .of_node ;
786
+ struct mv88q2xxx_priv * priv = phydev -> priv ;
787
+ struct device_node * leds ;
788
+ int ret = 0 ;
789
+ u32 index ;
790
+
791
+ if (!node )
792
+ return 0 ;
793
+
794
+ leds = of_get_child_by_name (node , "leds" );
795
+ if (!leds )
796
+ return 0 ;
797
+
798
+ for_each_available_child_of_node_scoped (leds , led ) {
799
+ ret = of_property_read_u32 (led , "reg" , & index );
800
+ if (ret )
801
+ goto exit ;
802
+
803
+ if (index > MV88Q2XXX_LED_INDEX_GPIO ) {
804
+ ret = - EINVAL ;
805
+ goto exit ;
806
+ }
807
+
808
+ if (index == MV88Q2XXX_LED_INDEX_TX_ENABLE )
809
+ priv -> enable_led0 = true;
810
+ }
811
+
812
+ exit :
813
+ of_node_put (leds );
814
+
815
+ return ret ;
816
+ }
817
+
818
+ #else
819
+ static int mv88q2xxx_leds_probe (struct phy_device * phydev )
820
+ {
821
+ return 0 ;
822
+ }
823
+ #endif
824
+
743
825
static int mv88q2xxx_probe (struct phy_device * phydev )
744
826
{
745
827
struct mv88q2xxx_priv * priv ;
828
+ int ret ;
746
829
747
830
priv = devm_kzalloc (& phydev -> mdio .dev , sizeof (* priv ), GFP_KERNEL );
748
831
if (!priv )
749
832
return - ENOMEM ;
750
833
751
834
phydev -> priv = priv ;
835
+ ret = mv88q2xxx_leds_probe (phydev );
836
+ if (ret )
837
+ return ret ;
752
838
753
839
return mv88q2xxx_hwmon_probe (phydev );
754
840
}
@@ -918,6 +1004,98 @@ static int mv88q222x_cable_test_get_status(struct phy_device *phydev,
918
1004
return 0 ;
919
1005
}
920
1006
1007
+ static int mv88q2xxx_led_mode (u8 index , unsigned long rules )
1008
+ {
1009
+ switch (rules ) {
1010
+ case BIT (TRIGGER_NETDEV_LINK ):
1011
+ return MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK ;
1012
+ case BIT (TRIGGER_NETDEV_LINK_1000 ):
1013
+ return MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_1000BT1_ON ;
1014
+ case BIT (TRIGGER_NETDEV_TX ):
1015
+ return MDIO_MMD_PCS_MV_LED_FUNC_CTRL_TX ;
1016
+ case BIT (TRIGGER_NETDEV_TX ) | BIT (TRIGGER_NETDEV_RX ):
1017
+ return MDIO_MMD_PCS_MV_LED_FUNC_CTRL_RX_TX ;
1018
+ case BIT (TRIGGER_NETDEV_LINK ) | BIT (TRIGGER_NETDEV_TX ) | BIT (TRIGGER_NETDEV_RX ):
1019
+ return MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_RX_TX ;
1020
+ default :
1021
+ return - EOPNOTSUPP ;
1022
+ }
1023
+ }
1024
+
1025
+ static int mv88q2xxx_led_hw_is_supported (struct phy_device * phydev , u8 index ,
1026
+ unsigned long rules )
1027
+ {
1028
+ int mode ;
1029
+
1030
+ mode = mv88q2xxx_led_mode (index , rules );
1031
+ if (mode < 0 )
1032
+ return mode ;
1033
+
1034
+ return 0 ;
1035
+ }
1036
+
1037
+ static int mv88q2xxx_led_hw_control_set (struct phy_device * phydev , u8 index ,
1038
+ unsigned long rules )
1039
+ {
1040
+ int mode ;
1041
+
1042
+ mode = mv88q2xxx_led_mode (index , rules );
1043
+ if (mode < 0 )
1044
+ return mode ;
1045
+
1046
+ if (index == MV88Q2XXX_LED_INDEX_TX_ENABLE )
1047
+ return phy_modify_mmd (phydev , MDIO_MMD_PCS ,
1048
+ MDIO_MMD_PCS_MV_LED_FUNC_CTRL ,
1049
+ MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_0_MASK ,
1050
+ FIELD_PREP (MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_0_MASK ,
1051
+ mode ));
1052
+ else
1053
+ return phy_modify_mmd (phydev , MDIO_MMD_PCS ,
1054
+ MDIO_MMD_PCS_MV_LED_FUNC_CTRL ,
1055
+ MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_1_MASK ,
1056
+ FIELD_PREP (MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_1_MASK ,
1057
+ mode ));
1058
+ }
1059
+
1060
+ static int mv88q2xxx_led_hw_control_get (struct phy_device * phydev , u8 index ,
1061
+ unsigned long * rules )
1062
+ {
1063
+ int val ;
1064
+
1065
+ val = phy_read_mmd (phydev , MDIO_MMD_PCS , MDIO_MMD_PCS_MV_LED_FUNC_CTRL );
1066
+ if (val < 0 )
1067
+ return val ;
1068
+
1069
+ if (index == MV88Q2XXX_LED_INDEX_TX_ENABLE )
1070
+ val = FIELD_GET (MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_0_MASK , val );
1071
+ else
1072
+ val = FIELD_GET (MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_1_MASK , val );
1073
+
1074
+ switch (val ) {
1075
+ case MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK :
1076
+ * rules = BIT (TRIGGER_NETDEV_LINK );
1077
+ break ;
1078
+ case MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_1000BT1_ON :
1079
+ * rules = BIT (TRIGGER_NETDEV_LINK_1000 );
1080
+ break ;
1081
+ case MDIO_MMD_PCS_MV_LED_FUNC_CTRL_TX :
1082
+ * rules = BIT (TRIGGER_NETDEV_TX );
1083
+ break ;
1084
+ case MDIO_MMD_PCS_MV_LED_FUNC_CTRL_RX_TX :
1085
+ * rules = BIT (TRIGGER_NETDEV_TX ) | BIT (TRIGGER_NETDEV_RX );
1086
+ break ;
1087
+ case MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_RX_TX :
1088
+ * rules = BIT (TRIGGER_NETDEV_LINK ) | BIT (TRIGGER_NETDEV_TX ) |
1089
+ BIT (TRIGGER_NETDEV_RX );
1090
+ break ;
1091
+ default :
1092
+ * rules = 0 ;
1093
+ break ;
1094
+ }
1095
+
1096
+ return 0 ;
1097
+ }
1098
+
921
1099
static struct phy_driver mv88q2xxx_driver [] = {
922
1100
{
923
1101
.phy_id = MARVELL_PHY_ID_88Q2110 ,
@@ -953,6 +1131,9 @@ static struct phy_driver mv88q2xxx_driver[] = {
953
1131
.get_sqi_max = mv88q2xxx_get_sqi_max ,
954
1132
.suspend = mv88q2xxx_suspend ,
955
1133
.resume = mv88q2xxx_resume ,
1134
+ .led_hw_is_supported = mv88q2xxx_led_hw_is_supported ,
1135
+ .led_hw_control_set = mv88q2xxx_led_hw_control_set ,
1136
+ .led_hw_control_get = mv88q2xxx_led_hw_control_get ,
956
1137
},
957
1138
};
958
1139
0 commit comments