Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.5-rc3 187 lines 4.7 kB view raw
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 32MODULE_DESCRIPTION("Realtek PHY driver"); 33MODULE_AUTHOR("Johnson Leung"); 34MODULE_LICENSE("GPL"); 35 36static 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 45static 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 57static 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 70static 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 83static 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 96static 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 118static 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 177module_phy_driver(realtek_drvs); 178 179static struct mdio_device_id __maybe_unused realtek_tbl[] = { 180 { 0x001cc912, 0x001fffff }, 181 { 0x001cc914, 0x001fffff }, 182 { 0x001cc915, 0x001fffff }, 183 { 0x001cc916, 0x001fffff }, 184 { } 185}; 186 187MODULE_DEVICE_TABLE(mdio, realtek_tbl);