1 /* 2 * drivers/net/phy/realtek.c 3 * 4 * Driver for Realtek PHYs 5 * 6 * Author: Johnson Leung <r58129@freescale.com> 7 * 8 * Copyright (c) 2004 Freescale Semiconductor, Inc. 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 */ 16 #include <linux/phy.h> 17 #include <linux/module.h> 18 19 #define RTL821x_PHYSR 0x11 20 #define RTL821x_PHYSR_DUPLEX 0x2000 21 #define RTL821x_PHYSR_SPEED 0xc000 22 #define RTL821x_INER 0x12 23 #define RTL821x_INER_INIT 0x6400 24 #define RTL821x_INSR 0x13 25 #define RTL8211E_INER_LINK_STATUS 0x400 26 27 #define RTL8211F_INER_LINK_STATUS 0x0010 28 #define RTL8211F_INSR 0x1d 29 #define RTL8211F_PAGE_SELECT 0x1f 30 #define RTL8211F_TX_DELAY 0x100 31 32 MODULE_DESCRIPTION("Realtek PHY driver"); 33 MODULE_AUTHOR("Johnson Leung"); 34 MODULE_LICENSE("GPL"); 35 36 static int rtl821x_ack_interrupt(struct phy_device *phydev) 37 { 38 int err; 39 40 err = phy_read(phydev, RTL821x_INSR); 41 42 return (err < 0) ? err : 0; 43 } 44 45 static int rtl8211f_ack_interrupt(struct phy_device *phydev) 46 { 47 int err; 48 49 phy_write(phydev, RTL8211F_PAGE_SELECT, 0xa43); 50 err = phy_read(phydev, RTL8211F_INSR); 51 /* restore to default page 0 */ 52 phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0); 53 54 return (err < 0) ? err : 0; 55 } 56 57 static int rtl8211b_config_intr(struct phy_device *phydev) 58 { 59 int err; 60 61 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 62 err = phy_write(phydev, RTL821x_INER, 63 RTL821x_INER_INIT); 64 else 65 err = phy_write(phydev, RTL821x_INER, 0); 66 67 return err; 68 } 69 70 static int rtl8211e_config_intr(struct phy_device *phydev) 71 { 72 int err; 73 74 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 75 err = phy_write(phydev, RTL821x_INER, 76 RTL8211E_INER_LINK_STATUS); 77 else 78 err = phy_write(phydev, RTL821x_INER, 0); 79 80 return err; 81 } 82 83 static int rtl8211f_config_intr(struct phy_device *phydev) 84 { 85 int err; 86 87 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 88 err = phy_write(phydev, RTL821x_INER, 89 RTL8211F_INER_LINK_STATUS); 90 else 91 err = phy_write(phydev, RTL821x_INER, 0); 92 93 return err; 94 } 95 96 static int rtl8211f_config_init(struct phy_device *phydev) 97 { 98 int ret; 99 u16 reg; 100 101 ret = genphy_config_init(phydev); 102 if (ret < 0) 103 return ret; 104 105 if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { 106 /* enable TXDLY */ 107 phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08); 108 reg = phy_read(phydev, 0x11); 109 reg |= RTL8211F_TX_DELAY; 110 phy_write(phydev, 0x11, reg); 111 /* restore to default page 0 */ 112 phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0); 113 } 114 115 return 0; 116 } 117 118 static struct phy_driver realtek_drvs[] = { 119 { 120 .phy_id = 0x00008201, 121 .name = "RTL8201CP Ethernet", 122 .phy_id_mask = 0x0000ffff, 123 .features = PHY_BASIC_FEATURES, 124 .flags = PHY_HAS_INTERRUPT, 125 .config_aneg = &genphy_config_aneg, 126 .read_status = &genphy_read_status, 127 }, { 128 .phy_id = 0x001cc912, 129 .name = "RTL8211B Gigabit Ethernet", 130 .phy_id_mask = 0x001fffff, 131 .features = PHY_GBIT_FEATURES, 132 .flags = PHY_HAS_INTERRUPT, 133 .config_aneg = &genphy_config_aneg, 134 .read_status = &genphy_read_status, 135 .ack_interrupt = &rtl821x_ack_interrupt, 136 .config_intr = &rtl8211b_config_intr, 137 }, { 138 .phy_id = 0x001cc914, 139 .name = "RTL8211DN Gigabit Ethernet", 140 .phy_id_mask = 0x001fffff, 141 .features = PHY_GBIT_FEATURES, 142 .flags = PHY_HAS_INTERRUPT, 143 .config_aneg = genphy_config_aneg, 144 .read_status = genphy_read_status, 145 .ack_interrupt = rtl821x_ack_interrupt, 146 .config_intr = rtl8211e_config_intr, 147 .suspend = genphy_suspend, 148 .resume = genphy_resume, 149 }, { 150 .phy_id = 0x001cc915, 151 .name = "RTL8211E Gigabit Ethernet", 152 .phy_id_mask = 0x001fffff, 153 .features = PHY_GBIT_FEATURES, 154 .flags = PHY_HAS_INTERRUPT, 155 .config_aneg = &genphy_config_aneg, 156 .read_status = &genphy_read_status, 157 .ack_interrupt = &rtl821x_ack_interrupt, 158 .config_intr = &rtl8211e_config_intr, 159 .suspend = genphy_suspend, 160 .resume = genphy_resume, 161 }, { 162 .phy_id = 0x001cc916, 163 .name = "RTL8211F Gigabit Ethernet", 164 .phy_id_mask = 0x001fffff, 165 .features = PHY_GBIT_FEATURES, 166 .flags = PHY_HAS_INTERRUPT, 167 .config_aneg = &genphy_config_aneg, 168 .config_init = &rtl8211f_config_init, 169 .read_status = &genphy_read_status, 170 .ack_interrupt = &rtl8211f_ack_interrupt, 171 .config_intr = &rtl8211f_config_intr, 172 .suspend = genphy_suspend, 173 .resume = genphy_resume, 174 }, 175 }; 176 177 module_phy_driver(realtek_drvs); 178 179 static struct mdio_device_id __maybe_unused realtek_tbl[] = { 180 { 0x001cc912, 0x001fffff }, 181 { 0x001cc914, 0x001fffff }, 182 { 0x001cc915, 0x001fffff }, 183 { 0x001cc916, 0x001fffff }, 184 { } 185 }; 186 187 MODULE_DEVICE_TABLE(mdio, realtek_tbl); 188