1 /* 2 * Driver for the Texas Instruments DP83848 PHY 3 * 4 * Copyright (C) 2015 Texas Instruments Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 16 #include <linux/module.h> 17 #include <linux/phy.h> 18 19 #define DP83848_PHY_ID 0x20005c90 20 21 /* Registers */ 22 #define DP83848_MICR 0x11 23 #define DP83848_MISR 0x12 24 25 /* MICR Register Fields */ 26 #define DP83848_MICR_INT_OE BIT(0) /* Interrupt Output Enable */ 27 #define DP83848_MICR_INTEN BIT(1) /* Interrupt Enable */ 28 29 /* MISR Register Fields */ 30 #define DP83848_MISR_RHF_INT_EN BIT(0) /* Receive Error Counter */ 31 #define DP83848_MISR_FHF_INT_EN BIT(1) /* False Carrier Counter */ 32 #define DP83848_MISR_ANC_INT_EN BIT(2) /* Auto-negotiation complete */ 33 #define DP83848_MISR_DUP_INT_EN BIT(3) /* Duplex Status */ 34 #define DP83848_MISR_SPD_INT_EN BIT(4) /* Speed status */ 35 #define DP83848_MISR_LINK_INT_EN BIT(5) /* Link status */ 36 #define DP83848_MISR_ED_INT_EN BIT(6) /* Energy detect */ 37 #define DP83848_MISR_LQM_INT_EN BIT(7) /* Link Quality Monitor */ 38 39 static int dp83848_ack_interrupt(struct phy_device *phydev) 40 { 41 int err = phy_read(phydev, DP83848_MISR); 42 43 return err < 0 ? err : 0; 44 } 45 46 static int dp83848_config_intr(struct phy_device *phydev) 47 { 48 int err; 49 50 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 51 err = phy_write(phydev, DP83848_MICR, 52 DP83848_MICR_INT_OE | 53 DP83848_MICR_INTEN); 54 if (err < 0) 55 return err; 56 57 return phy_write(phydev, DP83848_MISR, 58 DP83848_MISR_ANC_INT_EN | 59 DP83848_MISR_DUP_INT_EN | 60 DP83848_MISR_SPD_INT_EN | 61 DP83848_MISR_LINK_INT_EN); 62 } 63 64 return phy_write(phydev, DP83848_MICR, 0x0); 65 } 66 67 static struct mdio_device_id __maybe_unused dp83848_tbl[] = { 68 { DP83848_PHY_ID, 0xfffffff0 }, 69 { } 70 }; 71 MODULE_DEVICE_TABLE(mdio, dp83848_tbl); 72 73 static struct phy_driver dp83848_driver[] = { 74 { 75 .phy_id = DP83848_PHY_ID, 76 .phy_id_mask = 0xfffffff0, 77 .name = "TI DP83848", 78 .features = PHY_BASIC_FEATURES, 79 .flags = PHY_HAS_INTERRUPT, 80 81 .soft_reset = genphy_soft_reset, 82 .config_init = genphy_config_init, 83 .suspend = genphy_suspend, 84 .resume = genphy_resume, 85 .config_aneg = genphy_config_aneg, 86 .read_status = genphy_read_status, 87 88 /* IRQ related */ 89 .ack_interrupt = dp83848_ack_interrupt, 90 .config_intr = dp83848_config_intr, 91 }, 92 }; 93 module_phy_driver(dp83848_driver); 94 95 MODULE_DESCRIPTION("Texas Instruments DP83848 PHY driver"); 96 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com"); 97 MODULE_LICENSE("GPL"); 98