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

drivers/net/phy: add driver for the onsemi NCN26000 10BASE-T1S PHY

This patch adds support for the onsemi NCN26000 10BASE-T1S industrial
Ethernet PHY. The driver supports Point-to-Multipoint operation without
auto-negotiation and with link control handling. The PHY also features
PLCA for improving performance in P2MP mode.

Signed-off-by: Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Piergiorgio Beruto and committed by
David S. Miller
b53e7e8d 49332341

+186
+7
MAINTAINERS
··· 15584 15584 S: Maintained 15585 15585 F: arch/mips/boot/dts/ralink/omega2p.dts 15586 15586 15587 + ONSEMI ETHERNET PHY DRIVERS 15588 + M: Piergiorgio Beruto <piergiorgio.beruto@gmail.com> 15589 + L: netdev@vger.kernel.org 15590 + S: Supported 15591 + W: http://www.onsemi.com 15592 + F: drivers/net/phy/ncn* 15593 + 15587 15594 OP-TEE DRIVER 15588 15595 M: Jens Wiklander <jens.wiklander@linaro.org> 15589 15596 L: op-tee@lists.trustedfirmware.org
+7
drivers/net/phy/Kconfig
··· 277 277 help 278 278 Currently supports the NXP TJA1100 and TJA1101 PHY. 279 279 280 + config NCN26000_PHY 281 + tristate "Onsemi 10BASE-T1S Ethernet PHY" 282 + help 283 + Adds support for the onsemi 10BASE-T1S Ethernet PHY. 284 + Currently supports the NCN26000 10BASE-T1S Industrial PHY 285 + with MII interface. 286 + 280 287 config AT803X_PHY 281 288 tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs" 282 289 depends on REGULATOR
+1
drivers/net/phy/Makefile
··· 77 77 obj-$(CONFIG_MICROSEMI_PHY) += mscc/ 78 78 obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o 79 79 obj-$(CONFIG_NATIONAL_PHY) += national.o 80 + obj-$(CONFIG_NCN26000_PHY) += ncn26000.o 80 81 obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja11xx.o 81 82 obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o 82 83 obj-$(CONFIG_QSEMI_PHY) += qsemi.o
+171
drivers/net/phy/ncn26000.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2 + /* 3 + * Driver for the onsemi 10BASE-T1S NCN26000 PHYs family. 4 + * 5 + * Copyright 2022 onsemi 6 + */ 7 + #include <linux/kernel.h> 8 + #include <linux/bitfield.h> 9 + #include <linux/errno.h> 10 + #include <linux/init.h> 11 + #include <linux/module.h> 12 + #include <linux/mii.h> 13 + #include <linux/phy.h> 14 + 15 + #include "mdio-open-alliance.h" 16 + 17 + #define PHY_ID_NCN26000 0x180FF5A1 18 + 19 + #define NCN26000_REG_IRQ_CTL 16 20 + #define NCN26000_REG_IRQ_STATUS 17 21 + 22 + // the NCN26000 maps link_ctrl to BMCR_ANENABLE 23 + #define NCN26000_BCMR_LINK_CTRL_BIT BMCR_ANENABLE 24 + 25 + // the NCN26000 maps link_status to BMSR_ANEGCOMPLETE 26 + #define NCN26000_BMSR_LINK_STATUS_BIT BMSR_ANEGCOMPLETE 27 + 28 + #define NCN26000_IRQ_LINKST_BIT BIT(0) 29 + #define NCN26000_IRQ_PLCAST_BIT BIT(1) 30 + #define NCN26000_IRQ_LJABBER_BIT BIT(2) 31 + #define NCN26000_IRQ_RJABBER_BIT BIT(3) 32 + #define NCN26000_IRQ_PLCAREC_BIT BIT(4) 33 + #define NCN26000_IRQ_PHYSCOL_BIT BIT(5) 34 + #define NCN26000_IRQ_RESET_BIT BIT(15) 35 + 36 + #define TO_TMR_DEFAULT 32 37 + 38 + static int ncn26000_config_init(struct phy_device *phydev) 39 + { 40 + /* HW bug workaround: the default value of the PLCA TO_TIMER should be 41 + * 32, where the current version of NCN26000 reports 24. This will be 42 + * fixed in future PHY versions. For the time being, we force the 43 + * correct default here. 44 + */ 45 + return phy_write_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_TOTMR, 46 + TO_TMR_DEFAULT); 47 + } 48 + 49 + static int ncn26000_config_aneg(struct phy_device *phydev) 50 + { 51 + /* Note: the NCN26000 supports only P2MP link mode. Therefore, AN is not 52 + * supported. However, this function is invoked by phylib to enable the 53 + * PHY, regardless of the AN support. 54 + */ 55 + phydev->mdix_ctrl = ETH_TP_MDI_AUTO; 56 + phydev->mdix = ETH_TP_MDI; 57 + 58 + // bring up the link 59 + return phy_write(phydev, MII_BMCR, NCN26000_BCMR_LINK_CTRL_BIT); 60 + } 61 + 62 + static int ncn26000_read_status(struct phy_device *phydev) 63 + { 64 + /* The NCN26000 reports NCN26000_LINK_STATUS_BIT if the link status of 65 + * the PHY is up. It further reports the logical AND of the link status 66 + * and the PLCA status in the BMSR_LSTATUS bit. 67 + */ 68 + int ret; 69 + 70 + /* The link state is latched low so that momentary link 71 + * drops can be detected. Do not double-read the status 72 + * in polling mode to detect such short link drops except 73 + * the link was already down. 74 + */ 75 + if (!phy_polling_mode(phydev) || !phydev->link) { 76 + ret = phy_read(phydev, MII_BMSR); 77 + if (ret < 0) 78 + return ret; 79 + else if (ret & NCN26000_BMSR_LINK_STATUS_BIT) 80 + goto upd_link; 81 + } 82 + 83 + ret = phy_read(phydev, MII_BMSR); 84 + if (ret < 0) 85 + return ret; 86 + 87 + upd_link: 88 + // update link status 89 + if (ret & NCN26000_BMSR_LINK_STATUS_BIT) { 90 + phydev->link = 1; 91 + phydev->pause = 0; 92 + phydev->duplex = DUPLEX_HALF; 93 + phydev->speed = SPEED_10; 94 + } else { 95 + phydev->link = 0; 96 + phydev->duplex = DUPLEX_UNKNOWN; 97 + phydev->speed = SPEED_UNKNOWN; 98 + } 99 + 100 + return 0; 101 + } 102 + 103 + static irqreturn_t ncn26000_handle_interrupt(struct phy_device *phydev) 104 + { 105 + int ret; 106 + 107 + // read and aknowledge the IRQ status register 108 + ret = phy_read(phydev, NCN26000_REG_IRQ_STATUS); 109 + 110 + // check only link status changes 111 + if (ret < 0 || (ret & NCN26000_REG_IRQ_STATUS) == 0) 112 + return IRQ_NONE; 113 + 114 + phy_trigger_machine(phydev); 115 + return IRQ_HANDLED; 116 + } 117 + 118 + static int ncn26000_config_intr(struct phy_device *phydev) 119 + { 120 + int ret; 121 + u16 irqe; 122 + 123 + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 124 + // acknowledge IRQs 125 + ret = phy_read(phydev, NCN26000_REG_IRQ_STATUS); 126 + if (ret < 0) 127 + return ret; 128 + 129 + // get link status notifications 130 + irqe = NCN26000_IRQ_LINKST_BIT; 131 + } else { 132 + // disable all IRQs 133 + irqe = 0; 134 + } 135 + 136 + ret = phy_write(phydev, NCN26000_REG_IRQ_CTL, irqe); 137 + if (ret != 0) 138 + return ret; 139 + 140 + return 0; 141 + } 142 + 143 + static struct phy_driver ncn26000_driver[] = { 144 + { 145 + PHY_ID_MATCH_MODEL(PHY_ID_NCN26000), 146 + .name = "NCN26000", 147 + .features = PHY_BASIC_T1S_P2MP_FEATURES, 148 + .config_init = ncn26000_config_init, 149 + .config_intr = ncn26000_config_intr, 150 + .config_aneg = ncn26000_config_aneg, 151 + .read_status = ncn26000_read_status, 152 + .handle_interrupt = ncn26000_handle_interrupt, 153 + .get_plca_cfg = genphy_c45_plca_get_cfg, 154 + .set_plca_cfg = genphy_c45_plca_set_cfg, 155 + .get_plca_status = genphy_c45_plca_get_status, 156 + .soft_reset = genphy_soft_reset, 157 + }, 158 + }; 159 + 160 + module_phy_driver(ncn26000_driver); 161 + 162 + static struct mdio_device_id __maybe_unused ncn26000_tbl[] = { 163 + { PHY_ID_MATCH_MODEL(PHY_ID_NCN26000) }, 164 + { } 165 + }; 166 + 167 + MODULE_DEVICE_TABLE(mdio, ncn26000_tbl); 168 + 169 + MODULE_AUTHOR("Piergiorgio Beruto"); 170 + MODULE_DESCRIPTION("onsemi 10BASE-T1S PHY driver"); 171 + MODULE_LICENSE("Dual BSD/GPL");