Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.20-rc7 204 lines 5.1 kB view raw
1/* 2 * Driver for Aquantia PHY 3 * 4 * Author: Shaohui Xie <Shaohui.Xie@freescale.com> 5 * 6 * Copyright 2015 Freescale Semiconductor, Inc. 7 * 8 * This file is licensed under the terms of the GNU General Public License 9 * version 2. This program is licensed "as is" without any warranty of any 10 * kind, whether express or implied. 11 */ 12 13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <linux/delay.h> 16#include <linux/mii.h> 17#include <linux/ethtool.h> 18#include <linux/phy.h> 19#include <linux/mdio.h> 20 21#define PHY_ID_AQ1202 0x03a1b445 22#define PHY_ID_AQ2104 0x03a1b460 23#define PHY_ID_AQR105 0x03a1b4a2 24#define PHY_ID_AQR106 0x03a1b4d0 25#define PHY_ID_AQR107 0x03a1b4e0 26#define PHY_ID_AQR405 0x03a1b4b0 27 28#define PHY_AQUANTIA_FEATURES (SUPPORTED_10000baseT_Full | \ 29 SUPPORTED_1000baseT_Full | \ 30 SUPPORTED_100baseT_Full | \ 31 PHY_DEFAULT_FEATURES) 32 33static int aquantia_config_aneg(struct phy_device *phydev) 34{ 35 phydev->supported = PHY_AQUANTIA_FEATURES; 36 phydev->advertising = phydev->supported; 37 38 return 0; 39} 40 41static int aquantia_config_intr(struct phy_device *phydev) 42{ 43 int err; 44 45 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 46 err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 1); 47 if (err < 0) 48 return err; 49 50 err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 1); 51 if (err < 0) 52 return err; 53 54 err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0x1001); 55 } else { 56 err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 0); 57 if (err < 0) 58 return err; 59 60 err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 0); 61 if (err < 0) 62 return err; 63 64 err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0); 65 } 66 67 return err; 68} 69 70static int aquantia_ack_interrupt(struct phy_device *phydev) 71{ 72 int reg; 73 74 reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xcc01); 75 return (reg < 0) ? reg : 0; 76} 77 78static int aquantia_read_status(struct phy_device *phydev) 79{ 80 int reg; 81 82 reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); 83 reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); 84 if (reg & MDIO_STAT1_LSTATUS) 85 phydev->link = 1; 86 else 87 phydev->link = 0; 88 89 reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800); 90 mdelay(10); 91 reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800); 92 93 switch (reg) { 94 case 0x9: 95 phydev->speed = SPEED_2500; 96 break; 97 case 0x5: 98 phydev->speed = SPEED_1000; 99 break; 100 case 0x3: 101 phydev->speed = SPEED_100; 102 break; 103 case 0x7: 104 default: 105 phydev->speed = SPEED_10000; 106 break; 107 } 108 phydev->duplex = DUPLEX_FULL; 109 110 return 0; 111} 112 113static struct phy_driver aquantia_driver[] = { 114{ 115 .phy_id = PHY_ID_AQ1202, 116 .phy_id_mask = 0xfffffff0, 117 .name = "Aquantia AQ1202", 118 .features = PHY_10GBIT_FULL_FEATURES, 119 .flags = PHY_HAS_INTERRUPT, 120 .aneg_done = genphy_c45_aneg_done, 121 .config_aneg = aquantia_config_aneg, 122 .config_intr = aquantia_config_intr, 123 .ack_interrupt = aquantia_ack_interrupt, 124 .read_status = aquantia_read_status, 125}, 126{ 127 .phy_id = PHY_ID_AQ2104, 128 .phy_id_mask = 0xfffffff0, 129 .name = "Aquantia AQ2104", 130 .features = PHY_10GBIT_FULL_FEATURES, 131 .flags = PHY_HAS_INTERRUPT, 132 .aneg_done = genphy_c45_aneg_done, 133 .config_aneg = aquantia_config_aneg, 134 .config_intr = aquantia_config_intr, 135 .ack_interrupt = aquantia_ack_interrupt, 136 .read_status = aquantia_read_status, 137}, 138{ 139 .phy_id = PHY_ID_AQR105, 140 .phy_id_mask = 0xfffffff0, 141 .name = "Aquantia AQR105", 142 .features = PHY_10GBIT_FULL_FEATURES, 143 .flags = PHY_HAS_INTERRUPT, 144 .aneg_done = genphy_c45_aneg_done, 145 .config_aneg = aquantia_config_aneg, 146 .config_intr = aquantia_config_intr, 147 .ack_interrupt = aquantia_ack_interrupt, 148 .read_status = aquantia_read_status, 149}, 150{ 151 .phy_id = PHY_ID_AQR106, 152 .phy_id_mask = 0xfffffff0, 153 .name = "Aquantia AQR106", 154 .features = PHY_10GBIT_FULL_FEATURES, 155 .flags = PHY_HAS_INTERRUPT, 156 .aneg_done = genphy_c45_aneg_done, 157 .config_aneg = aquantia_config_aneg, 158 .config_intr = aquantia_config_intr, 159 .ack_interrupt = aquantia_ack_interrupt, 160 .read_status = aquantia_read_status, 161}, 162{ 163 .phy_id = PHY_ID_AQR107, 164 .phy_id_mask = 0xfffffff0, 165 .name = "Aquantia AQR107", 166 .features = PHY_10GBIT_FULL_FEATURES, 167 .flags = PHY_HAS_INTERRUPT, 168 .aneg_done = genphy_c45_aneg_done, 169 .config_aneg = aquantia_config_aneg, 170 .config_intr = aquantia_config_intr, 171 .ack_interrupt = aquantia_ack_interrupt, 172 .read_status = aquantia_read_status, 173}, 174{ 175 .phy_id = PHY_ID_AQR405, 176 .phy_id_mask = 0xfffffff0, 177 .name = "Aquantia AQR405", 178 .features = PHY_10GBIT_FULL_FEATURES, 179 .flags = PHY_HAS_INTERRUPT, 180 .aneg_done = genphy_c45_aneg_done, 181 .config_aneg = aquantia_config_aneg, 182 .config_intr = aquantia_config_intr, 183 .ack_interrupt = aquantia_ack_interrupt, 184 .read_status = aquantia_read_status, 185}, 186}; 187 188module_phy_driver(aquantia_driver); 189 190static struct mdio_device_id __maybe_unused aquantia_tbl[] = { 191 { PHY_ID_AQ1202, 0xfffffff0 }, 192 { PHY_ID_AQ2104, 0xfffffff0 }, 193 { PHY_ID_AQR105, 0xfffffff0 }, 194 { PHY_ID_AQR106, 0xfffffff0 }, 195 { PHY_ID_AQR107, 0xfffffff0 }, 196 { PHY_ID_AQR405, 0xfffffff0 }, 197 { } 198}; 199 200MODULE_DEVICE_TABLE(mdio, aquantia_tbl); 201 202MODULE_DESCRIPTION("Aquantia PHY driver"); 203MODULE_AUTHOR("Shaohui Xie <Shaohui.Xie@freescale.com>"); 204MODULE_LICENSE("GPL v2");