*/
 #include <linux/delay.h>
 #include <linux/ethtool.h>
+#include <linux/ethtool_netlink.h>
 #include <linux/kernel.h>
 #include <linux/mdio.h>
 #include <linux/mii.h>
 #define MII_ECTRL_POWER_MODE_NO_CHANGE (0x0 << 11)
 #define MII_ECTRL_POWER_MODE_NORMAL    (0x3 << 11)
 #define MII_ECTRL_POWER_MODE_STANDBY   (0xc << 11)
+#define MII_ECTRL_CABLE_TEST           BIT(5)
 #define MII_ECTRL_CONFIG_EN            BIT(2)
 #define MII_ECTRL_WAKE_REQUEST         BIT(0)
 
 #define MII_GENSTAT                    24
 #define MII_GENSTAT_PLL_LOCKED         BIT(14)
 
+#define MII_EXTSTAT                    25
+#define MII_EXTSTAT_SHORT_DETECT       BIT(8)
+#define MII_EXTSTAT_OPEN_DETECT                BIT(7)
+#define MII_EXTSTAT_POLARITY_DETECT    BIT(6)
+
 #define MII_COMMCFG                    27
 #define MII_COMMCFG_AUTO_OP            BIT(15)
 
        return phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_LINK_CONTROL);
 }
 
+static int tja11xx_disable_link_control(struct phy_device *phydev)
+{
+       return phy_clear_bits(phydev, MII_ECTRL, MII_ECTRL_LINK_CONTROL);
+}
+
 static int tja11xx_wakeup(struct phy_device *phydev)
 {
        int ret;
        return phy_write(phydev, MII_INTEN, value);
 }
 
+static int tja11xx_cable_test_start(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = phy_clear_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
+       if (ret)
+               return ret;
+
+       ret = tja11xx_wakeup(phydev);
+       if (ret < 0)
+               return ret;
+
+       ret = tja11xx_disable_link_control(phydev);
+       if (ret < 0)
+               return ret;
+
+       return phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_CABLE_TEST);
+}
+
+/*
+ * | BI_DA+           | BI_DA-                 | Result
+ * | open             | open                   | open
+ * | + short to -     | - short to +           | short
+ * | short to Vdd     | open                   | open
+ * | open             | shot to Vdd            | open
+ * | short to Vdd     | short to Vdd           | short
+ * | shot to GND      | open                   | open
+ * | open             | shot to GND            | open
+ * | short to GND     | shot to GND            | short
+ * | connected to active link partner (master) | shot and open
+ */
+static int tja11xx_cable_test_report_trans(u32 result)
+{
+       u32 mask = MII_EXTSTAT_SHORT_DETECT | MII_EXTSTAT_OPEN_DETECT;
+
+       if ((result & mask) == mask) {
+               /* connected to active link partner (master) */
+               return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
+       } else if ((result & mask) == 0) {
+               return ETHTOOL_A_CABLE_RESULT_CODE_OK;
+       } else if (result & MII_EXTSTAT_SHORT_DETECT) {
+               return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
+       } else if (result & MII_EXTSTAT_OPEN_DETECT) {
+               return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
+       } else {
+               return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
+       }
+}
+
+static int tja11xx_cable_test_report(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = phy_read(phydev, MII_EXTSTAT);
+       if (ret < 0)
+               return ret;
+
+       ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
+                               tja11xx_cable_test_report_trans(ret));
+
+       return 0;
+}
+
+static int tja11xx_cable_test_get_status(struct phy_device *phydev,
+                                        bool *finished)
+{
+       int ret;
+
+       *finished = false;
+
+       ret = phy_read(phydev, MII_ECTRL);
+       if (ret < 0)
+               return ret;
+
+       if (!(ret & MII_ECTRL_CABLE_TEST)) {
+               *finished = true;
+
+               ret = phy_set_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
+               if (ret)
+                       return ret;
+
+               return tja11xx_cable_test_report(phydev);
+       }
+
+       return 0;
+}
+
 static struct phy_driver tja11xx_driver[] = {
        {
                PHY_ID_MATCH_MODEL(PHY_ID_TJA1100),
        }, {
                .name           = "NXP TJA1102 Port 0",
                .features       = PHY_BASIC_T1_FEATURES,
+               .flags          = PHY_POLL_CABLE_TEST,
                .probe          = tja1102_p0_probe,
                .soft_reset     = tja11xx_soft_reset,
                .config_aneg    = tja11xx_config_aneg,
                .get_stats      = tja11xx_get_stats,
                .ack_interrupt  = tja11xx_ack_interrupt,
                .config_intr    = tja11xx_config_intr,
-
+               .cable_test_start = tja11xx_cable_test_start,
+               .cable_test_get_status = tja11xx_cable_test_get_status,
        }, {
                .name           = "NXP TJA1102 Port 1",
                .features       = PHY_BASIC_T1_FEATURES,
+               .flags          = PHY_POLL_CABLE_TEST,
                /* currently no probe for Port 1 is need */
                .soft_reset     = tja11xx_soft_reset,
                .config_aneg    = tja11xx_config_aneg,
                .get_stats      = tja11xx_get_stats,
                .ack_interrupt  = tja11xx_ack_interrupt,
                .config_intr    = tja11xx_config_intr,
+               .cable_test_start = tja11xx_cable_test_start,
+               .cable_test_get_status = tja11xx_cable_test_get_status,
        }
 };