Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for the Texas Instruments DP83848 PHY
0004  *
0005  * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/phy.h>
0010 
0011 #define TI_DP83848C_PHY_ID      0x20005ca0
0012 #define TI_DP83620_PHY_ID       0x20005ce0
0013 #define NS_DP83848C_PHY_ID      0x20005c90
0014 #define TLK10X_PHY_ID           0x2000a210
0015 
0016 /* Registers */
0017 #define DP83848_MICR            0x11 /* MII Interrupt Control Register */
0018 #define DP83848_MISR            0x12 /* MII Interrupt Status Register */
0019 
0020 /* MICR Register Fields */
0021 #define DP83848_MICR_INT_OE     BIT(0) /* Interrupt Output Enable */
0022 #define DP83848_MICR_INTEN      BIT(1) /* Interrupt Enable */
0023 
0024 /* MISR Register Fields */
0025 #define DP83848_MISR_RHF_INT_EN     BIT(0) /* Receive Error Counter */
0026 #define DP83848_MISR_FHF_INT_EN     BIT(1) /* False Carrier Counter */
0027 #define DP83848_MISR_ANC_INT_EN     BIT(2) /* Auto-negotiation complete */
0028 #define DP83848_MISR_DUP_INT_EN     BIT(3) /* Duplex Status */
0029 #define DP83848_MISR_SPD_INT_EN     BIT(4) /* Speed status */
0030 #define DP83848_MISR_LINK_INT_EN    BIT(5) /* Link status */
0031 #define DP83848_MISR_ED_INT_EN      BIT(6) /* Energy detect */
0032 #define DP83848_MISR_LQM_INT_EN     BIT(7) /* Link Quality Monitor */
0033 
0034 #define DP83848_INT_EN_MASK     \
0035     (DP83848_MISR_ANC_INT_EN |  \
0036      DP83848_MISR_DUP_INT_EN |  \
0037      DP83848_MISR_SPD_INT_EN |  \
0038      DP83848_MISR_LINK_INT_EN)
0039 
0040 #define DP83848_MISR_RHF_INT        BIT(8)
0041 #define DP83848_MISR_FHF_INT        BIT(9)
0042 #define DP83848_MISR_ANC_INT        BIT(10)
0043 #define DP83848_MISR_DUP_INT        BIT(11)
0044 #define DP83848_MISR_SPD_INT        BIT(12)
0045 #define DP83848_MISR_LINK_INT       BIT(13)
0046 #define DP83848_MISR_ED_INT     BIT(14)
0047 
0048 #define DP83848_INT_MASK        \
0049     (DP83848_MISR_ANC_INT | \
0050      DP83848_MISR_DUP_INT | \
0051      DP83848_MISR_SPD_INT | \
0052      DP83848_MISR_LINK_INT)
0053 
0054 static int dp83848_ack_interrupt(struct phy_device *phydev)
0055 {
0056     int err = phy_read(phydev, DP83848_MISR);
0057 
0058     return err < 0 ? err : 0;
0059 }
0060 
0061 static int dp83848_config_intr(struct phy_device *phydev)
0062 {
0063     int control, ret;
0064 
0065     control = phy_read(phydev, DP83848_MICR);
0066     if (control < 0)
0067         return control;
0068 
0069     if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
0070         ret = dp83848_ack_interrupt(phydev);
0071         if (ret)
0072             return ret;
0073 
0074         control |= DP83848_MICR_INT_OE;
0075         control |= DP83848_MICR_INTEN;
0076 
0077         ret = phy_write(phydev, DP83848_MISR, DP83848_INT_EN_MASK);
0078         if (ret < 0)
0079             return ret;
0080 
0081         ret = phy_write(phydev, DP83848_MICR, control);
0082     } else {
0083         control &= ~DP83848_MICR_INTEN;
0084         ret = phy_write(phydev, DP83848_MICR, control);
0085         if (ret)
0086             return ret;
0087 
0088         ret = dp83848_ack_interrupt(phydev);
0089     }
0090 
0091     return ret;
0092 }
0093 
0094 static irqreturn_t dp83848_handle_interrupt(struct phy_device *phydev)
0095 {
0096     int irq_status;
0097 
0098     irq_status = phy_read(phydev, DP83848_MISR);
0099     if (irq_status < 0) {
0100         phy_error(phydev);
0101         return IRQ_NONE;
0102     }
0103 
0104     if (!(irq_status & DP83848_INT_MASK))
0105         return IRQ_NONE;
0106 
0107     phy_trigger_machine(phydev);
0108 
0109     return IRQ_HANDLED;
0110 }
0111 
0112 static int dp83848_config_init(struct phy_device *phydev)
0113 {
0114     int val;
0115 
0116     /* DP83620 always reports Auto Negotiation Ability on BMSR. Instead,
0117      * we check initial value of BMCR Auto negotiation enable bit
0118      */
0119     val = phy_read(phydev, MII_BMCR);
0120     if (!(val & BMCR_ANENABLE))
0121         phydev->autoneg = AUTONEG_DISABLE;
0122 
0123     return 0;
0124 }
0125 
0126 static struct mdio_device_id __maybe_unused dp83848_tbl[] = {
0127     { TI_DP83848C_PHY_ID, 0xfffffff0 },
0128     { NS_DP83848C_PHY_ID, 0xfffffff0 },
0129     { TI_DP83620_PHY_ID, 0xfffffff0 },
0130     { TLK10X_PHY_ID, 0xfffffff0 },
0131     { }
0132 };
0133 MODULE_DEVICE_TABLE(mdio, dp83848_tbl);
0134 
0135 #define DP83848_PHY_DRIVER(_id, _name, _config_init)        \
0136     {                           \
0137         .phy_id     = _id,              \
0138         .phy_id_mask    = 0xfffffff0,           \
0139         .name       = _name,            \
0140         /* PHY_BASIC_FEATURES */            \
0141                                 \
0142         .soft_reset = genphy_soft_reset,        \
0143         .config_init    = _config_init,         \
0144         .suspend    = genphy_suspend,       \
0145         .resume     = genphy_resume,        \
0146                                 \
0147         /* IRQ related */               \
0148         .config_intr    = dp83848_config_intr,      \
0149         .handle_interrupt = dp83848_handle_interrupt,   \
0150     }
0151 
0152 static struct phy_driver dp83848_driver[] = {
0153     DP83848_PHY_DRIVER(TI_DP83848C_PHY_ID, "TI DP83848C 10/100 Mbps PHY",
0154                NULL),
0155     DP83848_PHY_DRIVER(NS_DP83848C_PHY_ID, "NS DP83848C 10/100 Mbps PHY",
0156                NULL),
0157     DP83848_PHY_DRIVER(TI_DP83620_PHY_ID, "TI DP83620 10/100 Mbps PHY",
0158                dp83848_config_init),
0159     DP83848_PHY_DRIVER(TLK10X_PHY_ID, "TI TLK10X 10/100 Mbps PHY",
0160                NULL),
0161 };
0162 module_phy_driver(dp83848_driver);
0163 
0164 MODULE_DESCRIPTION("Texas Instruments DP83848 PHY driver");
0165 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
0166 MODULE_LICENSE("GPL v2");