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

Configure Feed

Select the types of activity you want to include in your feed.

net: phy: micrel: Add support for lan9645x internal phy

LAN9645X is a family of switch chips with 5 internal copper phys. The
internal PHY is based on parts of LAN8832. This 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.

Add support for the internal PHY of the lan9645x chip family.

Reviewed-by: Steen Hegelund <Steen.Hegelund@microchip.com>
Reviewed-by: Daniel Machon <daniel.machon@microchip.com>
Signed-off-by: Jens Emil Schulz Østergaard <jensemil.schulzostergaard@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20260226-phy_micrel_add_support_for_lan9645x_internal_phy-v3-1-1fe82379962b@microchip.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Jens Emil Schulz Østergaard and committed by
Jakub Kicinski
11c0663a fd6dad4e

+153
+152
drivers/net/phy/micrel.c
··· 6523 6523 stats->tx_errors = priv->phy_stats.tx_errors; 6524 6524 } 6525 6525 6526 + #define LAN9645X_CTRL_REG 0x1f 6527 + #define LAN9645X_CTRL_REG_SW_SOFT_RST BIT(1) 6528 + 6529 + #define LAN9645X_DAC_ICAS_AMP_POWER_DOWN 0x47 6530 + #define LAN9645X_BTRX_QBIAS_POWER_DOWN 0x46 6531 + #define LAN9645X_TX_LOW_I_CH_CD_POWER_MGMT 0x45 6532 + #define LAN9645X_TX_LOW_I_CH_B_POWER_MGMT 0x44 6533 + #define LAN9645X_TX_LOW_I_CH_A_POWER_MGMT 0x43 6534 + 6535 + static const struct lanphy_reg_data force_dac_tx_errata[] = { 6536 + /* Force channel A/B/C/D TX on */ 6537 + { LAN8814_PAGE_POWER_REGS, 6538 + LAN9645X_DAC_ICAS_AMP_POWER_DOWN, 6539 + 0 }, 6540 + /* Force channel A/B/C/D QBias on */ 6541 + { LAN8814_PAGE_POWER_REGS, 6542 + LAN9645X_BTRX_QBIAS_POWER_DOWN, 6543 + 0xaa }, 6544 + /* Tx low I on channel C/D overwrite */ 6545 + { LAN8814_PAGE_POWER_REGS, 6546 + LAN9645X_TX_LOW_I_CH_CD_POWER_MGMT, 6547 + 0xbfff }, 6548 + /* Channel B low I overwrite */ 6549 + { LAN8814_PAGE_POWER_REGS, 6550 + LAN9645X_TX_LOW_I_CH_B_POWER_MGMT, 6551 + 0xabbf }, 6552 + /* Channel A low I overwrite */ 6553 + { LAN8814_PAGE_POWER_REGS, 6554 + LAN9645X_TX_LOW_I_CH_A_POWER_MGMT, 6555 + 0xbd3f }, 6556 + }; 6557 + 6558 + static int lan9645x_config_init(struct phy_device *phydev) 6559 + { 6560 + int ret; 6561 + 6562 + /* Apply erratas from previous generations. */ 6563 + ret = lan8842_erratas(phydev); 6564 + if (ret < 0) 6565 + return ret; 6566 + 6567 + /* Apply errata for an issue where bringing a port down, can cause a few 6568 + * CRC errors for traffic flowing through adjacent ports. 6569 + */ 6570 + return lanphy_write_reg_data(phydev, force_dac_tx_errata, 6571 + ARRAY_SIZE(force_dac_tx_errata)); 6572 + } 6573 + 6574 + static int lan9645x_suspend(struct phy_device *phydev) 6575 + { 6576 + int ret, val; 6577 + 6578 + /* Force link down before software power down (SPD), by doing software 6579 + * soft reset. This resets the PHY, but keeps all register configuration 6580 + * intact. The bit self clears. 6581 + * 6582 + * This is needed as a workaround for an issue where performing SPD on a 6583 + * port can bring adjacent ports down, when there is traffic flowing 6584 + * through the ports. 6585 + */ 6586 + ret = phy_set_bits(phydev, LAN9645X_CTRL_REG, 6587 + LAN9645X_CTRL_REG_SW_SOFT_RST); 6588 + if (ret) 6589 + return ret; 6590 + 6591 + ret = phy_read_poll_timeout(phydev, LAN9645X_CTRL_REG, val, 6592 + !(val & LAN9645X_CTRL_REG_SW_SOFT_RST), 6593 + 3000, 100000, true); 6594 + if (ret) 6595 + return ret; 6596 + 6597 + return genphy_suspend(phydev); 6598 + } 6599 + 6600 + static int lan9645x_config_intr(struct phy_device *phydev) 6601 + { 6602 + int err; 6603 + 6604 + /* enable / disable interrupts */ 6605 + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 6606 + /* This is an internal PHY of lan9645x and is not possible to 6607 + * change the polarity of irq sources in the OIC (CPU_INTR) 6608 + * found in lan9645x. Therefore change the polarity of the 6609 + * interrupt in the PHY from being active low instead of active 6610 + * high. 6611 + */ 6612 + err = phy_write(phydev, LAN8804_CONTROL, 6613 + LAN8804_CONTROL_INTR_POLARITY); 6614 + if (err) 6615 + return err; 6616 + 6617 + /* By default interrupt buffer is open-drain in which case the 6618 + * interrupt can be active only low. Therefore change the 6619 + * interrupt buffer to be push-pull to be able to change 6620 + * interrupt polarity. 6621 + */ 6622 + err = phy_write(phydev, LAN8804_OUTPUT_CONTROL, 6623 + LAN8804_OUTPUT_CONTROL_INTR_BUFFER); 6624 + if (err) 6625 + return err; 6626 + 6627 + err = lan8814_ack_interrupt(phydev); 6628 + if (err) 6629 + return err; 6630 + 6631 + err = phy_write(phydev, LAN8814_INTC, 6632 + LAN8814_INT_LINK | LAN8814_INT_FLF); 6633 + } else { 6634 + err = phy_write(phydev, LAN8814_INTC, 0); 6635 + if (err) 6636 + return err; 6637 + 6638 + err = lan8814_ack_interrupt(phydev); 6639 + } 6640 + 6641 + return err; 6642 + } 6643 + 6644 + static irqreturn_t lan9645x_handle_interrupt(struct phy_device *phydev) 6645 + { 6646 + int status; 6647 + 6648 + status = phy_read(phydev, LAN8814_INTS); 6649 + if (status < 0) { 6650 + phy_error(phydev); 6651 + return IRQ_NONE; 6652 + } 6653 + 6654 + if (status & (LAN8814_INT_LINK | LAN8814_INT_FLF)) { 6655 + phy_trigger_machine(phydev); 6656 + return IRQ_HANDLED; 6657 + } 6658 + 6659 + return IRQ_NONE; 6660 + } 6661 + 6526 6662 static struct phy_driver ksphy_driver[] = { 6527 6663 { 6528 6664 PHY_ID_MATCH_MODEL(PHY_ID_KS8737), ··· 6898 6762 .cable_test_start = lan8814_cable_test_start, 6899 6763 .cable_test_get_status = ksz886x_cable_test_get_status, 6900 6764 }, { 6765 + PHY_ID_MATCH_MODEL(PHY_ID_LAN9645X), 6766 + .name = "Microchip LAN9645X Gigabit PHY", 6767 + .config_init = lan9645x_config_init, 6768 + .driver_data = &ksz9021_type, 6769 + .probe = kszphy_probe, 6770 + .soft_reset = genphy_soft_reset, 6771 + .suspend = lan9645x_suspend, 6772 + .resume = genphy_resume, 6773 + .config_intr = lan9645x_config_intr, 6774 + .handle_interrupt = lan9645x_handle_interrupt, 6775 + .get_tunable = lan8842_get_tunable, 6776 + .set_tunable = lan8842_set_tunable, 6777 + .get_phy_stats = lan8842_get_phy_stats, 6778 + .update_stats = lan8842_update_stats, 6779 + }, { 6901 6780 PHY_ID_MATCH_MODEL(PHY_ID_KSZ9131), 6902 6781 .name = "Microchip KSZ9131 Gigabit PHY", 6903 6782 /* PHY_GBIT_FEATURES */ ··· 7010 6859 { PHY_ID_MATCH_MODEL(PHY_ID_LAN8804) }, 7011 6860 { PHY_ID_MATCH_MODEL(PHY_ID_LAN8841) }, 7012 6861 { PHY_ID_MATCH_MODEL(PHY_ID_LAN8842) }, 6862 + { PHY_ID_MATCH_MODEL(PHY_ID_LAN9645X) }, 7013 6863 { } 7014 6864 }; 7015 6865
+1
include/linux/micrel_phy.h
··· 33 33 #define PHY_ID_LAN8804 0x00221670 34 34 #define PHY_ID_LAN8841 0x00221650 35 35 #define PHY_ID_LAN8842 0x002216C0 36 + #define PHY_ID_LAN9645X 0x002216D0 36 37 37 38 #define PHY_ID_KSZ886X 0x00221430 38 39 #define PHY_ID_KSZ8863 0x00221435