Skip to content

Commit 5a774b6

Browse files
HoratiuVulturPaolo Abeni
authored andcommitted
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>
1 parent d471793 commit 5a774b6

File tree

2 files changed

+210
-0
lines changed

2 files changed

+210
-0
lines changed

drivers/net/phy/micrel.c

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
451462
static 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+
57715964
static 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

include/linux/micrel_phy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#define PHY_ID_LAN8814 0x00221660
3333
#define PHY_ID_LAN8804 0x00221670
3434
#define PHY_ID_LAN8841 0x00221650
35+
#define PHY_ID_LAN8842 0x002216C0
3536

3637
#define PHY_ID_KSZ886X 0x00221430
3738
#define PHY_ID_KSZ8863 0x00221435

0 commit comments

Comments
 (0)