^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Driver for the Texas Instruments DP83848 PHY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #define TI_DP83848C_PHY_ID 0x20005ca0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #define TI_DP83620_PHY_ID 0x20005ce0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define NS_DP83848C_PHY_ID 0x20005c90
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define TLK10X_PHY_ID 0x2000a210
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) /* Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define DP83848_MICR 0x11 /* MII Interrupt Control Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define DP83848_MISR 0x12 /* MII Interrupt Status Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* MICR Register Fields */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define DP83848_MICR_INT_OE BIT(0) /* Interrupt Output Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define DP83848_MICR_INTEN BIT(1) /* Interrupt Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /* MISR Register Fields */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define DP83848_MISR_RHF_INT_EN BIT(0) /* Receive Error Counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define DP83848_MISR_FHF_INT_EN BIT(1) /* False Carrier Counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define DP83848_MISR_ANC_INT_EN BIT(2) /* Auto-negotiation complete */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define DP83848_MISR_DUP_INT_EN BIT(3) /* Duplex Status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define DP83848_MISR_SPD_INT_EN BIT(4) /* Speed status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define DP83848_MISR_LINK_INT_EN BIT(5) /* Link status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define DP83848_MISR_ED_INT_EN BIT(6) /* Energy detect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define DP83848_MISR_LQM_INT_EN BIT(7) /* Link Quality Monitor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define DP83848_INT_EN_MASK \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) (DP83848_MISR_ANC_INT_EN | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) DP83848_MISR_DUP_INT_EN | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) DP83848_MISR_SPD_INT_EN | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) DP83848_MISR_LINK_INT_EN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static int dp83848_ack_interrupt(struct phy_device *phydev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) int err = phy_read(phydev, DP83848_MISR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return err < 0 ? err : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static int dp83848_config_intr(struct phy_device *phydev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int control, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) control = phy_read(phydev, DP83848_MICR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (control < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) control |= DP83848_MICR_INT_OE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) control |= DP83848_MICR_INTEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) ret = phy_write(phydev, DP83848_MISR, DP83848_INT_EN_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) control &= ~DP83848_MICR_INTEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return phy_write(phydev, DP83848_MICR, control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static int dp83848_config_init(struct phy_device *phydev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* DP83620 always reports Auto Negotiation Ability on BMSR. Instead,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * we check initial value of BMCR Auto negotiation enable bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) val = phy_read(phydev, MII_BMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (!(val & BMCR_ANENABLE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) phydev->autoneg = AUTONEG_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static struct mdio_device_id __maybe_unused dp83848_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) { TI_DP83848C_PHY_ID, 0xfffffff0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) { NS_DP83848C_PHY_ID, 0xfffffff0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) { TI_DP83620_PHY_ID, 0xfffffff0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) { TLK10X_PHY_ID, 0xfffffff0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) MODULE_DEVICE_TABLE(mdio, dp83848_tbl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #define DP83848_PHY_DRIVER(_id, _name, _config_init) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .phy_id = _id, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .phy_id_mask = 0xfffffff0, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .name = _name, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* PHY_BASIC_FEATURES */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .soft_reset = genphy_soft_reset, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .config_init = _config_init, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .suspend = genphy_suspend, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .resume = genphy_resume, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /* IRQ related */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .ack_interrupt = dp83848_ack_interrupt, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .config_intr = dp83848_config_intr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static struct phy_driver dp83848_driver[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) DP83848_PHY_DRIVER(TI_DP83848C_PHY_ID, "TI DP83848C 10/100 Mbps PHY",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) DP83848_PHY_DRIVER(NS_DP83848C_PHY_ID, "NS DP83848C 10/100 Mbps PHY",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) DP83848_PHY_DRIVER(TI_DP83620_PHY_ID, "TI DP83620 10/100 Mbps PHY",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) dp83848_config_init),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) DP83848_PHY_DRIVER(TLK10X_PHY_ID, "TI TLK10X 10/100 Mbps PHY",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) module_phy_driver(dp83848_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) MODULE_DESCRIPTION("Texas Instruments DP83848 PHY driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) MODULE_LICENSE("GPL v2");