843 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Driver for the Texas Instruments DP83822, DP83825 and DP83826 PHYs.3 *4 * Copyright (C) 2017 Texas Instruments Inc.5 */6 7#include <linux/ethtool.h>8#include <linux/etherdevice.h>9#include <linux/kernel.h>10#include <linux/mii.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/phy.h>14#include <linux/netdevice.h>15#include <linux/bitfield.h>16 17#define DP83822_PHY_ID 0x2000a24018#define DP83825S_PHY_ID 0x2000a14019#define DP83825I_PHY_ID 0x2000a15020#define DP83825CM_PHY_ID 0x2000a16021#define DP83825CS_PHY_ID 0x2000a17022#define DP83826C_PHY_ID 0x2000a13023#define DP83826NC_PHY_ID 0x2000a11024 25#define DP83822_DEVADDR 0x1f26 27#define MII_DP83822_CTRL_2 0x0a28#define MII_DP83822_PHYSTS 0x1029#define MII_DP83822_PHYSCR 0x1130#define MII_DP83822_MISR1 0x1231#define MII_DP83822_MISR2 0x1332#define MII_DP83822_FCSCR 0x1433#define MII_DP83822_RCSR 0x1734#define MII_DP83822_RESET_CTRL 0x1f35#define MII_DP83822_GENCFG 0x46536#define MII_DP83822_SOR1 0x46737 38/* DP83826 specific registers */39#define MII_DP83826_VOD_CFG1 0x30b40#define MII_DP83826_VOD_CFG2 0x30c41 42/* GENCFG */43#define DP83822_SIG_DET_LOW BIT(0)44 45/* Control Register 2 bits */46#define DP83822_FX_ENABLE BIT(14)47 48#define DP83822_SW_RESET BIT(15)49#define DP83822_DIG_RESTART BIT(14)50 51/* PHY STS bits */52#define DP83822_PHYSTS_DUPLEX BIT(2)53#define DP83822_PHYSTS_10 BIT(1)54#define DP83822_PHYSTS_LINK BIT(0)55 56/* PHYSCR Register Fields */57#define DP83822_PHYSCR_INT_OE BIT(0) /* Interrupt Output Enable */58#define DP83822_PHYSCR_INTEN BIT(1) /* Interrupt Enable */59 60/* MISR1 bits */61#define DP83822_RX_ERR_HF_INT_EN BIT(0)62#define DP83822_FALSE_CARRIER_HF_INT_EN BIT(1)63#define DP83822_ANEG_COMPLETE_INT_EN BIT(2)64#define DP83822_DUP_MODE_CHANGE_INT_EN BIT(3)65#define DP83822_SPEED_CHANGED_INT_EN BIT(4)66#define DP83822_LINK_STAT_INT_EN BIT(5)67#define DP83822_ENERGY_DET_INT_EN BIT(6)68#define DP83822_LINK_QUAL_INT_EN BIT(7)69 70/* MISR2 bits */71#define DP83822_JABBER_DET_INT_EN BIT(0)72#define DP83822_WOL_PKT_INT_EN BIT(1)73#define DP83822_SLEEP_MODE_INT_EN BIT(2)74#define DP83822_MDI_XOVER_INT_EN BIT(3)75#define DP83822_LB_FIFO_INT_EN BIT(4)76#define DP83822_PAGE_RX_INT_EN BIT(5)77#define DP83822_ANEG_ERR_INT_EN BIT(6)78#define DP83822_EEE_ERROR_CHANGE_INT_EN BIT(7)79 80/* INT_STAT1 bits */81#define DP83822_WOL_INT_EN BIT(4)82#define DP83822_WOL_INT_STAT BIT(12)83 84#define MII_DP83822_RXSOP1 0x04a585#define MII_DP83822_RXSOP2 0x04a686#define MII_DP83822_RXSOP3 0x04a787 88/* WoL Registers */89#define MII_DP83822_WOL_CFG 0x04a090#define MII_DP83822_WOL_STAT 0x04a191#define MII_DP83822_WOL_DA1 0x04a292#define MII_DP83822_WOL_DA2 0x04a393#define MII_DP83822_WOL_DA3 0x04a494 95/* WoL bits */96#define DP83822_WOL_MAGIC_EN BIT(0)97#define DP83822_WOL_SECURE_ON BIT(5)98#define DP83822_WOL_EN BIT(7)99#define DP83822_WOL_INDICATION_SEL BIT(8)100#define DP83822_WOL_CLR_INDICATION BIT(11)101 102/* RCSR bits */103#define DP83822_RMII_MODE_EN BIT(5)104#define DP83822_RMII_MODE_SEL BIT(7)105#define DP83822_RGMII_MODE_EN BIT(9)106#define DP83822_RX_CLK_SHIFT BIT(12)107#define DP83822_TX_CLK_SHIFT BIT(11)108 109/* SOR1 mode */110#define DP83822_STRAP_MODE1 0111#define DP83822_STRAP_MODE2 BIT(0)112#define DP83822_STRAP_MODE3 BIT(1)113#define DP83822_STRAP_MODE4 GENMASK(1, 0)114 115#define DP83822_COL_STRAP_MASK GENMASK(11, 10)116#define DP83822_COL_SHIFT 10117#define DP83822_RX_ER_STR_MASK GENMASK(9, 8)118#define DP83822_RX_ER_SHIFT 8119 120/* DP83826: VOD_CFG1 & VOD_CFG2 */121#define DP83826_VOD_CFG1_MINUS_MDIX_MASK GENMASK(13, 12)122#define DP83826_VOD_CFG1_MINUS_MDI_MASK GENMASK(11, 6)123#define DP83826_VOD_CFG2_MINUS_MDIX_MASK GENMASK(15, 12)124#define DP83826_VOD_CFG2_PLUS_MDIX_MASK GENMASK(11, 6)125#define DP83826_VOD_CFG2_PLUS_MDI_MASK GENMASK(5, 0)126#define DP83826_CFG_DAC_MINUS_MDIX_5_TO_4 GENMASK(5, 4)127#define DP83826_CFG_DAC_MINUS_MDIX_3_TO_0 GENMASK(3, 0)128#define DP83826_CFG_DAC_PERCENT_PER_STEP 625129#define DP83826_CFG_DAC_PERCENT_DEFAULT 10000130#define DP83826_CFG_DAC_MINUS_DEFAULT 0x30131#define DP83826_CFG_DAC_PLUS_DEFAULT 0x10132 133#define MII_DP83822_FIBER_ADVERTISE (ADVERTISED_TP | ADVERTISED_MII | \134 ADVERTISED_FIBRE | \135 ADVERTISED_Pause | ADVERTISED_Asym_Pause)136 137struct dp83822_private {138 bool fx_signal_det_low;139 int fx_enabled;140 u16 fx_sd_enable;141 u8 cfg_dac_minus;142 u8 cfg_dac_plus;143 struct ethtool_wolinfo wol;144};145 146static int dp83822_config_wol(struct phy_device *phydev,147 struct ethtool_wolinfo *wol)148{149 struct net_device *ndev = phydev->attached_dev;150 u16 value;151 const u8 *mac;152 153 if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {154 mac = (const u8 *)ndev->dev_addr;155 156 if (!is_valid_ether_addr(mac))157 return -EINVAL;158 159 /* MAC addresses start with byte 5, but stored in mac[0].160 * 822 PHYs store bytes 4|5, 2|3, 0|1161 */162 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA1,163 (mac[1] << 8) | mac[0]);164 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA2,165 (mac[3] << 8) | mac[2]);166 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA3,167 (mac[5] << 8) | mac[4]);168 169 value = phy_read_mmd(phydev, DP83822_DEVADDR,170 MII_DP83822_WOL_CFG);171 if (wol->wolopts & WAKE_MAGIC)172 value |= DP83822_WOL_MAGIC_EN;173 else174 value &= ~DP83822_WOL_MAGIC_EN;175 176 if (wol->wolopts & WAKE_MAGICSECURE) {177 phy_write_mmd(phydev, DP83822_DEVADDR,178 MII_DP83822_RXSOP1,179 (wol->sopass[1] << 8) | wol->sopass[0]);180 phy_write_mmd(phydev, DP83822_DEVADDR,181 MII_DP83822_RXSOP2,182 (wol->sopass[3] << 8) | wol->sopass[2]);183 phy_write_mmd(phydev, DP83822_DEVADDR,184 MII_DP83822_RXSOP3,185 (wol->sopass[5] << 8) | wol->sopass[4]);186 value |= DP83822_WOL_SECURE_ON;187 } else {188 value &= ~DP83822_WOL_SECURE_ON;189 }190 191 /* Clear any pending WoL interrupt */192 phy_read(phydev, MII_DP83822_MISR2);193 194 value |= DP83822_WOL_EN | DP83822_WOL_INDICATION_SEL |195 DP83822_WOL_CLR_INDICATION;196 197 return phy_write_mmd(phydev, DP83822_DEVADDR,198 MII_DP83822_WOL_CFG, value);199 } else {200 return phy_clear_bits_mmd(phydev, DP83822_DEVADDR,201 MII_DP83822_WOL_CFG,202 DP83822_WOL_EN |203 DP83822_WOL_MAGIC_EN |204 DP83822_WOL_SECURE_ON);205 }206}207 208static int dp83822_set_wol(struct phy_device *phydev,209 struct ethtool_wolinfo *wol)210{211 struct dp83822_private *dp83822 = phydev->priv;212 int ret;213 214 ret = dp83822_config_wol(phydev, wol);215 if (!ret)216 memcpy(&dp83822->wol, wol, sizeof(*wol));217 return ret;218}219 220static void dp83822_get_wol(struct phy_device *phydev,221 struct ethtool_wolinfo *wol)222{223 int value;224 u16 sopass_val;225 226 wol->supported = (WAKE_MAGIC | WAKE_MAGICSECURE);227 wol->wolopts = 0;228 229 value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);230 231 if (value & DP83822_WOL_MAGIC_EN)232 wol->wolopts |= WAKE_MAGIC;233 234 if (value & DP83822_WOL_SECURE_ON) {235 sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,236 MII_DP83822_RXSOP1);237 wol->sopass[0] = (sopass_val & 0xff);238 wol->sopass[1] = (sopass_val >> 8);239 240 sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,241 MII_DP83822_RXSOP2);242 wol->sopass[2] = (sopass_val & 0xff);243 wol->sopass[3] = (sopass_val >> 8);244 245 sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,246 MII_DP83822_RXSOP3);247 wol->sopass[4] = (sopass_val & 0xff);248 wol->sopass[5] = (sopass_val >> 8);249 250 wol->wolopts |= WAKE_MAGICSECURE;251 }252 253 /* WoL is not enabled so set wolopts to 0 */254 if (!(value & DP83822_WOL_EN))255 wol->wolopts = 0;256}257 258static int dp83822_config_intr(struct phy_device *phydev)259{260 struct dp83822_private *dp83822 = phydev->priv;261 int misr_status;262 int physcr_status;263 int err;264 265 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {266 misr_status = phy_read(phydev, MII_DP83822_MISR1);267 if (misr_status < 0)268 return misr_status;269 270 misr_status |= (DP83822_LINK_STAT_INT_EN |271 DP83822_ENERGY_DET_INT_EN |272 DP83822_LINK_QUAL_INT_EN);273 274 if (!dp83822->fx_enabled)275 misr_status |= DP83822_ANEG_COMPLETE_INT_EN |276 DP83822_DUP_MODE_CHANGE_INT_EN |277 DP83822_SPEED_CHANGED_INT_EN;278 279 280 err = phy_write(phydev, MII_DP83822_MISR1, misr_status);281 if (err < 0)282 return err;283 284 misr_status = phy_read(phydev, MII_DP83822_MISR2);285 if (misr_status < 0)286 return misr_status;287 288 misr_status |= (DP83822_JABBER_DET_INT_EN |289 DP83822_SLEEP_MODE_INT_EN |290 DP83822_LB_FIFO_INT_EN |291 DP83822_PAGE_RX_INT_EN |292 DP83822_EEE_ERROR_CHANGE_INT_EN);293 294 if (!dp83822->fx_enabled)295 misr_status |= DP83822_ANEG_ERR_INT_EN |296 DP83822_WOL_PKT_INT_EN;297 298 err = phy_write(phydev, MII_DP83822_MISR2, misr_status);299 if (err < 0)300 return err;301 302 physcr_status = phy_read(phydev, MII_DP83822_PHYSCR);303 if (physcr_status < 0)304 return physcr_status;305 306 physcr_status |= DP83822_PHYSCR_INT_OE | DP83822_PHYSCR_INTEN;307 308 } else {309 err = phy_write(phydev, MII_DP83822_MISR1, 0);310 if (err < 0)311 return err;312 313 err = phy_write(phydev, MII_DP83822_MISR2, 0);314 if (err < 0)315 return err;316 317 physcr_status = phy_read(phydev, MII_DP83822_PHYSCR);318 if (physcr_status < 0)319 return physcr_status;320 321 physcr_status &= ~DP83822_PHYSCR_INTEN;322 }323 324 return phy_write(phydev, MII_DP83822_PHYSCR, physcr_status);325}326 327static irqreturn_t dp83822_handle_interrupt(struct phy_device *phydev)328{329 bool trigger_machine = false;330 int irq_status;331 332 /* The MISR1 and MISR2 registers are holding the interrupt status in333 * the upper half (15:8), while the lower half (7:0) is used for334 * controlling the interrupt enable state of those individual interrupt335 * sources. To determine the possible interrupt sources, just read the336 * MISR* register and use it directly to know which interrupts have337 * been enabled previously or not.338 */339 irq_status = phy_read(phydev, MII_DP83822_MISR1);340 if (irq_status < 0) {341 phy_error(phydev);342 return IRQ_NONE;343 }344 if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))345 trigger_machine = true;346 347 irq_status = phy_read(phydev, MII_DP83822_MISR2);348 if (irq_status < 0) {349 phy_error(phydev);350 return IRQ_NONE;351 }352 if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))353 trigger_machine = true;354 355 if (!trigger_machine)356 return IRQ_NONE;357 358 phy_trigger_machine(phydev);359 360 return IRQ_HANDLED;361}362 363static int dp83822_read_status(struct phy_device *phydev)364{365 struct dp83822_private *dp83822 = phydev->priv;366 int status = phy_read(phydev, MII_DP83822_PHYSTS);367 int ctrl2;368 int ret;369 370 if (dp83822->fx_enabled) {371 if (status & DP83822_PHYSTS_LINK) {372 phydev->speed = SPEED_UNKNOWN;373 phydev->duplex = DUPLEX_UNKNOWN;374 } else {375 ctrl2 = phy_read(phydev, MII_DP83822_CTRL_2);376 if (ctrl2 < 0)377 return ctrl2;378 379 if (!(ctrl2 & DP83822_FX_ENABLE)) {380 ret = phy_write(phydev, MII_DP83822_CTRL_2,381 DP83822_FX_ENABLE | ctrl2);382 if (ret < 0)383 return ret;384 }385 }386 }387 388 ret = genphy_read_status(phydev);389 if (ret)390 return ret;391 392 if (status < 0)393 return status;394 395 if (status & DP83822_PHYSTS_DUPLEX)396 phydev->duplex = DUPLEX_FULL;397 else398 phydev->duplex = DUPLEX_HALF;399 400 if (status & DP83822_PHYSTS_10)401 phydev->speed = SPEED_10;402 else403 phydev->speed = SPEED_100;404 405 return 0;406}407 408static int dp83822_config_init(struct phy_device *phydev)409{410 struct dp83822_private *dp83822 = phydev->priv;411 struct device *dev = &phydev->mdio.dev;412 int rgmii_delay = 0;413 s32 rx_int_delay;414 s32 tx_int_delay;415 int err = 0;416 int bmcr;417 418 if (phy_interface_is_rgmii(phydev)) {419 rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,420 true);421 422 /* Set DP83822_RX_CLK_SHIFT to enable rx clk internal delay */423 if (rx_int_delay > 0)424 rgmii_delay |= DP83822_RX_CLK_SHIFT;425 426 tx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,427 false);428 429 /* Set DP83822_TX_CLK_SHIFT to disable tx clk internal delay */430 if (tx_int_delay <= 0)431 rgmii_delay |= DP83822_TX_CLK_SHIFT;432 433 err = phy_modify_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR,434 DP83822_RX_CLK_SHIFT | DP83822_TX_CLK_SHIFT, rgmii_delay);435 if (err)436 return err;437 438 err = phy_set_bits_mmd(phydev, DP83822_DEVADDR,439 MII_DP83822_RCSR, DP83822_RGMII_MODE_EN);440 441 if (err)442 return err;443 } else {444 err = phy_clear_bits_mmd(phydev, DP83822_DEVADDR,445 MII_DP83822_RCSR, DP83822_RGMII_MODE_EN);446 447 if (err)448 return err;449 }450 451 if (dp83822->fx_enabled) {452 err = phy_modify(phydev, MII_DP83822_CTRL_2,453 DP83822_FX_ENABLE, 1);454 if (err < 0)455 return err;456 457 /* Only allow advertising what this PHY supports */458 linkmode_and(phydev->advertising, phydev->advertising,459 phydev->supported);460 461 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,462 phydev->supported);463 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,464 phydev->advertising);465 linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT,466 phydev->supported);467 linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT,468 phydev->supported);469 linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT,470 phydev->advertising);471 linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT,472 phydev->advertising);473 474 /* Auto neg is not supported in fiber mode */475 bmcr = phy_read(phydev, MII_BMCR);476 if (bmcr < 0)477 return bmcr;478 479 if (bmcr & BMCR_ANENABLE) {480 err = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);481 if (err < 0)482 return err;483 }484 phydev->autoneg = AUTONEG_DISABLE;485 linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,486 phydev->supported);487 linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,488 phydev->advertising);489 490 /* Setup fiber advertisement */491 err = phy_modify_changed(phydev, MII_ADVERTISE,492 MII_DP83822_FIBER_ADVERTISE,493 MII_DP83822_FIBER_ADVERTISE);494 495 if (err < 0)496 return err;497 498 if (dp83822->fx_signal_det_low) {499 err = phy_set_bits_mmd(phydev, DP83822_DEVADDR,500 MII_DP83822_GENCFG,501 DP83822_SIG_DET_LOW);502 if (err)503 return err;504 }505 }506 return dp83822_config_wol(phydev, &dp83822->wol);507}508 509static int dp83826_config_rmii_mode(struct phy_device *phydev)510{511 struct device *dev = &phydev->mdio.dev;512 const char *of_val;513 int ret;514 515 if (!device_property_read_string(dev, "ti,rmii-mode", &of_val)) {516 if (strcmp(of_val, "master") == 0) {517 ret = phy_clear_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR,518 DP83822_RMII_MODE_SEL);519 } else if (strcmp(of_val, "slave") == 0) {520 ret = phy_set_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR,521 DP83822_RMII_MODE_SEL);522 } else {523 phydev_err(phydev, "Invalid value for ti,rmii-mode property (%s)\n",524 of_val);525 ret = -EINVAL;526 }527 528 if (ret)529 return ret;530 }531 532 return 0;533}534 535static int dp83826_config_init(struct phy_device *phydev)536{537 struct dp83822_private *dp83822 = phydev->priv;538 u16 val, mask;539 int ret;540 541 if (phydev->interface == PHY_INTERFACE_MODE_RMII) {542 ret = phy_set_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR,543 DP83822_RMII_MODE_EN);544 if (ret)545 return ret;546 547 ret = dp83826_config_rmii_mode(phydev);548 if (ret)549 return ret;550 } else {551 ret = phy_clear_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR,552 DP83822_RMII_MODE_EN);553 if (ret)554 return ret;555 }556 557 if (dp83822->cfg_dac_minus != DP83826_CFG_DAC_MINUS_DEFAULT) {558 val = FIELD_PREP(DP83826_VOD_CFG1_MINUS_MDI_MASK, dp83822->cfg_dac_minus) |559 FIELD_PREP(DP83826_VOD_CFG1_MINUS_MDIX_MASK,560 FIELD_GET(DP83826_CFG_DAC_MINUS_MDIX_5_TO_4,561 dp83822->cfg_dac_minus));562 mask = DP83826_VOD_CFG1_MINUS_MDIX_MASK | DP83826_VOD_CFG1_MINUS_MDI_MASK;563 ret = phy_modify_mmd(phydev, DP83822_DEVADDR, MII_DP83826_VOD_CFG1, mask, val);564 if (ret)565 return ret;566 567 val = FIELD_PREP(DP83826_VOD_CFG2_MINUS_MDIX_MASK,568 FIELD_GET(DP83826_CFG_DAC_MINUS_MDIX_3_TO_0,569 dp83822->cfg_dac_minus));570 mask = DP83826_VOD_CFG2_MINUS_MDIX_MASK;571 ret = phy_modify_mmd(phydev, DP83822_DEVADDR, MII_DP83826_VOD_CFG2, mask, val);572 if (ret)573 return ret;574 }575 576 if (dp83822->cfg_dac_plus != DP83826_CFG_DAC_PLUS_DEFAULT) {577 val = FIELD_PREP(DP83826_VOD_CFG2_PLUS_MDIX_MASK, dp83822->cfg_dac_plus) |578 FIELD_PREP(DP83826_VOD_CFG2_PLUS_MDI_MASK, dp83822->cfg_dac_plus);579 mask = DP83826_VOD_CFG2_PLUS_MDIX_MASK | DP83826_VOD_CFG2_PLUS_MDI_MASK;580 ret = phy_modify_mmd(phydev, DP83822_DEVADDR, MII_DP83826_VOD_CFG2, mask, val);581 if (ret)582 return ret;583 }584 585 return dp83822_config_wol(phydev, &dp83822->wol);586}587 588static int dp8382x_config_init(struct phy_device *phydev)589{590 struct dp83822_private *dp83822 = phydev->priv;591 592 return dp83822_config_wol(phydev, &dp83822->wol);593}594 595static int dp83822_phy_reset(struct phy_device *phydev)596{597 int err;598 599 err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_SW_RESET);600 if (err < 0)601 return err;602 603 return phydev->drv->config_init(phydev);604}605 606#ifdef CONFIG_OF_MDIO607static int dp83822_of_init(struct phy_device *phydev)608{609 struct dp83822_private *dp83822 = phydev->priv;610 struct device *dev = &phydev->mdio.dev;611 612 /* Signal detection for the PHY is only enabled if the FX_EN and the613 * SD_EN pins are strapped. Signal detection can only enabled if FX_EN614 * is strapped otherwise signal detection is disabled for the PHY.615 */616 if (dp83822->fx_enabled && dp83822->fx_sd_enable)617 dp83822->fx_signal_det_low = device_property_present(dev,618 "ti,link-loss-low");619 if (!dp83822->fx_enabled)620 dp83822->fx_enabled = device_property_present(dev,621 "ti,fiber-mode");622 623 return 0;624}625 626static int dp83826_to_dac_minus_one_regval(int percent)627{628 int tmp = DP83826_CFG_DAC_PERCENT_DEFAULT - percent;629 630 return tmp / DP83826_CFG_DAC_PERCENT_PER_STEP;631}632 633static int dp83826_to_dac_plus_one_regval(int percent)634{635 int tmp = percent - DP83826_CFG_DAC_PERCENT_DEFAULT;636 637 return tmp / DP83826_CFG_DAC_PERCENT_PER_STEP;638}639 640static void dp83826_of_init(struct phy_device *phydev)641{642 struct dp83822_private *dp83822 = phydev->priv;643 struct device *dev = &phydev->mdio.dev;644 u32 val;645 646 dp83822->cfg_dac_minus = DP83826_CFG_DAC_MINUS_DEFAULT;647 if (!device_property_read_u32(dev, "ti,cfg-dac-minus-one-bp", &val))648 dp83822->cfg_dac_minus += dp83826_to_dac_minus_one_regval(val);649 650 dp83822->cfg_dac_plus = DP83826_CFG_DAC_PLUS_DEFAULT;651 if (!device_property_read_u32(dev, "ti,cfg-dac-plus-one-bp", &val))652 dp83822->cfg_dac_plus += dp83826_to_dac_plus_one_regval(val);653}654#else655static int dp83822_of_init(struct phy_device *phydev)656{657 return 0;658}659 660static void dp83826_of_init(struct phy_device *phydev)661{662}663#endif /* CONFIG_OF_MDIO */664 665static int dp83822_read_straps(struct phy_device *phydev)666{667 struct dp83822_private *dp83822 = phydev->priv;668 int fx_enabled, fx_sd_enable;669 int val;670 671 val = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_SOR1);672 if (val < 0)673 return val;674 675 phydev_dbg(phydev, "SOR1 strap register: 0x%04x\n", val);676 677 fx_enabled = (val & DP83822_COL_STRAP_MASK) >> DP83822_COL_SHIFT;678 if (fx_enabled == DP83822_STRAP_MODE2 ||679 fx_enabled == DP83822_STRAP_MODE3)680 dp83822->fx_enabled = 1;681 682 if (dp83822->fx_enabled) {683 fx_sd_enable = (val & DP83822_RX_ER_STR_MASK) >> DP83822_RX_ER_SHIFT;684 if (fx_sd_enable == DP83822_STRAP_MODE3 ||685 fx_sd_enable == DP83822_STRAP_MODE4)686 dp83822->fx_sd_enable = 1;687 }688 689 return 0;690}691 692static int dp8382x_probe(struct phy_device *phydev)693{694 struct dp83822_private *dp83822;695 696 dp83822 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83822),697 GFP_KERNEL);698 if (!dp83822)699 return -ENOMEM;700 701 phydev->priv = dp83822;702 703 return 0;704}705 706static int dp83822_probe(struct phy_device *phydev)707{708 struct dp83822_private *dp83822;709 int ret;710 711 ret = dp8382x_probe(phydev);712 if (ret)713 return ret;714 715 dp83822 = phydev->priv;716 717 ret = dp83822_read_straps(phydev);718 if (ret)719 return ret;720 721 dp83822_of_init(phydev);722 723 if (dp83822->fx_enabled)724 phydev->port = PORT_FIBRE;725 726 return 0;727}728 729static int dp83826_probe(struct phy_device *phydev)730{731 int ret;732 733 ret = dp8382x_probe(phydev);734 if (ret)735 return ret;736 737 dp83826_of_init(phydev);738 739 return 0;740}741 742static int dp83822_suspend(struct phy_device *phydev)743{744 int value;745 746 value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);747 748 if (!(value & DP83822_WOL_EN))749 genphy_suspend(phydev);750 751 return 0;752}753 754static int dp83822_resume(struct phy_device *phydev)755{756 int value;757 758 genphy_resume(phydev);759 760 value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);761 762 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, value |763 DP83822_WOL_CLR_INDICATION);764 765 return 0;766}767 768#define DP83822_PHY_DRIVER(_id, _name) \769 { \770 PHY_ID_MATCH_MODEL(_id), \771 .name = (_name), \772 /* PHY_BASIC_FEATURES */ \773 .probe = dp83822_probe, \774 .soft_reset = dp83822_phy_reset, \775 .config_init = dp83822_config_init, \776 .read_status = dp83822_read_status, \777 .get_wol = dp83822_get_wol, \778 .set_wol = dp83822_set_wol, \779 .config_intr = dp83822_config_intr, \780 .handle_interrupt = dp83822_handle_interrupt, \781 .suspend = dp83822_suspend, \782 .resume = dp83822_resume, \783 }784 785#define DP83826_PHY_DRIVER(_id, _name) \786 { \787 PHY_ID_MATCH_MODEL(_id), \788 .name = (_name), \789 /* PHY_BASIC_FEATURES */ \790 .probe = dp83826_probe, \791 .soft_reset = dp83822_phy_reset, \792 .config_init = dp83826_config_init, \793 .get_wol = dp83822_get_wol, \794 .set_wol = dp83822_set_wol, \795 .config_intr = dp83822_config_intr, \796 .handle_interrupt = dp83822_handle_interrupt, \797 .suspend = dp83822_suspend, \798 .resume = dp83822_resume, \799 }800 801#define DP8382X_PHY_DRIVER(_id, _name) \802 { \803 PHY_ID_MATCH_MODEL(_id), \804 .name = (_name), \805 /* PHY_BASIC_FEATURES */ \806 .probe = dp8382x_probe, \807 .soft_reset = dp83822_phy_reset, \808 .config_init = dp8382x_config_init, \809 .get_wol = dp83822_get_wol, \810 .set_wol = dp83822_set_wol, \811 .config_intr = dp83822_config_intr, \812 .handle_interrupt = dp83822_handle_interrupt, \813 .suspend = dp83822_suspend, \814 .resume = dp83822_resume, \815 }816 817static struct phy_driver dp83822_driver[] = {818 DP83822_PHY_DRIVER(DP83822_PHY_ID, "TI DP83822"),819 DP8382X_PHY_DRIVER(DP83825I_PHY_ID, "TI DP83825I"),820 DP83826_PHY_DRIVER(DP83826C_PHY_ID, "TI DP83826C"),821 DP83826_PHY_DRIVER(DP83826NC_PHY_ID, "TI DP83826NC"),822 DP8382X_PHY_DRIVER(DP83825S_PHY_ID, "TI DP83825S"),823 DP8382X_PHY_DRIVER(DP83825CM_PHY_ID, "TI DP83825M"),824 DP8382X_PHY_DRIVER(DP83825CS_PHY_ID, "TI DP83825CS"),825};826module_phy_driver(dp83822_driver);827 828static struct mdio_device_id __maybe_unused dp83822_tbl[] = {829 { DP83822_PHY_ID, 0xfffffff0 },830 { DP83825I_PHY_ID, 0xfffffff0 },831 { DP83826C_PHY_ID, 0xfffffff0 },832 { DP83826NC_PHY_ID, 0xfffffff0 },833 { DP83825S_PHY_ID, 0xfffffff0 },834 { DP83825CM_PHY_ID, 0xfffffff0 },835 { DP83825CS_PHY_ID, 0xfffffff0 },836 { },837};838MODULE_DEVICE_TABLE(mdio, dp83822_tbl);839 840MODULE_DESCRIPTION("Texas Instruments DP83822 PHY driver");841MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com");842MODULE_LICENSE("GPL v2");843