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 phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08); 106 reg = phy_read(phydev, 0x11); 107 108 /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */ 109 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 110 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 111 reg |= RTL8211F_TX_DELAY; 112 else 113 reg &= ~RTL8211F_TX_DELAY; 114 115 phy_write(phydev, 0x11, reg); 116 /* restore to default page 0 */ 117 phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0); 118 119 return 0; 120 } 121 122 static struct phy_driver realtek_drvs[] = { 123 { 124 .phy_id = 0x00008201, 125 .name = "RTL8201CP Ethernet", 126 .phy_id_mask = 0x0000ffff, 127 .features = PHY_BASIC_FEATURES, 128 .flags = PHY_HAS_INTERRUPT, 129 .config_aneg = &genphy_config_aneg, 130 .read_status = &genphy_read_status, 131 }, { 132 .phy_id = 0x001cc912, 133 .name = "RTL8211B Gigabit Ethernet", 134 .phy_id_mask = 0x001fffff, 135 .features = PHY_GBIT_FEATURES, 136 .flags = PHY_HAS_INTERRUPT, 137 .config_aneg = &genphy_config_aneg, 138 .read_status = &genphy_read_status, 139 .ack_interrupt = &rtl821x_ack_interrupt, 140 .config_intr = &rtl8211b_config_intr, 141 }, { 142 .phy_id = 0x001cc914, 143 .name = "RTL8211DN Gigabit Ethernet", 144 .phy_id_mask = 0x001fffff, 145 .features = PHY_GBIT_FEATURES, 146 .flags = PHY_HAS_INTERRUPT, 147 .config_aneg = genphy_config_aneg, 148 .read_status = genphy_read_status, 149 .ack_interrupt = rtl821x_ack_interrupt, 150 .config_intr = rtl8211e_config_intr, 151 .suspend = genphy_suspend, 152 .resume = genphy_resume, 153 }, { 154 .phy_id = 0x001cc915, 155 .name = "RTL8211E Gigabit Ethernet", 156 .phy_id_mask = 0x001fffff, 157 .features = PHY_GBIT_FEATURES, 158 .flags = PHY_HAS_INTERRUPT, 159 .config_aneg = &genphy_config_aneg, 160 .read_status = &genphy_read_status, 161 .ack_interrupt = &rtl821x_ack_interrupt, 162 .config_intr = &rtl8211e_config_intr, 163 .suspend = genphy_suspend, 164 .resume = genphy_resume, 165 }, { 166 .phy_id = 0x001cc916, 167 .name = "RTL8211F Gigabit Ethernet", 168 .phy_id_mask = 0x001fffff, 169 .features = PHY_GBIT_FEATURES, 170 .flags = PHY_HAS_INTERRUPT, 171 .config_aneg = &genphy_config_aneg, 172 .config_init = &rtl8211f_config_init, 173 .read_status = &genphy_read_status, 174 .ack_interrupt = &rtl8211f_ack_interrupt, 175 .config_intr = &rtl8211f_config_intr, 176 .suspend = genphy_suspend, 177 .resume = genphy_resume, 178 }, 179 }; 180 181 module_phy_driver(realtek_drvs); 182 183 static struct mdio_device_id __maybe_unused realtek_tbl[] = { 184 { 0x001cc912, 0x001fffff }, 185 { 0x001cc914, 0x001fffff }, 186 { 0x001cc915, 0x001fffff }, 187 { 0x001cc916, 0x001fffff }, 188 { } 189 }; 190 191 MODULE_DEVICE_TABLE(mdio, realtek_tbl); 192