1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2012 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> 4 * Copyright (C) 2016 Hauke Mehrtens <hauke@hauke-m.de> 5 */ 6 7 #include <linux/mdio.h> 8 #include <linux/module.h> 9 #include <linux/phy.h> 10 #include <linux/of.h> 11 #include <linux/bitfield.h> 12 13 #define XWAY_MDIO_ERRCNT 0x15 /* error counter */ 14 #define XWAY_MDIO_MIICTRL 0x17 /* mii control */ 15 #define XWAY_MDIO_IMASK 0x19 /* interrupt mask */ 16 #define XWAY_MDIO_ISTAT 0x1A /* interrupt status */ 17 #define XWAY_MDIO_LED 0x1B /* led control */ 18 19 #define XWAY_MDIO_ERRCNT_SEL GENMASK(11, 8) 20 #define XWAY_MDIO_ERRCNT_COUNT GENMASK(7, 0) 21 #define XWAY_MDIO_ERRCNT_SEL_RXERR 0 22 23 #define XWAY_MDIO_MIICTRL_RXSKEW_MASK GENMASK(14, 12) 24 #define XWAY_MDIO_MIICTRL_TXSKEW_MASK GENMASK(10, 8) 25 26 /* bit 15:12 are reserved */ 27 #define XWAY_MDIO_LED_LED3_EN BIT(11) /* Enable the integrated function of LED3 */ 28 #define XWAY_MDIO_LED_LED2_EN BIT(10) /* Enable the integrated function of LED2 */ 29 #define XWAY_MDIO_LED_LED1_EN BIT(9) /* Enable the integrated function of LED1 */ 30 #define XWAY_MDIO_LED_LED0_EN BIT(8) /* Enable the integrated function of LED0 */ 31 /* bit 7:4 are reserved */ 32 #define XWAY_MDIO_LED_LED3_DA BIT(3) /* Direct Access to LED3 */ 33 #define XWAY_MDIO_LED_LED2_DA BIT(2) /* Direct Access to LED2 */ 34 #define XWAY_MDIO_LED_LED1_DA BIT(1) /* Direct Access to LED1 */ 35 #define XWAY_MDIO_LED_LED0_DA BIT(0) /* Direct Access to LED0 */ 36 37 #define XWAY_MDIO_INIT_WOL BIT(15) /* Wake-On-LAN */ 38 #define XWAY_MDIO_INIT_MSRE BIT(14) 39 #define XWAY_MDIO_INIT_NPRX BIT(13) 40 #define XWAY_MDIO_INIT_NPTX BIT(12) 41 #define XWAY_MDIO_INIT_ANE BIT(11) /* Auto-Neg error */ 42 #define XWAY_MDIO_INIT_ANC BIT(10) /* Auto-Neg complete */ 43 #define XWAY_MDIO_INIT_ADSC BIT(5) /* Link auto-downspeed detect */ 44 #define XWAY_MDIO_INIT_MPIPC BIT(4) 45 #define XWAY_MDIO_INIT_MDIXC BIT(3) 46 #define XWAY_MDIO_INIT_DXMC BIT(2) /* Duplex mode change */ 47 #define XWAY_MDIO_INIT_LSPC BIT(1) /* Link speed change */ 48 #define XWAY_MDIO_INIT_LSTC BIT(0) /* Link state change */ 49 #define XWAY_MDIO_INIT_MASK (XWAY_MDIO_INIT_LSTC | \ 50 XWAY_MDIO_INIT_ADSC) 51 52 #define ADVERTISED_MPD BIT(10) /* Multi-port device */ 53 54 /* LED Configuration */ 55 #define XWAY_MMD_LEDCH 0x01E0 56 /* Inverse of SCAN Function */ 57 #define XWAY_MMD_LEDCH_NACS_NONE 0x0000 58 #define XWAY_MMD_LEDCH_NACS_LINK 0x0001 59 #define XWAY_MMD_LEDCH_NACS_PDOWN 0x0002 60 #define XWAY_MMD_LEDCH_NACS_EEE 0x0003 61 #define XWAY_MMD_LEDCH_NACS_ANEG 0x0004 62 #define XWAY_MMD_LEDCH_NACS_ABIST 0x0005 63 #define XWAY_MMD_LEDCH_NACS_CDIAG 0x0006 64 #define XWAY_MMD_LEDCH_NACS_TEST 0x0007 65 /* Slow Blink Frequency */ 66 #define XWAY_MMD_LEDCH_SBF_F02HZ 0x0000 67 #define XWAY_MMD_LEDCH_SBF_F04HZ 0x0010 68 #define XWAY_MMD_LEDCH_SBF_F08HZ 0x0020 69 #define XWAY_MMD_LEDCH_SBF_F16HZ 0x0030 70 /* Fast Blink Frequency */ 71 #define XWAY_MMD_LEDCH_FBF_F02HZ 0x0000 72 #define XWAY_MMD_LEDCH_FBF_F04HZ 0x0040 73 #define XWAY_MMD_LEDCH_FBF_F08HZ 0x0080 74 #define XWAY_MMD_LEDCH_FBF_F16HZ 0x00C0 75 /* LED Configuration */ 76 #define XWAY_MMD_LEDCL 0x01E1 77 /* Complex Blinking Configuration */ 78 #define XWAY_MMD_LEDCH_CBLINK_NONE 0x0000 79 #define XWAY_MMD_LEDCH_CBLINK_LINK 0x0001 80 #define XWAY_MMD_LEDCH_CBLINK_PDOWN 0x0002 81 #define XWAY_MMD_LEDCH_CBLINK_EEE 0x0003 82 #define XWAY_MMD_LEDCH_CBLINK_ANEG 0x0004 83 #define XWAY_MMD_LEDCH_CBLINK_ABIST 0x0005 84 #define XWAY_MMD_LEDCH_CBLINK_CDIAG 0x0006 85 #define XWAY_MMD_LEDCH_CBLINK_TEST 0x0007 86 /* Complex SCAN Configuration */ 87 #define XWAY_MMD_LEDCH_SCAN_NONE 0x0000 88 #define XWAY_MMD_LEDCH_SCAN_LINK 0x0010 89 #define XWAY_MMD_LEDCH_SCAN_PDOWN 0x0020 90 #define XWAY_MMD_LEDCH_SCAN_EEE 0x0030 91 #define XWAY_MMD_LEDCH_SCAN_ANEG 0x0040 92 #define XWAY_MMD_LEDCH_SCAN_ABIST 0x0050 93 #define XWAY_MMD_LEDCH_SCAN_CDIAG 0x0060 94 #define XWAY_MMD_LEDCH_SCAN_TEST 0x0070 95 /* Configuration for LED Pin x */ 96 #define XWAY_MMD_LED0H 0x01E2 97 /* Fast Blinking Configuration */ 98 #define XWAY_MMD_LEDxH_BLINKF_MASK 0x000F 99 #define XWAY_MMD_LEDxH_BLINKF_NONE 0x0000 100 #define XWAY_MMD_LEDxH_BLINKF_LINK10 0x0001 101 #define XWAY_MMD_LEDxH_BLINKF_LINK100 0x0002 102 #define XWAY_MMD_LEDxH_BLINKF_LINK10X 0x0003 103 #define XWAY_MMD_LEDxH_BLINKF_LINK1000 0x0004 104 #define XWAY_MMD_LEDxH_BLINKF_LINK10_0 0x0005 105 #define XWAY_MMD_LEDxH_BLINKF_LINK100X 0x0006 106 #define XWAY_MMD_LEDxH_BLINKF_LINK10XX 0x0007 107 #define XWAY_MMD_LEDxH_BLINKF_PDOWN 0x0008 108 #define XWAY_MMD_LEDxH_BLINKF_EEE 0x0009 109 #define XWAY_MMD_LEDxH_BLINKF_ANEG 0x000A 110 #define XWAY_MMD_LEDxH_BLINKF_ABIST 0x000B 111 #define XWAY_MMD_LEDxH_BLINKF_CDIAG 0x000C 112 /* Constant On Configuration */ 113 #define XWAY_MMD_LEDxH_CON_MASK 0x00F0 114 #define XWAY_MMD_LEDxH_CON_NONE 0x0000 115 #define XWAY_MMD_LEDxH_CON_LINK10 0x0010 116 #define XWAY_MMD_LEDxH_CON_LINK100 0x0020 117 #define XWAY_MMD_LEDxH_CON_LINK10X 0x0030 118 #define XWAY_MMD_LEDxH_CON_LINK1000 0x0040 119 #define XWAY_MMD_LEDxH_CON_LINK10_0 0x0050 120 #define XWAY_MMD_LEDxH_CON_LINK100X 0x0060 121 #define XWAY_MMD_LEDxH_CON_LINK10XX 0x0070 122 #define XWAY_MMD_LEDxH_CON_PDOWN 0x0080 123 #define XWAY_MMD_LEDxH_CON_EEE 0x0090 124 #define XWAY_MMD_LEDxH_CON_ANEG 0x00A0 125 #define XWAY_MMD_LEDxH_CON_ABIST 0x00B0 126 #define XWAY_MMD_LEDxH_CON_CDIAG 0x00C0 127 #define XWAY_MMD_LEDxH_CON_COPPER 0x00D0 128 #define XWAY_MMD_LEDxH_CON_FIBER 0x00E0 129 /* Configuration for LED Pin x */ 130 #define XWAY_MMD_LED0L 0x01E3 131 /* Pulsing Configuration */ 132 #define XWAY_MMD_LEDxL_PULSE_MASK 0x000F 133 #define XWAY_MMD_LEDxL_PULSE_NONE 0x0000 134 #define XWAY_MMD_LEDxL_PULSE_TXACT 0x0001 135 #define XWAY_MMD_LEDxL_PULSE_RXACT 0x0002 136 #define XWAY_MMD_LEDxL_PULSE_COL 0x0004 137 /* Slow Blinking Configuration */ 138 #define XWAY_MMD_LEDxL_BLINKS_MASK 0x00F0 139 #define XWAY_MMD_LEDxL_BLINKS_NONE 0x0000 140 #define XWAY_MMD_LEDxL_BLINKS_LINK10 0x0010 141 #define XWAY_MMD_LEDxL_BLINKS_LINK100 0x0020 142 #define XWAY_MMD_LEDxL_BLINKS_LINK10X 0x0030 143 #define XWAY_MMD_LEDxL_BLINKS_LINK1000 0x0040 144 #define XWAY_MMD_LEDxL_BLINKS_LINK10_0 0x0050 145 #define XWAY_MMD_LEDxL_BLINKS_LINK100X 0x0060 146 #define XWAY_MMD_LEDxL_BLINKS_LINK10XX 0x0070 147 #define XWAY_MMD_LEDxL_BLINKS_PDOWN 0x0080 148 #define XWAY_MMD_LEDxL_BLINKS_EEE 0x0090 149 #define XWAY_MMD_LEDxL_BLINKS_ANEG 0x00A0 150 #define XWAY_MMD_LEDxL_BLINKS_ABIST 0x00B0 151 #define XWAY_MMD_LEDxL_BLINKS_CDIAG 0x00C0 152 #define XWAY_MMD_LED1H 0x01E4 153 #define XWAY_MMD_LED1L 0x01E5 154 #define XWAY_MMD_LED2H 0x01E6 155 #define XWAY_MMD_LED2L 0x01E7 156 #define XWAY_MMD_LED3H 0x01E8 157 #define XWAY_MMD_LED3L 0x01E9 158 159 #define XWAY_GPHY_MAX_LEDS 3 160 #define XWAY_GPHY_LED_INV(idx) BIT(12 + (idx)) 161 #define XWAY_GPHY_LED_EN(idx) BIT(8 + (idx)) 162 #define XWAY_GPHY_LED_DA(idx) BIT(idx) 163 #define XWAY_MMD_LEDxH(idx) (XWAY_MMD_LED0H + 2 * (idx)) 164 #define XWAY_MMD_LEDxL(idx) (XWAY_MMD_LED0L + 2 * (idx)) 165 166 #define PHY_ID_PHY11G_1_3 0x030260D1 167 #define PHY_ID_PHY22F_1_3 0x030260E1 168 #define PHY_ID_PHY11G_1_4 0xD565A400 169 #define PHY_ID_PHY22F_1_4 0xD565A410 170 #define PHY_ID_PHY11G_1_5 0xD565A401 171 #define PHY_ID_PHY22F_1_5 0xD565A411 172 #define PHY_ID_PHY11G_VR9_1_1 0xD565A408 173 #define PHY_ID_PHY22F_VR9_1_1 0xD565A418 174 #define PHY_ID_PHY11G_VR9_1_2 0xD565A409 175 #define PHY_ID_PHY22F_VR9_1_2 0xD565A419 176 177 struct xway_gphy_priv { 178 u64 rx_errors; 179 }; 180 181 static const int xway_internal_delay[] = {0, 500, 1000, 1500, 2000, 2500, 182 3000, 3500}; 183 184 static int xway_gphy_rgmii_init(struct phy_device *phydev) 185 { 186 unsigned int delay_size = ARRAY_SIZE(xway_internal_delay); 187 s32 int_delay; 188 int val = 0; 189 190 if (!phy_interface_is_rgmii(phydev)) 191 return 0; 192 193 /* Existing behavior was to use default pin strapping delay in rgmii 194 * mode, but rgmii should have meant no delay. Warn existing users, 195 * but do not change anything at the moment. 196 */ 197 if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { 198 u16 txskew, rxskew; 199 200 val = phy_read(phydev, XWAY_MDIO_MIICTRL); 201 if (val < 0) 202 return val; 203 204 txskew = FIELD_GET(XWAY_MDIO_MIICTRL_TXSKEW_MASK, val); 205 rxskew = FIELD_GET(XWAY_MDIO_MIICTRL_RXSKEW_MASK, val); 206 207 if (txskew > 0 || rxskew > 0) 208 phydev_warn(phydev, 209 "PHY has delays (e.g. via pin strapping), but phy-mode = 'rgmii'\n" 210 "Should be 'rgmii-id' to use internal delays txskew:%d ps rxskew:%d ps\n", 211 xway_internal_delay[txskew], 212 xway_internal_delay[rxskew]); 213 return 0; 214 } 215 216 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 217 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 218 int_delay = phy_get_internal_delay(phydev, xway_internal_delay, 219 delay_size, true); 220 221 /* if rx-internal-delay-ps is missing, use default of 2.0 ns */ 222 if (int_delay < 0) 223 int_delay = 4; /* 2000 ps */ 224 225 val |= FIELD_PREP(XWAY_MDIO_MIICTRL_RXSKEW_MASK, int_delay); 226 } 227 228 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 229 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 230 int_delay = phy_get_internal_delay(phydev, xway_internal_delay, 231 delay_size, false); 232 233 /* if tx-internal-delay-ps is missing, use default of 2.0 ns */ 234 if (int_delay < 0) 235 int_delay = 4; /* 2000 ps */ 236 237 val |= FIELD_PREP(XWAY_MDIO_MIICTRL_TXSKEW_MASK, int_delay); 238 } 239 240 return phy_modify(phydev, XWAY_MDIO_MIICTRL, 241 XWAY_MDIO_MIICTRL_RXSKEW_MASK | 242 XWAY_MDIO_MIICTRL_TXSKEW_MASK, val); 243 } 244 245 static int xway_gphy_init_leds(struct phy_device *phydev) 246 { 247 int err; 248 u32 ledxh; 249 u32 ledxl; 250 251 /* Ensure that integrated led function is enabled for all leds */ 252 err = phy_write(phydev, XWAY_MDIO_LED, 253 XWAY_MDIO_LED_LED0_EN | 254 XWAY_MDIO_LED_LED1_EN | 255 XWAY_MDIO_LED_LED2_EN | 256 XWAY_MDIO_LED_LED3_EN); 257 if (err) 258 return err; 259 260 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCH, 261 XWAY_MMD_LEDCH_NACS_NONE | 262 XWAY_MMD_LEDCH_SBF_F02HZ | 263 XWAY_MMD_LEDCH_FBF_F16HZ); 264 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCL, 265 XWAY_MMD_LEDCH_CBLINK_NONE | 266 XWAY_MMD_LEDCH_SCAN_NONE); 267 268 /** 269 * In most cases only one LED is connected to this phy, so 270 * configure them all to constant on and pulse mode. LED3 is 271 * only available in some packages, leave it in its reset 272 * configuration. 273 */ 274 ledxh = XWAY_MMD_LEDxH_BLINKF_NONE | XWAY_MMD_LEDxH_CON_LINK10XX; 275 ledxl = XWAY_MMD_LEDxL_PULSE_TXACT | XWAY_MMD_LEDxL_PULSE_RXACT | 276 XWAY_MMD_LEDxL_BLINKS_NONE; 277 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0H, ledxh); 278 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0L, ledxl); 279 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1H, ledxh); 280 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1L, ledxl); 281 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh); 282 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl); 283 284 return 0; 285 } 286 287 static int xway_gphy_config_init(struct phy_device *phydev) 288 { 289 struct device_node *np; 290 int err; 291 292 /* Mask all interrupts */ 293 err = phy_write(phydev, XWAY_MDIO_IMASK, 0); 294 if (err) 295 return err; 296 297 /* Use default LED configuration if 'leds' node isn't defined */ 298 np = of_get_child_by_name(phydev->mdio.dev.of_node, "leds"); 299 if (np) 300 of_node_put(np); 301 else 302 xway_gphy_init_leds(phydev); 303 304 /* Clear all pending interrupts */ 305 phy_read(phydev, XWAY_MDIO_ISTAT); 306 307 err = xway_gphy_rgmii_init(phydev); 308 if (err) 309 return err; 310 311 /* Count MDI RX errors (SymbolErrorDuringCarrier) */ 312 return phy_write(phydev, XWAY_MDIO_ERRCNT, 313 FIELD_PREP(XWAY_MDIO_ERRCNT_SEL, XWAY_MDIO_ERRCNT_SEL_RXERR)); 314 } 315 316 static int xway_gphy_probe(struct phy_device *phydev) 317 { 318 struct device *dev = &phydev->mdio.dev; 319 struct xway_gphy_priv *priv; 320 321 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 322 if (!priv) 323 return -ENOMEM; 324 phydev->priv = priv; 325 326 return 0; 327 } 328 329 static int xway_gphy14_config_aneg(struct phy_device *phydev) 330 { 331 int reg, err; 332 333 /* Advertise as multi-port device, see IEEE802.3-2002 40.5.1.1 */ 334 /* This is a workaround for an errata in rev < 1.5 devices */ 335 reg = phy_read(phydev, MII_CTRL1000); 336 reg |= ADVERTISED_MPD; 337 err = phy_write(phydev, MII_CTRL1000, reg); 338 if (err) 339 return err; 340 341 return genphy_config_aneg(phydev); 342 } 343 344 static int xway_gphy_ack_interrupt(struct phy_device *phydev) 345 { 346 int reg; 347 348 reg = phy_read(phydev, XWAY_MDIO_ISTAT); 349 return (reg < 0) ? reg : 0; 350 } 351 352 static int xway_gphy_config_intr(struct phy_device *phydev) 353 { 354 u16 mask = 0; 355 int err; 356 357 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 358 err = xway_gphy_ack_interrupt(phydev); 359 if (err) 360 return err; 361 362 mask = XWAY_MDIO_INIT_MASK; 363 err = phy_write(phydev, XWAY_MDIO_IMASK, mask); 364 } else { 365 err = phy_write(phydev, XWAY_MDIO_IMASK, mask); 366 if (err) 367 return err; 368 369 err = xway_gphy_ack_interrupt(phydev); 370 } 371 372 return err; 373 } 374 375 static irqreturn_t xway_gphy_handle_interrupt(struct phy_device *phydev) 376 { 377 int irq_status; 378 379 irq_status = phy_read(phydev, XWAY_MDIO_ISTAT); 380 if (irq_status < 0) { 381 phy_error(phydev); 382 return IRQ_NONE; 383 } 384 385 if (!(irq_status & XWAY_MDIO_INIT_MASK)) 386 return IRQ_NONE; 387 388 phy_trigger_machine(phydev); 389 390 return IRQ_HANDLED; 391 } 392 393 static int xway_gphy_led_brightness_set(struct phy_device *phydev, 394 u8 index, enum led_brightness value) 395 { 396 int ret; 397 398 if (index >= XWAY_GPHY_MAX_LEDS) 399 return -EINVAL; 400 401 /* clear EN and set manual LED state */ 402 ret = phy_modify(phydev, XWAY_MDIO_LED, 403 ((value == LED_OFF) ? XWAY_GPHY_LED_EN(index) : 0) | 404 XWAY_GPHY_LED_DA(index), 405 (value == LED_OFF) ? 0 : XWAY_GPHY_LED_DA(index)); 406 if (ret) 407 return ret; 408 409 /* clear HW LED setup */ 410 if (value == LED_OFF) { 411 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), 0); 412 if (ret) 413 return ret; 414 415 return phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), 0); 416 } else { 417 return 0; 418 } 419 } 420 421 static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) | 422 BIT(TRIGGER_NETDEV_LINK_10) | 423 BIT(TRIGGER_NETDEV_LINK_100) | 424 BIT(TRIGGER_NETDEV_LINK_1000) | 425 BIT(TRIGGER_NETDEV_RX) | 426 BIT(TRIGGER_NETDEV_TX)); 427 428 static int xway_gphy_led_hw_is_supported(struct phy_device *phydev, u8 index, 429 unsigned long rules) 430 { 431 if (index >= XWAY_GPHY_MAX_LEDS) 432 return -EINVAL; 433 434 /* activity triggers are not possible without combination with a link 435 * trigger. 436 */ 437 if (rules & (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) && 438 !(rules & (BIT(TRIGGER_NETDEV_LINK) | 439 BIT(TRIGGER_NETDEV_LINK_10) | 440 BIT(TRIGGER_NETDEV_LINK_100) | 441 BIT(TRIGGER_NETDEV_LINK_1000)))) 442 return -EOPNOTSUPP; 443 444 /* All other combinations of the supported triggers are allowed */ 445 if (rules & ~supported_triggers) 446 return -EOPNOTSUPP; 447 448 return 0; 449 } 450 451 static int xway_gphy_led_hw_control_get(struct phy_device *phydev, u8 index, 452 unsigned long *rules) 453 { 454 int lval, hval; 455 456 if (index >= XWAY_GPHY_MAX_LEDS) 457 return -EINVAL; 458 459 hval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index)); 460 if (hval < 0) 461 return hval; 462 463 lval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index)); 464 if (lval < 0) 465 return lval; 466 467 if (hval & XWAY_MMD_LEDxH_CON_LINK10) 468 *rules |= BIT(TRIGGER_NETDEV_LINK_10); 469 470 if (hval & XWAY_MMD_LEDxH_CON_LINK100) 471 *rules |= BIT(TRIGGER_NETDEV_LINK_100); 472 473 if (hval & XWAY_MMD_LEDxH_CON_LINK1000) 474 *rules |= BIT(TRIGGER_NETDEV_LINK_1000); 475 476 if ((hval & XWAY_MMD_LEDxH_CON_LINK10) && 477 (hval & XWAY_MMD_LEDxH_CON_LINK100) && 478 (hval & XWAY_MMD_LEDxH_CON_LINK1000)) 479 *rules |= BIT(TRIGGER_NETDEV_LINK); 480 481 if (lval & XWAY_MMD_LEDxL_PULSE_TXACT) 482 *rules |= BIT(TRIGGER_NETDEV_TX); 483 484 if (lval & XWAY_MMD_LEDxL_PULSE_RXACT) 485 *rules |= BIT(TRIGGER_NETDEV_RX); 486 487 return 0; 488 } 489 490 static int xway_gphy_led_hw_control_set(struct phy_device *phydev, u8 index, 491 unsigned long rules) 492 { 493 u16 hval = 0, lval = 0; 494 int ret; 495 496 if (index >= XWAY_GPHY_MAX_LEDS) 497 return -EINVAL; 498 499 if (rules & BIT(TRIGGER_NETDEV_LINK) || 500 rules & BIT(TRIGGER_NETDEV_LINK_10)) 501 hval |= XWAY_MMD_LEDxH_CON_LINK10; 502 503 if (rules & BIT(TRIGGER_NETDEV_LINK) || 504 rules & BIT(TRIGGER_NETDEV_LINK_100)) 505 hval |= XWAY_MMD_LEDxH_CON_LINK100; 506 507 if (rules & BIT(TRIGGER_NETDEV_LINK) || 508 rules & BIT(TRIGGER_NETDEV_LINK_1000)) 509 hval |= XWAY_MMD_LEDxH_CON_LINK1000; 510 511 if (rules & BIT(TRIGGER_NETDEV_TX)) 512 lval |= XWAY_MMD_LEDxL_PULSE_TXACT; 513 514 if (rules & BIT(TRIGGER_NETDEV_RX)) 515 lval |= XWAY_MMD_LEDxL_PULSE_RXACT; 516 517 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), hval); 518 if (ret) 519 return ret; 520 521 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), lval); 522 if (ret) 523 return ret; 524 525 return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_EN(index)); 526 } 527 528 static int xway_gphy_led_polarity_set(struct phy_device *phydev, int index, 529 unsigned long modes) 530 { 531 bool force_active_low = false, force_active_high = false; 532 u32 mode; 533 534 if (index >= XWAY_GPHY_MAX_LEDS) 535 return -EINVAL; 536 537 for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { 538 switch (mode) { 539 case PHY_LED_ACTIVE_LOW: 540 force_active_low = true; 541 break; 542 case PHY_LED_ACTIVE_HIGH: 543 force_active_high = true; 544 break; 545 default: 546 return -EINVAL; 547 } 548 } 549 550 if (force_active_low) 551 return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index)); 552 553 if (force_active_high) 554 return phy_clear_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index)); 555 556 return -EINVAL; 557 } 558 559 static int xway_gphy_update_stats(struct phy_device *phydev) 560 { 561 struct xway_gphy_priv *priv = phydev->priv; 562 int ret; 563 564 /* XWAY_MDIO_ERRCNT: 8-bit read-clear counter, SEL set to RXERR */ 565 ret = phy_read(phydev, XWAY_MDIO_ERRCNT); 566 if (ret < 0) 567 return ret; 568 569 priv->rx_errors += FIELD_GET(XWAY_MDIO_ERRCNT_COUNT, ret); 570 571 return 0; 572 } 573 574 static void xway_gphy_get_phy_stats(struct phy_device *phydev, 575 struct ethtool_eth_phy_stats *eth_stats, 576 struct ethtool_phy_stats *stats) 577 { 578 struct xway_gphy_priv *priv = phydev->priv; 579 580 eth_stats->SymbolErrorDuringCarrier = priv->rx_errors; 581 stats->rx_errors = priv->rx_errors; 582 } 583 584 static struct phy_driver xway_gphy[] = { 585 { 586 .phy_id = PHY_ID_PHY11G_1_3, 587 .phy_id_mask = 0xffffffff, 588 .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.3", 589 /* PHY_GBIT_FEATURES */ 590 .config_init = xway_gphy_config_init, 591 .probe = xway_gphy_probe, 592 .config_aneg = xway_gphy14_config_aneg, 593 .handle_interrupt = xway_gphy_handle_interrupt, 594 .config_intr = xway_gphy_config_intr, 595 .suspend = genphy_suspend, 596 .resume = genphy_resume, 597 .led_brightness_set = xway_gphy_led_brightness_set, 598 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 599 .led_hw_control_get = xway_gphy_led_hw_control_get, 600 .led_hw_control_set = xway_gphy_led_hw_control_set, 601 .led_polarity_set = xway_gphy_led_polarity_set, 602 .update_stats = xway_gphy_update_stats, 603 .get_phy_stats = xway_gphy_get_phy_stats, 604 }, { 605 .phy_id = PHY_ID_PHY22F_1_3, 606 .phy_id_mask = 0xffffffff, 607 .name = "Intel XWAY PHY22F (PEF 7061) v1.3", 608 /* PHY_BASIC_FEATURES */ 609 .config_init = xway_gphy_config_init, 610 .probe = xway_gphy_probe, 611 .config_aneg = xway_gphy14_config_aneg, 612 .handle_interrupt = xway_gphy_handle_interrupt, 613 .config_intr = xway_gphy_config_intr, 614 .suspend = genphy_suspend, 615 .resume = genphy_resume, 616 .led_brightness_set = xway_gphy_led_brightness_set, 617 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 618 .led_hw_control_get = xway_gphy_led_hw_control_get, 619 .led_hw_control_set = xway_gphy_led_hw_control_set, 620 .led_polarity_set = xway_gphy_led_polarity_set, 621 .update_stats = xway_gphy_update_stats, 622 .get_phy_stats = xway_gphy_get_phy_stats, 623 }, { 624 .phy_id = PHY_ID_PHY11G_1_4, 625 .phy_id_mask = 0xffffffff, 626 .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.4", 627 /* PHY_GBIT_FEATURES */ 628 .config_init = xway_gphy_config_init, 629 .probe = xway_gphy_probe, 630 .config_aneg = xway_gphy14_config_aneg, 631 .handle_interrupt = xway_gphy_handle_interrupt, 632 .config_intr = xway_gphy_config_intr, 633 .suspend = genphy_suspend, 634 .resume = genphy_resume, 635 .led_brightness_set = xway_gphy_led_brightness_set, 636 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 637 .led_hw_control_get = xway_gphy_led_hw_control_get, 638 .led_hw_control_set = xway_gphy_led_hw_control_set, 639 .led_polarity_set = xway_gphy_led_polarity_set, 640 .update_stats = xway_gphy_update_stats, 641 .get_phy_stats = xway_gphy_get_phy_stats, 642 }, { 643 .phy_id = PHY_ID_PHY22F_1_4, 644 .phy_id_mask = 0xffffffff, 645 .name = "Intel XWAY PHY22F (PEF 7061) v1.4", 646 /* PHY_BASIC_FEATURES */ 647 .config_init = xway_gphy_config_init, 648 .probe = xway_gphy_probe, 649 .config_aneg = xway_gphy14_config_aneg, 650 .handle_interrupt = xway_gphy_handle_interrupt, 651 .config_intr = xway_gphy_config_intr, 652 .suspend = genphy_suspend, 653 .resume = genphy_resume, 654 .led_brightness_set = xway_gphy_led_brightness_set, 655 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 656 .led_hw_control_get = xway_gphy_led_hw_control_get, 657 .led_hw_control_set = xway_gphy_led_hw_control_set, 658 .led_polarity_set = xway_gphy_led_polarity_set, 659 .update_stats = xway_gphy_update_stats, 660 .get_phy_stats = xway_gphy_get_phy_stats, 661 }, { 662 .phy_id = PHY_ID_PHY11G_1_5, 663 .phy_id_mask = 0xffffffff, 664 .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6", 665 /* PHY_GBIT_FEATURES */ 666 .config_init = xway_gphy_config_init, 667 .probe = xway_gphy_probe, 668 .handle_interrupt = xway_gphy_handle_interrupt, 669 .config_intr = xway_gphy_config_intr, 670 .suspend = genphy_suspend, 671 .resume = genphy_resume, 672 .led_brightness_set = xway_gphy_led_brightness_set, 673 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 674 .led_hw_control_get = xway_gphy_led_hw_control_get, 675 .led_hw_control_set = xway_gphy_led_hw_control_set, 676 .led_polarity_set = xway_gphy_led_polarity_set, 677 .update_stats = xway_gphy_update_stats, 678 .get_phy_stats = xway_gphy_get_phy_stats, 679 }, { 680 .phy_id = PHY_ID_PHY22F_1_5, 681 .phy_id_mask = 0xffffffff, 682 .name = "Intel XWAY PHY22F (PEF 7061) v1.5 / v1.6", 683 /* PHY_BASIC_FEATURES */ 684 .config_init = xway_gphy_config_init, 685 .probe = xway_gphy_probe, 686 .handle_interrupt = xway_gphy_handle_interrupt, 687 .config_intr = xway_gphy_config_intr, 688 .suspend = genphy_suspend, 689 .resume = genphy_resume, 690 .led_brightness_set = xway_gphy_led_brightness_set, 691 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 692 .led_hw_control_get = xway_gphy_led_hw_control_get, 693 .led_hw_control_set = xway_gphy_led_hw_control_set, 694 .led_polarity_set = xway_gphy_led_polarity_set, 695 .update_stats = xway_gphy_update_stats, 696 .get_phy_stats = xway_gphy_get_phy_stats, 697 }, { 698 .phy_id = PHY_ID_PHY11G_VR9_1_1, 699 .phy_id_mask = 0xffffffff, 700 .name = "Intel XWAY PHY11G (xRX v1.1 integrated)", 701 /* PHY_GBIT_FEATURES */ 702 .config_init = xway_gphy_config_init, 703 .probe = xway_gphy_probe, 704 .handle_interrupt = xway_gphy_handle_interrupt, 705 .config_intr = xway_gphy_config_intr, 706 .suspend = genphy_suspend, 707 .resume = genphy_resume, 708 .led_brightness_set = xway_gphy_led_brightness_set, 709 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 710 .led_hw_control_get = xway_gphy_led_hw_control_get, 711 .led_hw_control_set = xway_gphy_led_hw_control_set, 712 .led_polarity_set = xway_gphy_led_polarity_set, 713 .update_stats = xway_gphy_update_stats, 714 .get_phy_stats = xway_gphy_get_phy_stats, 715 }, { 716 .phy_id = PHY_ID_PHY22F_VR9_1_1, 717 .phy_id_mask = 0xffffffff, 718 .name = "Intel XWAY PHY22F (xRX v1.1 integrated)", 719 /* PHY_BASIC_FEATURES */ 720 .config_init = xway_gphy_config_init, 721 .probe = xway_gphy_probe, 722 .handle_interrupt = xway_gphy_handle_interrupt, 723 .config_intr = xway_gphy_config_intr, 724 .suspend = genphy_suspend, 725 .resume = genphy_resume, 726 .led_brightness_set = xway_gphy_led_brightness_set, 727 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 728 .led_hw_control_get = xway_gphy_led_hw_control_get, 729 .led_hw_control_set = xway_gphy_led_hw_control_set, 730 .led_polarity_set = xway_gphy_led_polarity_set, 731 .update_stats = xway_gphy_update_stats, 732 .get_phy_stats = xway_gphy_get_phy_stats, 733 }, { 734 .phy_id = PHY_ID_PHY11G_VR9_1_2, 735 .phy_id_mask = 0xffffffff, 736 .name = "Intel XWAY PHY11G (xRX v1.2 integrated)", 737 /* PHY_GBIT_FEATURES */ 738 .config_init = xway_gphy_config_init, 739 .probe = xway_gphy_probe, 740 .handle_interrupt = xway_gphy_handle_interrupt, 741 .config_intr = xway_gphy_config_intr, 742 .suspend = genphy_suspend, 743 .resume = genphy_resume, 744 .led_brightness_set = xway_gphy_led_brightness_set, 745 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 746 .led_hw_control_get = xway_gphy_led_hw_control_get, 747 .led_hw_control_set = xway_gphy_led_hw_control_set, 748 .led_polarity_set = xway_gphy_led_polarity_set, 749 .update_stats = xway_gphy_update_stats, 750 .get_phy_stats = xway_gphy_get_phy_stats, 751 }, { 752 .phy_id = PHY_ID_PHY22F_VR9_1_2, 753 .phy_id_mask = 0xffffffff, 754 .name = "Intel XWAY PHY22F (xRX v1.2 integrated)", 755 /* PHY_BASIC_FEATURES */ 756 .config_init = xway_gphy_config_init, 757 .probe = xway_gphy_probe, 758 .handle_interrupt = xway_gphy_handle_interrupt, 759 .config_intr = xway_gphy_config_intr, 760 .suspend = genphy_suspend, 761 .resume = genphy_resume, 762 .led_brightness_set = xway_gphy_led_brightness_set, 763 .led_hw_is_supported = xway_gphy_led_hw_is_supported, 764 .led_hw_control_get = xway_gphy_led_hw_control_get, 765 .led_hw_control_set = xway_gphy_led_hw_control_set, 766 .led_polarity_set = xway_gphy_led_polarity_set, 767 .update_stats = xway_gphy_update_stats, 768 .get_phy_stats = xway_gphy_get_phy_stats, 769 }, 770 }; 771 module_phy_driver(xway_gphy); 772 773 static const struct mdio_device_id __maybe_unused xway_gphy_tbl[] = { 774 { PHY_ID_PHY11G_1_3, 0xffffffff }, 775 { PHY_ID_PHY22F_1_3, 0xffffffff }, 776 { PHY_ID_PHY11G_1_4, 0xffffffff }, 777 { PHY_ID_PHY22F_1_4, 0xffffffff }, 778 { PHY_ID_PHY11G_1_5, 0xffffffff }, 779 { PHY_ID_PHY22F_1_5, 0xffffffff }, 780 { PHY_ID_PHY11G_VR9_1_1, 0xffffffff }, 781 { PHY_ID_PHY22F_VR9_1_1, 0xffffffff }, 782 { PHY_ID_PHY11G_VR9_1_2, 0xffffffff }, 783 { PHY_ID_PHY22F_VR9_1_2, 0xffffffff }, 784 { } 785 }; 786 MODULE_DEVICE_TABLE(mdio, xway_gphy_tbl); 787 788 MODULE_DESCRIPTION("Intel XWAY PHY driver"); 789 MODULE_LICENSE("GPL"); 790