@@ -448,6 +448,17 @@ struct kszphy_priv {
448448 struct kszphy_phy_stats phy_stats ;
449449};
450450
451+ struct lan8842_phy_stats {
452+ u64 rx_packets ;
453+ u64 rx_errors ;
454+ u64 tx_packets ;
455+ u64 tx_errors ;
456+ };
457+
458+ struct lan8842_priv {
459+ struct lan8842_phy_stats phy_stats ;
460+ };
461+
451462static const struct kszphy_type lan8814_type = {
452463 .led_mode_reg = ~LAN8814_LED_CTRL_1 ,
453464 .cable_diag_reg = LAN8814_CABLE_DIAG ,
@@ -5768,6 +5779,188 @@ static int ksz9131_resume(struct phy_device *phydev)
57685779 return kszphy_resume (phydev );
57695780}
57705781
5782+ #define LAN8842_SELF_TEST 14 /* 0x0e */
5783+ #define LAN8842_SELF_TEST_RX_CNT_ENA BIT(8)
5784+ #define LAN8842_SELF_TEST_TX_CNT_ENA BIT(4)
5785+
5786+ static int lan8842_probe (struct phy_device * phydev )
5787+ {
5788+ struct lan8842_priv * priv ;
5789+ int ret ;
5790+
5791+ priv = devm_kzalloc (& phydev -> mdio .dev , sizeof (* priv ), GFP_KERNEL );
5792+ if (!priv )
5793+ return - ENOMEM ;
5794+
5795+ phydev -> priv = priv ;
5796+
5797+ /* Similar to lan8814 this PHY has a pin which needs to be pulled down
5798+ * to enable to pass any traffic through it. Therefore use the same
5799+ * function as lan8814
5800+ */
5801+ ret = lan8814_release_coma_mode (phydev );
5802+ if (ret )
5803+ return ret ;
5804+
5805+ /* Enable to count the RX and TX packets */
5806+ ret = lanphy_write_page_reg (phydev , LAN8814_PAGE_PCS_DIGITAL ,
5807+ LAN8842_SELF_TEST ,
5808+ LAN8842_SELF_TEST_RX_CNT_ENA |
5809+ LAN8842_SELF_TEST_TX_CNT_ENA );
5810+ if (ret < 0 )
5811+ return ret ;
5812+
5813+ return 0 ;
5814+ }
5815+
5816+ static int lan8842_config_init (struct phy_device * phydev )
5817+ {
5818+ int ret ;
5819+
5820+ /* Reset the PHY */
5821+ ret = lanphy_modify_page_reg (phydev , LAN8814_PAGE_COMMON_REGS ,
5822+ LAN8814_QSGMII_SOFT_RESET ,
5823+ LAN8814_QSGMII_SOFT_RESET_BIT ,
5824+ LAN8814_QSGMII_SOFT_RESET_BIT );
5825+ if (ret < 0 )
5826+ return ret ;
5827+
5828+ /* To allow the PHY to control the LEDs the GPIOs of the PHY should have
5829+ * a function mode and not the GPIO. Apparently by default the value is
5830+ * GPIO and not function even though the datasheet it says that it is
5831+ * function. Therefore set this value.
5832+ */
5833+ return lanphy_write_page_reg (phydev , LAN8814_PAGE_COMMON_REGS ,
5834+ LAN8814_GPIO_EN2 , 0 );
5835+ }
5836+
5837+ #define LAN8842_INTR_CTRL_REG 52 /* 0x34 */
5838+
5839+ static int lan8842_config_intr (struct phy_device * phydev )
5840+ {
5841+ int err ;
5842+
5843+ lanphy_write_page_reg (phydev , LAN8814_PAGE_COMMON_REGS ,
5844+ LAN8842_INTR_CTRL_REG ,
5845+ LAN8814_INTR_CTRL_REG_INTR_ENABLE );
5846+
5847+ /* enable / disable interrupts */
5848+ if (phydev -> interrupts == PHY_INTERRUPT_ENABLED ) {
5849+ err = lan8814_ack_interrupt (phydev );
5850+ if (err )
5851+ return err ;
5852+
5853+ err = phy_write (phydev , LAN8814_INTC , LAN8814_INT_LINK );
5854+ } else {
5855+ err = phy_write (phydev , LAN8814_INTC , 0 );
5856+ if (err )
5857+ return err ;
5858+
5859+ err = lan8814_ack_interrupt (phydev );
5860+ }
5861+
5862+ return err ;
5863+ }
5864+
5865+ static unsigned int lan8842_inband_caps (struct phy_device * phydev ,
5866+ phy_interface_t interface )
5867+ {
5868+ /* Inband configuration can be enabled or disabled using the registers
5869+ * PCS1G_ANEG_CONFIG.
5870+ */
5871+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE ;
5872+ }
5873+
5874+ static int lan8842_config_inband (struct phy_device * phydev , unsigned int modes )
5875+ {
5876+ bool enable ;
5877+
5878+ if (modes == LINK_INBAND_DISABLE )
5879+ enable = false;
5880+ else
5881+ enable = true;
5882+
5883+ /* Disable or enable in-band autoneg with PCS Host side
5884+ * It has the same address as lan8814
5885+ */
5886+ return lanphy_modify_page_reg (phydev , LAN8814_PAGE_PORT_REGS ,
5887+ LAN8814_QSGMII_PCS1G_ANEG_CONFIG ,
5888+ LAN8814_QSGMII_PCS1G_ANEG_CONFIG_ANEG_ENA ,
5889+ enable ? LAN8814_QSGMII_PCS1G_ANEG_CONFIG_ANEG_ENA : 0 );
5890+ }
5891+
5892+ static irqreturn_t lan8842_handle_interrupt (struct phy_device * phydev )
5893+ {
5894+ int ret = IRQ_NONE ;
5895+ int irq_status ;
5896+
5897+ irq_status = phy_read (phydev , LAN8814_INTS );
5898+ if (irq_status < 0 ) {
5899+ phy_error (phydev );
5900+ return IRQ_NONE ;
5901+ }
5902+
5903+ if (irq_status & LAN8814_INT_LINK ) {
5904+ phy_trigger_machine (phydev );
5905+ ret = IRQ_HANDLED ;
5906+ }
5907+
5908+ return ret ;
5909+ }
5910+
5911+ static u64 lan8842_get_stat (struct phy_device * phydev , int count , int * regs )
5912+ {
5913+ u64 ret = 0 ;
5914+ int val ;
5915+
5916+ for (int j = 0 ; j < count ; ++ j ) {
5917+ val = lanphy_read_page_reg (phydev , LAN8814_PAGE_PCS_DIGITAL ,
5918+ regs [j ]);
5919+ if (val < 0 )
5920+ return U64_MAX ;
5921+
5922+ ret <<= 16 ;
5923+ ret += val ;
5924+ }
5925+ return ret ;
5926+ }
5927+
5928+ static int lan8842_update_stats (struct phy_device * phydev )
5929+ {
5930+ struct lan8842_priv * priv = phydev -> priv ;
5931+ int rx_packets_regs [] = {88 , 61 , 60 };
5932+ int rx_errors_regs [] = {63 , 62 };
5933+ int tx_packets_regs [] = {89 , 85 , 84 };
5934+ int tx_errors_regs [] = {87 , 86 };
5935+
5936+ priv -> phy_stats .rx_packets = lan8842_get_stat (phydev ,
5937+ ARRAY_SIZE (rx_packets_regs ),
5938+ rx_packets_regs );
5939+ priv -> phy_stats .rx_errors = lan8842_get_stat (phydev ,
5940+ ARRAY_SIZE (rx_errors_regs ),
5941+ rx_errors_regs );
5942+ priv -> phy_stats .tx_packets = lan8842_get_stat (phydev ,
5943+ ARRAY_SIZE (tx_packets_regs ),
5944+ tx_packets_regs );
5945+ priv -> phy_stats .tx_errors = lan8842_get_stat (phydev ,
5946+ ARRAY_SIZE (tx_errors_regs ),
5947+ tx_errors_regs );
5948+
5949+ return 0 ;
5950+ }
5951+
5952+ static void lan8842_get_phy_stats (struct phy_device * phydev ,
5953+ struct ethtool_eth_phy_stats * eth_stats ,
5954+ struct ethtool_phy_stats * stats )
5955+ {
5956+ struct lan8842_priv * priv = phydev -> priv ;
5957+
5958+ stats -> rx_packets = priv -> phy_stats .rx_packets ;
5959+ stats -> rx_errors = priv -> phy_stats .rx_errors ;
5960+ stats -> tx_packets = priv -> phy_stats .tx_packets ;
5961+ stats -> tx_errors = priv -> phy_stats .tx_errors ;
5962+ }
5963+
57715964static struct phy_driver ksphy_driver [] = {
57725965{
57735966 PHY_ID_MATCH_MODEL (PHY_ID_KS8737 ),
@@ -5987,6 +6180,21 @@ static struct phy_driver ksphy_driver[] = {
59876180 .resume = lan8841_resume ,
59886181 .cable_test_start = lan8814_cable_test_start ,
59896182 .cable_test_get_status = ksz886x_cable_test_get_status ,
6183+ }, {
6184+ PHY_ID_MATCH_MODEL (PHY_ID_LAN8842 ),
6185+ .name = "Microchip LAN8842 Gigabit PHY" ,
6186+ .flags = PHY_POLL_CABLE_TEST ,
6187+ .driver_data = & lan8814_type ,
6188+ .probe = lan8842_probe ,
6189+ .config_init = lan8842_config_init ,
6190+ .config_intr = lan8842_config_intr ,
6191+ .inband_caps = lan8842_inband_caps ,
6192+ .config_inband = lan8842_config_inband ,
6193+ .handle_interrupt = lan8842_handle_interrupt ,
6194+ .get_phy_stats = lan8842_get_phy_stats ,
6195+ .update_stats = lan8842_update_stats ,
6196+ .cable_test_start = lan8814_cable_test_start ,
6197+ .cable_test_get_status = ksz886x_cable_test_get_status ,
59906198}, {
59916199 PHY_ID_MATCH_MODEL (PHY_ID_KSZ9131 ),
59926200 .name = "Microchip KSZ9131 Gigabit PHY" ,
@@ -6082,6 +6290,7 @@ static const struct mdio_device_id __maybe_unused micrel_tbl[] = {
60826290 { PHY_ID_MATCH_MODEL (PHY_ID_LAN8814 ) },
60836291 { PHY_ID_MATCH_MODEL (PHY_ID_LAN8804 ) },
60846292 { PHY_ID_MATCH_MODEL (PHY_ID_LAN8841 ) },
6293+ { PHY_ID_MATCH_MODEL (PHY_ID_LAN8842 ) },
60856294 { }
60866295};
60876296
0 commit comments