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

net: phy: micrel: Add support for lan8842

The LAN8842 is a low-power, single port triple-speed (10BASE-T/ 100BASE-TX/
1000BASE-T) ethernet physical layer transceiver (PHY) that supports
transmission and reception of data on standard CAT-5, as well as CAT-5e and
CAT-6, Unshielded Twisted Pair (UTP) cables.

The LAN8842 supports industry-standard SGMII (Serial Gigabit Media
Independent Interface) providing chip-to-chip connection to a Gigabit
Ethernet MAC using a single serialized link (differential pair) in each
direction.

There are 2 variants of the lan8842. The one that supports timestamping
(lan8842) and one that doesn't have timestamping (lan8832).

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20250818075121.1298170-5-horatiu.vultur@microchip.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Horatiu Vultur and committed by
Paolo Abeni
5a774b64 d471793a

+210
+209
drivers/net/phy/micrel.c
··· 448 448 struct kszphy_phy_stats phy_stats; 449 449 }; 450 450 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 + 451 462 static const struct kszphy_type lan8814_type = { 452 463 .led_mode_reg = ~LAN8814_LED_CTRL_1, 453 464 .cable_diag_reg = LAN8814_CABLE_DIAG, ··· 5779 5768 return kszphy_resume(phydev); 5780 5769 } 5781 5770 5771 + #define LAN8842_SELF_TEST 14 /* 0x0e */ 5772 + #define LAN8842_SELF_TEST_RX_CNT_ENA BIT(8) 5773 + #define LAN8842_SELF_TEST_TX_CNT_ENA BIT(4) 5774 + 5775 + static int lan8842_probe(struct phy_device *phydev) 5776 + { 5777 + struct lan8842_priv *priv; 5778 + int ret; 5779 + 5780 + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 5781 + if (!priv) 5782 + return -ENOMEM; 5783 + 5784 + phydev->priv = priv; 5785 + 5786 + /* Similar to lan8814 this PHY has a pin which needs to be pulled down 5787 + * to enable to pass any traffic through it. Therefore use the same 5788 + * function as lan8814 5789 + */ 5790 + ret = lan8814_release_coma_mode(phydev); 5791 + if (ret) 5792 + return ret; 5793 + 5794 + /* Enable to count the RX and TX packets */ 5795 + ret = lanphy_write_page_reg(phydev, LAN8814_PAGE_PCS_DIGITAL, 5796 + LAN8842_SELF_TEST, 5797 + LAN8842_SELF_TEST_RX_CNT_ENA | 5798 + LAN8842_SELF_TEST_TX_CNT_ENA); 5799 + if (ret < 0) 5800 + return ret; 5801 + 5802 + return 0; 5803 + } 5804 + 5805 + static int lan8842_config_init(struct phy_device *phydev) 5806 + { 5807 + int ret; 5808 + 5809 + /* Reset the PHY */ 5810 + ret = lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, 5811 + LAN8814_QSGMII_SOFT_RESET, 5812 + LAN8814_QSGMII_SOFT_RESET_BIT, 5813 + LAN8814_QSGMII_SOFT_RESET_BIT); 5814 + if (ret < 0) 5815 + return ret; 5816 + 5817 + /* To allow the PHY to control the LEDs the GPIOs of the PHY should have 5818 + * a function mode and not the GPIO. Apparently by default the value is 5819 + * GPIO and not function even though the datasheet it says that it is 5820 + * function. Therefore set this value. 5821 + */ 5822 + return lanphy_write_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, 5823 + LAN8814_GPIO_EN2, 0); 5824 + } 5825 + 5826 + #define LAN8842_INTR_CTRL_REG 52 /* 0x34 */ 5827 + 5828 + static int lan8842_config_intr(struct phy_device *phydev) 5829 + { 5830 + int err; 5831 + 5832 + lanphy_write_page_reg(phydev, LAN8814_PAGE_COMMON_REGS, 5833 + LAN8842_INTR_CTRL_REG, 5834 + LAN8814_INTR_CTRL_REG_INTR_ENABLE); 5835 + 5836 + /* enable / disable interrupts */ 5837 + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 5838 + err = lan8814_ack_interrupt(phydev); 5839 + if (err) 5840 + return err; 5841 + 5842 + err = phy_write(phydev, LAN8814_INTC, LAN8814_INT_LINK); 5843 + } else { 5844 + err = phy_write(phydev, LAN8814_INTC, 0); 5845 + if (err) 5846 + return err; 5847 + 5848 + err = lan8814_ack_interrupt(phydev); 5849 + } 5850 + 5851 + return err; 5852 + } 5853 + 5854 + static unsigned int lan8842_inband_caps(struct phy_device *phydev, 5855 + phy_interface_t interface) 5856 + { 5857 + /* Inband configuration can be enabled or disabled using the registers 5858 + * PCS1G_ANEG_CONFIG. 5859 + */ 5860 + return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; 5861 + } 5862 + 5863 + static int lan8842_config_inband(struct phy_device *phydev, unsigned int modes) 5864 + { 5865 + bool enable; 5866 + 5867 + if (modes == LINK_INBAND_DISABLE) 5868 + enable = false; 5869 + else 5870 + enable = true; 5871 + 5872 + /* Disable or enable in-band autoneg with PCS Host side 5873 + * It has the same address as lan8814 5874 + */ 5875 + return lanphy_modify_page_reg(phydev, LAN8814_PAGE_PORT_REGS, 5876 + LAN8814_QSGMII_PCS1G_ANEG_CONFIG, 5877 + LAN8814_QSGMII_PCS1G_ANEG_CONFIG_ANEG_ENA, 5878 + enable ? LAN8814_QSGMII_PCS1G_ANEG_CONFIG_ANEG_ENA : 0); 5879 + } 5880 + 5881 + static irqreturn_t lan8842_handle_interrupt(struct phy_device *phydev) 5882 + { 5883 + int ret = IRQ_NONE; 5884 + int irq_status; 5885 + 5886 + irq_status = phy_read(phydev, LAN8814_INTS); 5887 + if (irq_status < 0) { 5888 + phy_error(phydev); 5889 + return IRQ_NONE; 5890 + } 5891 + 5892 + if (irq_status & LAN8814_INT_LINK) { 5893 + phy_trigger_machine(phydev); 5894 + ret = IRQ_HANDLED; 5895 + } 5896 + 5897 + return ret; 5898 + } 5899 + 5900 + static u64 lan8842_get_stat(struct phy_device *phydev, int count, int *regs) 5901 + { 5902 + u64 ret = 0; 5903 + int val; 5904 + 5905 + for (int j = 0; j < count; ++j) { 5906 + val = lanphy_read_page_reg(phydev, LAN8814_PAGE_PCS_DIGITAL, 5907 + regs[j]); 5908 + if (val < 0) 5909 + return U64_MAX; 5910 + 5911 + ret <<= 16; 5912 + ret += val; 5913 + } 5914 + return ret; 5915 + } 5916 + 5917 + static int lan8842_update_stats(struct phy_device *phydev) 5918 + { 5919 + struct lan8842_priv *priv = phydev->priv; 5920 + int rx_packets_regs[] = {88, 61, 60}; 5921 + int rx_errors_regs[] = {63, 62}; 5922 + int tx_packets_regs[] = {89, 85, 84}; 5923 + int tx_errors_regs[] = {87, 86}; 5924 + 5925 + priv->phy_stats.rx_packets = lan8842_get_stat(phydev, 5926 + ARRAY_SIZE(rx_packets_regs), 5927 + rx_packets_regs); 5928 + priv->phy_stats.rx_errors = lan8842_get_stat(phydev, 5929 + ARRAY_SIZE(rx_errors_regs), 5930 + rx_errors_regs); 5931 + priv->phy_stats.tx_packets = lan8842_get_stat(phydev, 5932 + ARRAY_SIZE(tx_packets_regs), 5933 + tx_packets_regs); 5934 + priv->phy_stats.tx_errors = lan8842_get_stat(phydev, 5935 + ARRAY_SIZE(tx_errors_regs), 5936 + tx_errors_regs); 5937 + 5938 + return 0; 5939 + } 5940 + 5941 + static void lan8842_get_phy_stats(struct phy_device *phydev, 5942 + struct ethtool_eth_phy_stats *eth_stats, 5943 + struct ethtool_phy_stats *stats) 5944 + { 5945 + struct lan8842_priv *priv = phydev->priv; 5946 + 5947 + stats->rx_packets = priv->phy_stats.rx_packets; 5948 + stats->rx_errors = priv->phy_stats.rx_errors; 5949 + stats->tx_packets = priv->phy_stats.tx_packets; 5950 + stats->tx_errors = priv->phy_stats.tx_errors; 5951 + } 5952 + 5782 5953 static struct phy_driver ksphy_driver[] = { 5783 5954 { 5784 5955 PHY_ID_MATCH_MODEL(PHY_ID_KS8737), ··· 6181 5988 .cable_test_start = lan8814_cable_test_start, 6182 5989 .cable_test_get_status = ksz886x_cable_test_get_status, 6183 5990 }, { 5991 + PHY_ID_MATCH_MODEL(PHY_ID_LAN8842), 5992 + .name = "Microchip LAN8842 Gigabit PHY", 5993 + .flags = PHY_POLL_CABLE_TEST, 5994 + .driver_data = &lan8814_type, 5995 + .probe = lan8842_probe, 5996 + .config_init = lan8842_config_init, 5997 + .config_intr = lan8842_config_intr, 5998 + .inband_caps = lan8842_inband_caps, 5999 + .config_inband = lan8842_config_inband, 6000 + .handle_interrupt = lan8842_handle_interrupt, 6001 + .get_phy_stats = lan8842_get_phy_stats, 6002 + .update_stats = lan8842_update_stats, 6003 + .cable_test_start = lan8814_cable_test_start, 6004 + .cable_test_get_status = ksz886x_cable_test_get_status, 6005 + }, { 6184 6006 PHY_ID_MATCH_MODEL(PHY_ID_KSZ9131), 6185 6007 .name = "Microchip KSZ9131 Gigabit PHY", 6186 6008 /* PHY_GBIT_FEATURES */ ··· 6290 6082 { PHY_ID_MATCH_MODEL(PHY_ID_LAN8814) }, 6291 6083 { PHY_ID_MATCH_MODEL(PHY_ID_LAN8804) }, 6292 6084 { PHY_ID_MATCH_MODEL(PHY_ID_LAN8841) }, 6085 + { PHY_ID_MATCH_MODEL(PHY_ID_LAN8842) }, 6293 6086 { } 6294 6087 }; 6295 6088
+1
include/linux/micrel_phy.h
··· 32 32 #define PHY_ID_LAN8814 0x00221660 33 33 #define PHY_ID_LAN8804 0x00221670 34 34 #define PHY_ID_LAN8841 0x00221650 35 + #define PHY_ID_LAN8842 0x002216C0 35 36 36 37 #define PHY_ID_KSZ886X 0x00221430 37 38 #define PHY_ID_KSZ8863 0x00221435