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 .driver = { .owner = THIS_MODULE,}, 128 }, { 129 .phy_id = 0x001cc912, 130 .name = "RTL8211B Gigabit Ethernet", 131 .phy_id_mask = 0x001fffff, 132 .features = PHY_GBIT_FEATURES, 133 .flags = PHY_HAS_INTERRUPT, 134 .config_aneg = &genphy_config_aneg, 135 .read_status = &genphy_read_status, 136 .ack_interrupt = &rtl821x_ack_interrupt, 137 .config_intr = &rtl8211b_config_intr, 138 .driver = { .owner = THIS_MODULE,}, 139 }, { 140 .phy_id = 0x001cc914, 141 .name = "RTL8211DN Gigabit Ethernet", 142 .phy_id_mask = 0x001fffff, 143 .features = PHY_GBIT_FEATURES, 144 .flags = PHY_HAS_INTERRUPT, 145 .config_aneg = genphy_config_aneg, 146 .read_status = genphy_read_status, 147 .ack_interrupt = rtl821x_ack_interrupt, 148 .config_intr = rtl8211e_config_intr, 149 .suspend = genphy_suspend, 150 .resume = genphy_resume, 151 .driver = { .owner = THIS_MODULE,}, 152 }, { 153 .phy_id = 0x001cc915, 154 .name = "RTL8211E Gigabit Ethernet", 155 .phy_id_mask = 0x001fffff, 156 .features = PHY_GBIT_FEATURES, 157 .flags = PHY_HAS_INTERRUPT, 158 .config_aneg = &genphy_config_aneg, 159 .read_status = &genphy_read_status, 160 .ack_interrupt = &rtl821x_ack_interrupt, 161 .config_intr = &rtl8211e_config_intr, 162 .suspend = genphy_suspend, 163 .resume = genphy_resume, 164 .driver = { .owner = THIS_MODULE,}, 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 .driver = { .owner = THIS_MODULE }, 179 }, 180 }; 181 182 module_phy_driver(realtek_drvs); 183 184 static struct mdio_device_id __maybe_unused realtek_tbl[] = { 185 { 0x001cc912, 0x001fffff }, 186 { 0x001cc914, 0x001fffff }, 187 { 0x001cc915, 0x001fffff }, 188 { 0x001cc916, 0x001fffff }, 189 { } 190 }; 191 192 MODULE_DEVICE_TABLE(mdio, realtek_tbl); 193