Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.11 191 lines 4.8 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 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 122static 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 181module_phy_driver(realtek_drvs); 182 183static struct mdio_device_id __maybe_unused realtek_tbl[] = { 184 { 0x001cc912, 0x001fffff }, 185 { 0x001cc914, 0x001fffff }, 186 { 0x001cc915, 0x001fffff }, 187 { 0x001cc916, 0x001fffff }, 188 { } 189}; 190 191MODULE_DEVICE_TABLE(mdio, realtek_tbl);