5
5
*/
6
6
#include <linux/delay.h>
7
7
#include <linux/ethtool.h>
8
+ #include <linux/ethtool_netlink.h>
8
9
#include <linux/kernel.h>
9
10
#include <linux/mdio.h>
10
11
#include <linux/mii.h>
26
27
#define MII_ECTRL_POWER_MODE_NO_CHANGE (0x0 << 11)
27
28
#define MII_ECTRL_POWER_MODE_NORMAL (0x3 << 11)
28
29
#define MII_ECTRL_POWER_MODE_STANDBY (0xc << 11)
30
+ #define MII_ECTRL_CABLE_TEST BIT(5)
29
31
#define MII_ECTRL_CONFIG_EN BIT(2)
30
32
#define MII_ECTRL_WAKE_REQUEST BIT(0)
31
33
55
57
#define MII_GENSTAT 24
56
58
#define MII_GENSTAT_PLL_LOCKED BIT(14)
57
59
60
+ #define MII_EXTSTAT 25
61
+ #define MII_EXTSTAT_SHORT_DETECT BIT(8)
62
+ #define MII_EXTSTAT_OPEN_DETECT BIT(7)
63
+ #define MII_EXTSTAT_POLARITY_DETECT BIT(6)
64
+
58
65
#define MII_COMMCFG 27
59
66
#define MII_COMMCFG_AUTO_OP BIT(15)
60
67
@@ -111,6 +118,11 @@ static int tja11xx_enable_link_control(struct phy_device *phydev)
111
118
return phy_set_bits (phydev , MII_ECTRL , MII_ECTRL_LINK_CONTROL );
112
119
}
113
120
121
+ static int tja11xx_disable_link_control (struct phy_device * phydev )
122
+ {
123
+ return phy_clear_bits (phydev , MII_ECTRL , MII_ECTRL_LINK_CONTROL );
124
+ }
125
+
114
126
static int tja11xx_wakeup (struct phy_device * phydev )
115
127
{
116
128
int ret ;
@@ -536,6 +548,93 @@ static int tja11xx_config_intr(struct phy_device *phydev)
536
548
return phy_write (phydev , MII_INTEN , value );
537
549
}
538
550
551
+ static int tja11xx_cable_test_start (struct phy_device * phydev )
552
+ {
553
+ int ret ;
554
+
555
+ ret = phy_clear_bits (phydev , MII_COMMCFG , MII_COMMCFG_AUTO_OP );
556
+ if (ret )
557
+ return ret ;
558
+
559
+ ret = tja11xx_wakeup (phydev );
560
+ if (ret < 0 )
561
+ return ret ;
562
+
563
+ ret = tja11xx_disable_link_control (phydev );
564
+ if (ret < 0 )
565
+ return ret ;
566
+
567
+ return phy_set_bits (phydev , MII_ECTRL , MII_ECTRL_CABLE_TEST );
568
+ }
569
+
570
+ /*
571
+ * | BI_DA+ | BI_DA- | Result
572
+ * | open | open | open
573
+ * | + short to - | - short to + | short
574
+ * | short to Vdd | open | open
575
+ * | open | shot to Vdd | open
576
+ * | short to Vdd | short to Vdd | short
577
+ * | shot to GND | open | open
578
+ * | open | shot to GND | open
579
+ * | short to GND | shot to GND | short
580
+ * | connected to active link partner (master) | shot and open
581
+ */
582
+ static int tja11xx_cable_test_report_trans (u32 result )
583
+ {
584
+ u32 mask = MII_EXTSTAT_SHORT_DETECT | MII_EXTSTAT_OPEN_DETECT ;
585
+
586
+ if ((result & mask ) == mask ) {
587
+ /* connected to active link partner (master) */
588
+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC ;
589
+ } else if ((result & mask ) == 0 ) {
590
+ return ETHTOOL_A_CABLE_RESULT_CODE_OK ;
591
+ } else if (result & MII_EXTSTAT_SHORT_DETECT ) {
592
+ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT ;
593
+ } else if (result & MII_EXTSTAT_OPEN_DETECT ) {
594
+ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN ;
595
+ } else {
596
+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC ;
597
+ }
598
+ }
599
+
600
+ static int tja11xx_cable_test_report (struct phy_device * phydev )
601
+ {
602
+ int ret ;
603
+
604
+ ret = phy_read (phydev , MII_EXTSTAT );
605
+ if (ret < 0 )
606
+ return ret ;
607
+
608
+ ethnl_cable_test_result (phydev , ETHTOOL_A_CABLE_PAIR_A ,
609
+ tja11xx_cable_test_report_trans (ret ));
610
+
611
+ return 0 ;
612
+ }
613
+
614
+ static int tja11xx_cable_test_get_status (struct phy_device * phydev ,
615
+ bool * finished )
616
+ {
617
+ int ret ;
618
+
619
+ * finished = false;
620
+
621
+ ret = phy_read (phydev , MII_ECTRL );
622
+ if (ret < 0 )
623
+ return ret ;
624
+
625
+ if (!(ret & MII_ECTRL_CABLE_TEST )) {
626
+ * finished = true;
627
+
628
+ ret = phy_set_bits (phydev , MII_COMMCFG , MII_COMMCFG_AUTO_OP );
629
+ if (ret )
630
+ return ret ;
631
+
632
+ return tja11xx_cable_test_report (phydev );
633
+ }
634
+
635
+ return 0 ;
636
+ }
637
+
539
638
static struct phy_driver tja11xx_driver [] = {
540
639
{
541
640
PHY_ID_MATCH_MODEL (PHY_ID_TJA1100 ),
@@ -572,6 +671,7 @@ static struct phy_driver tja11xx_driver[] = {
572
671
}, {
573
672
.name = "NXP TJA1102 Port 0" ,
574
673
.features = PHY_BASIC_T1_FEATURES ,
674
+ .flags = PHY_POLL_CABLE_TEST ,
575
675
.probe = tja1102_p0_probe ,
576
676
.soft_reset = tja11xx_soft_reset ,
577
677
.config_aneg = tja11xx_config_aneg ,
@@ -587,10 +687,12 @@ static struct phy_driver tja11xx_driver[] = {
587
687
.get_stats = tja11xx_get_stats ,
588
688
.ack_interrupt = tja11xx_ack_interrupt ,
589
689
.config_intr = tja11xx_config_intr ,
590
-
690
+ .cable_test_start = tja11xx_cable_test_start ,
691
+ .cable_test_get_status = tja11xx_cable_test_get_status ,
591
692
}, {
592
693
.name = "NXP TJA1102 Port 1" ,
593
694
.features = PHY_BASIC_T1_FEATURES ,
695
+ .flags = PHY_POLL_CABLE_TEST ,
594
696
/* currently no probe for Port 1 is need */
595
697
.soft_reset = tja11xx_soft_reset ,
596
698
.config_aneg = tja11xx_config_aneg ,
@@ -606,6 +708,8 @@ static struct phy_driver tja11xx_driver[] = {
606
708
.get_stats = tja11xx_get_stats ,
607
709
.ack_interrupt = tja11xx_ack_interrupt ,
608
710
.config_intr = tja11xx_config_intr ,
711
+ .cable_test_start = tja11xx_cable_test_start ,
712
+ .cable_test_get_status = tja11xx_cable_test_get_status ,
609
713
}
610
714
};
611
715
0 commit comments