diff options
Diffstat (limited to 'drivers/net/phy')
| -rw-r--r-- | drivers/net/phy/dp83867.c | 28 | ||||
| -rw-r--r-- | drivers/net/phy/micrel.c | 397 | ||||
| -rw-r--r-- | drivers/net/phy/mxl-gpy.c | 35 | ||||
| -rw-r--r-- | drivers/net/phy/phy_device.c | 4 | ||||
| -rw-r--r-- | drivers/net/phy/sfp.c | 48 | ||||
| -rw-r--r-- | drivers/net/phy/smsc.c | 33 | ||||
| -rw-r--r-- | drivers/net/phy/spi_ks8995.c | 2 |
7 files changed, 488 insertions, 59 deletions
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 89cd821f1f46..5821f04c69dc 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -693,6 +693,30 @@ static int dp83867_of_init(struct phy_device *phydev) } #endif /* CONFIG_OF_MDIO */ +static int dp83867_suspend(struct phy_device *phydev) +{ + /* Disable PHY Interrupts */ + if (phy_interrupt_is_valid(phydev)) { + phydev->interrupts = PHY_INTERRUPT_DISABLED; + dp83867_config_intr(phydev); + } + + return genphy_suspend(phydev); +} + +static int dp83867_resume(struct phy_device *phydev) +{ + /* Enable PHY Interrupts */ + if (phy_interrupt_is_valid(phydev)) { + phydev->interrupts = PHY_INTERRUPT_ENABLED; + dp83867_config_intr(phydev); + } + + genphy_resume(phydev); + + return 0; +} + static int dp83867_probe(struct phy_device *phydev) { struct dp83867_private *dp83867; @@ -968,8 +992,8 @@ static struct phy_driver dp83867_driver[] = { .config_intr = dp83867_config_intr, .handle_interrupt = dp83867_handle_interrupt, - .suspend = genphy_suspend, - .resume = genphy_resume, + .suspend = dp83867_suspend, + .resume = dp83867_resume, .link_change_notify = dp83867_link_change_notify, .set_loopback = dp83867_loopback, diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2c84fccef4f6..e26c6723caa4 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -318,6 +318,7 @@ struct kszphy_ptp_priv { struct ptp_clock_info ptp_clock_info; /* Lock for ptp_clock */ struct mutex ptp_lock; + struct ptp_pin_desc *pin_config; }; struct kszphy_priv { @@ -435,11 +436,9 @@ static int kszphy_config_intr(struct phy_device *phydev) if (err) return err; - temp = KSZPHY_INTCS_ALL; - err = phy_write(phydev, MII_KSZPHY_INTCS, temp); + err = phy_write(phydev, MII_KSZPHY_INTCS, KSZPHY_INTCS_ALL); } else { - temp = 0; - err = phy_write(phydev, MII_KSZPHY_INTCS, temp); + err = phy_write(phydev, MII_KSZPHY_INTCS, 0); if (err) return err; @@ -3658,6 +3657,77 @@ static int lan8841_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; } +#define LAN8841_EVENT_A 0 +#define LAN8841_EVENT_B 1 +#define LAN8841_PTP_LTC_TARGET_SEC_HI(event) ((event) == LAN8841_EVENT_A ? 278 : 288) +#define LAN8841_PTP_LTC_TARGET_SEC_LO(event) ((event) == LAN8841_EVENT_A ? 279 : 289) +#define LAN8841_PTP_LTC_TARGET_NS_HI(event) ((event) == LAN8841_EVENT_A ? 280 : 290) +#define LAN8841_PTP_LTC_TARGET_NS_LO(event) ((event) == LAN8841_EVENT_A ? 281 : 291) + +static int lan8841_ptp_set_target(struct kszphy_ptp_priv *ptp_priv, u8 event, + s64 sec, u32 nsec) +{ + struct phy_device *phydev = ptp_priv->phydev; + int ret; + + ret = phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_TARGET_SEC_HI(event), + upper_16_bits(sec)); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_TARGET_SEC_LO(event), + lower_16_bits(sec)); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_TARGET_NS_HI(event) & 0x3fff, + upper_16_bits(nsec)); + if (ret) + return ret; + + return phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_TARGET_NS_LO(event), + lower_16_bits(nsec)); +} + +#define LAN8841_BUFFER_TIME 2 + +static int lan8841_ptp_update_target(struct kszphy_ptp_priv *ptp_priv, + const struct timespec64 *ts) +{ + return lan8841_ptp_set_target(ptp_priv, LAN8841_EVENT_A, + ts->tv_sec + LAN8841_BUFFER_TIME, ts->tv_nsec); +} + +#define LAN8841_PTP_LTC_TARGET_RELOAD_SEC_HI(event) ((event) == LAN8841_EVENT_A ? 282 : 292) +#define LAN8841_PTP_LTC_TARGET_RELOAD_SEC_LO(event) ((event) == LAN8841_EVENT_A ? 283 : 293) +#define LAN8841_PTP_LTC_TARGET_RELOAD_NS_HI(event) ((event) == LAN8841_EVENT_A ? 284 : 294) +#define LAN8841_PTP_LTC_TARGET_RELOAD_NS_LO(event) ((event) == LAN8841_EVENT_A ? 285 : 295) + +static int lan8841_ptp_set_reload(struct kszphy_ptp_priv *ptp_priv, u8 event, + s64 sec, u32 nsec) +{ + struct phy_device *phydev = ptp_priv->phydev; + int ret; + + ret = phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_TARGET_RELOAD_SEC_HI(event), + upper_16_bits(sec)); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_TARGET_RELOAD_SEC_LO(event), + lower_16_bits(sec)); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_TARGET_RELOAD_NS_HI(event) & 0x3fff, + upper_16_bits(nsec)); + if (ret) + return ret; + + return phy_write_mmd(phydev, 2, LAN8841_PTP_LTC_TARGET_RELOAD_NS_LO(event), + lower_16_bits(nsec)); +} + #define LAN8841_PTP_LTC_SET_SEC_HI 262 #define LAN8841_PTP_LTC_SET_SEC_MID 263 #define LAN8841_PTP_LTC_SET_SEC_LO 264 @@ -3671,6 +3741,7 @@ static int lan8841_ptp_settime64(struct ptp_clock_info *ptp, struct kszphy_ptp_priv *ptp_priv = container_of(ptp, struct kszphy_ptp_priv, ptp_clock_info); struct phy_device *phydev = ptp_priv->phydev; + int ret; /* Set the value to be stored */ mutex_lock(&ptp_priv->ptp_lock); @@ -3683,9 +3754,10 @@ static int lan8841_ptp_settime64(struct ptp_clock_info *ptp, /* Set the command to load the LTC */ phy_write_mmd(phydev, 2, LAN8841_PTP_CMD_CTL, LAN8841_PTP_CMD_CTL_PTP_LTC_LOAD); + ret = lan8841_ptp_update_target(ptp_priv, ts); mutex_unlock(&ptp_priv->ptp_lock); - return 0; + return ret; } #define LAN8841_PTP_LTC_RD_SEC_HI 358 @@ -3740,6 +3812,7 @@ static int lan8841_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) bool add = true; u32 nsec; s32 sec; + int ret; /* The HW allows up to 15 sec to adjust the time, but here we limit to * 10 sec the adjustment. The reason is, in case the adjustment is 14 @@ -3803,7 +3876,13 @@ static int lan8841_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) } mutex_unlock(&ptp_priv->ptp_lock); - return 0; + /* Update the target clock */ + ptp->gettime64(ptp, &ts); + mutex_lock(&ptp_priv->ptp_lock); + ret = lan8841_ptp_update_target(ptp_priv, &ts); + mutex_unlock(&ptp_priv->ptp_lock); + + return ret; } #define LAN8841_PTP_LTC_RATE_ADJ_HI 269 @@ -3839,6 +3918,292 @@ static int lan8841_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) return 0; } +static int lan8841_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin, + enum ptp_pin_function func, unsigned int chan) +{ + switch (func) { + case PTP_PF_NONE: + case PTP_PF_PEROUT: + break; + default: + return -1; + } + + return 0; +} + +#define LAN8841_PTP_GPIO_NUM 10 +#define LAN8841_GPIO_EN 128 +#define LAN8841_GPIO_DIR 129 +#define LAN8841_GPIO_BUF 130 + +static int lan8841_ptp_perout_off(struct kszphy_ptp_priv *ptp_priv, int pin) +{ + struct phy_device *phydev = ptp_priv->phydev; + int ret; + + ret = phy_clear_bits_mmd(phydev, 2, LAN8841_GPIO_EN, BIT(pin)); + if (ret) + return ret; + + ret = phy_clear_bits_mmd(phydev, 2, LAN8841_GPIO_DIR, BIT(pin)); + if (ret) + return ret; + + return phy_clear_bits_mmd(phydev, 2, LAN8841_GPIO_BUF, BIT(pin)); +} + +static int lan8841_ptp_perout_on(struct kszphy_ptp_priv *ptp_priv, int pin) +{ + struct phy_device *phydev = ptp_priv->phydev; + int ret; + + ret = phy_set_bits_mmd(phydev, 2, LAN8841_GPIO_EN, BIT(pin)); + if (ret) + return ret; + + ret = phy_set_bits_mmd(phydev, 2, LAN8841_GPIO_DIR, BIT(pin)); + if (ret) + return ret; + + return phy_set_bits_mmd(phydev, 2, LAN8841_GPIO_BUF, BIT(pin)); +} + +#define LAN8841_GPIO_DATA_SEL1 131 +#define LAN8841_GPIO_DATA_SEL2 132 +#define LAN8841_GPIO_DATA_SEL_GPIO_DATA_SEL_EVENT_MASK GENMASK(2, 0) +#define LAN8841_GPIO_DATA_SEL_GPIO_DATA_SEL_EVENT_A 1 +#define LAN8841_GPIO_DATA_SEL_GPIO_DATA_SEL_EVENT_B 2 +#define LAN8841_PTP_GENERAL_CONFIG 257 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_A BIT(1) +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_B BIT(3) +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_A_MASK GENMASK(7, 4) +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_B_MASK GENMASK(11, 8) +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_A 4 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_B 7 + +static int lan8841_ptp_remove_event(struct kszphy_ptp_priv *ptp_priv, int pin, + u8 event) +{ + struct phy_device *phydev = ptp_priv->phydev; + u16 tmp; + int ret; + + /* Now remove pin from the event. GPIO_DATA_SEL1 contains the GPIO + * pins 0-4 while GPIO_DATA_SEL2 contains GPIO pins 5-9, therefore + * depending on the pin, it requires to read a different register + */ + if (pin < 5) { + tmp = LAN8841_GPIO_DATA_SEL_GPIO_DATA_SEL_EVENT_MASK << (3 * pin); + ret = phy_clear_bits_mmd(phydev, 2, LAN8841_GPIO_DATA_SEL1, tmp); + } else { + tmp = LAN8841_GPIO_DATA_SEL_GPIO_DATA_SEL_EVENT_MASK << (3 * (pin - 5)); + ret = phy_clear_bits_mmd(phydev, 2, LAN8841_GPIO_DATA_SEL2, tmp); + } + if (ret) + return ret; + + /* Disable the event */ + if (event == LAN8841_EVENT_A) + tmp = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_A | + LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_A_MASK; + else + tmp = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_B | + LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_B_MASK; + return phy_clear_bits_mmd(phydev, 2, LAN8841_GPIO_EN, tmp); +} + +static int lan8841_ptp_enable_event(struct kszphy_ptp_priv *ptp_priv, int pin, + u8 event, int pulse_width) +{ + struct phy_device *phydev = ptp_priv->phydev; + u16 tmp; + int ret; + + /* Enable the event */ + if (event == LAN8841_EVENT_A) + ret = phy_modify_mmd(phydev, 2, LAN8841_PTP_GENERAL_CONFIG, + LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_A | + LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_A_MASK, + LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_A | + pulse_width << LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_A); + else + ret = phy_modify_mmd(phydev, 2, LAN8841_PTP_GENERAL_CONFIG, + LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_B | + LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_B_MASK, + LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_POL_B | + pulse_width << LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_B); + if (ret) + return ret; + + /* Now connect the pin to the event. GPIO_DATA_SEL1 contains the GPIO + * pins 0-4 while GPIO_DATA_SEL2 contains GPIO pins 5-9, therefore + * depending on the pin, it requires to read a different register + */ + if (event == LAN8841_EVENT_A) + tmp = LAN8841_GPIO_DATA_SEL_GPIO_DATA_SEL_EVENT_A; + else + tmp = LAN8841_GPIO_DATA_SEL_GPIO_DATA_SEL_EVENT_B; + + if (pin < 5) + ret = phy_set_bits_mmd(phydev, 2, LAN8841_GPIO_DATA_SEL1, + tmp << (3 * pin)); + else + ret = phy_set_bits_mmd(phydev, 2, LAN8841_GPIO_DATA_SEL2, + tmp << (3 * (pin - 5))); + + return ret; +} + +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_200MS 13 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_100MS 12 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_50MS 11 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_10MS 10 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_5MS 9 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_1MS 8 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_500US 7 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_100US 6 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_50US 5 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_10US 4 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_5US 3 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_1US 2 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_500NS 1 +#define LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_100NS 0 + +static int lan8841_ptp_perout(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct kszphy_ptp_priv *ptp_priv = container_of(ptp, struct kszphy_ptp_priv, + ptp_clock_info); + struct phy_device *phydev = ptp_priv->phydev; + struct timespec64 ts_on, ts_period; + s64 on_nsec, period_nsec; + int pulse_width; + int pin; + int ret; + + if (rq->perout.flags & ~PTP_PEROUT_DUTY_CYCLE) + return -EOPNOTSUPP; + + pin = ptp_find_pin(ptp_priv->ptp_clock, PTP_PF_PEROUT, rq->perout.index); + if (pin == -1 || pin >= LAN8841_PTP_GPIO_NUM) + return -EINVAL; + + if (!on) { + ret = lan8841_ptp_perout_off(ptp_priv, pin); + if (ret) + return ret; + + return lan8841_ptp_remove_event(ptp_priv, LAN8841_EVENT_A, pin); + } + + ts_on.tv_sec = rq->perout.on.sec; + ts_on.tv_nsec = rq->perout.on.nsec; + on_nsec = timespec64_to_ns(&ts_on); + + ts_period.tv_sec = rq->perout.period.sec; + ts_period.tv_nsec = rq->perout.period.nsec; + period_nsec = timespec64_to_ns(&ts_period); + + if (period_nsec < 200) { + pr_warn_ratelimited("%s: perout period too small, minimum is 200 nsec\n", + phydev_name(phydev)); + return -EOPNOTSUPP; + } + + if (on_nsec >= period_nsec) { + pr_warn_ratelimited("%s: pulse width must be smaller than period\n", + phydev_name(phydev)); + return -EINVAL; + } + + switch (on_nsec) { + case 200000000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_200MS; + break; + case 100000000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_100MS; + break; + case 50000000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_50MS; + break; + case 10000000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_10MS; + break; + case 5000000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_5MS; + break; + case 1000000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_1MS; + break; + case 500000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_500US; + break; + case 100000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_100US; + break; + case 50000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_50US; + break; + case 10000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_10US; + break; + case 5000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_5US; + break; + case 1000: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_1US; + break; + case 500: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_500NS; + break; + case 100: + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_100NS; + break; + default: + pr_warn_ratelimited("%s: Use default duty cycle of 100ns\n", + phydev_name(phydev)); + pulse_width = LAN8841_PTP_GENERAL_CONFIG_LTC_EVENT_100NS; + break; + } + + mutex_lock(&ptp_priv->ptp_lock); + ret = lan8841_ptp_set_target(ptp_priv, LAN8841_EVENT_A, rq->perout.start.sec, + rq->perout.start.nsec); + mutex_unlock(&ptp_priv->ptp_lock); + if (ret) + return ret; + + ret = lan8841_ptp_set_reload(ptp_priv, LAN8841_EVENT_A, rq->perout.period.sec, + rq->perout.period.nsec); + if (ret) + return ret; + + ret = lan8841_ptp_enable_event(ptp_priv, pin, LAN8841_EVENT_A, + pulse_width); + if (ret) + return ret; + + ret = lan8841_ptp_perout_on(ptp_priv, pin); + if (ret) + lan8841_ptp_remove_event(ptp_priv, pin, LAN8841_EVENT_A); + + return ret; +} + +static int lan8841_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + switch (rq->type) { + case PTP_CLK_REQ_PEROUT: + return lan8841_ptp_perout(ptp, rq, on); + default: + return -EOPNOTSUPP; + } + + return 0; +} + static struct ptp_clock_info lan8841_ptp_clock_info = { .owner = THIS_MODULE, .name = "lan8841 ptp", @@ -3847,6 +4212,10 @@ static struct ptp_clock_info lan8841_ptp_clock_info = { .settime64 = lan8841_ptp_settime64, .adjtime = lan8841_ptp_adjtime, .adjfine = lan8841_ptp_adjfine, + .verify = lan8841_ptp_verify, + .enable = lan8841_ptp_enable, + .n_per_out = LAN8841_PTP_GPIO_NUM, + .n_pins = LAN8841_PTP_GPIO_NUM, }; #define LAN8841_OPERATION_MODE_STRAP_LOW_REGISTER 3 @@ -3874,7 +4243,23 @@ static int lan8841_probe(struct phy_device *phydev) priv = phydev->priv; ptp_priv = &priv->ptp_priv; + ptp_priv->pin_config = devm_kcalloc(&phydev->mdio.dev, + LAN8841_PTP_GPIO_NUM, + sizeof(*ptp_priv->pin_config), + GFP_KERNEL); + if (!ptp_priv->pin_config) + return -ENOMEM; + + for (int i = 0; i < LAN8841_PTP_GPIO_NUM; ++i) { + struct ptp_pin_desc *p = &ptp_priv->pin_config[i]; + + snprintf(p->name, sizeof(p->name), "pin%d", i); + p->index = i; + p->func = PTP_PF_NONE; + } + ptp_priv->ptp_clock_info = lan8841_ptp_clock_info; + ptp_priv->ptp_clock_info.pin_config = ptp_priv->pin_config; ptp_priv->ptp_clock = ptp_clock_register(&ptp_priv->ptp_clock_info, &phydev->mdio.dev); if (IS_ERR(ptp_priv->ptp_clock)) { diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c index e5972b4ef6e8..8e6bb97b5f85 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -107,6 +107,13 @@ struct gpy_priv { u8 fw_major; u8 fw_minor; + + /* It takes 3 seconds to fully switch out of loopback mode before + * it can safely re-enter loopback mode. Record the time when + * loopback is disabled. Check and wait if necessary before loopback + * is enabled. + */ + u64 lb_dis_to; }; static const struct { @@ -769,18 +776,34 @@ static void gpy_get_wol(struct phy_device *phydev, static int gpy_loopback(struct phy_device *phydev, bool enable) { + struct gpy_priv *priv = phydev->priv; + u16 set = 0; int ret; - ret = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, - enable ? BMCR_LOOPBACK : 0); - if (!ret) { - /* It takes some time for PHY device to switch - * into/out-of loopback mode. + if (enable) { + u64 now = get_jiffies_64(); + + /* wait until 3 seconds from last disable */ + if (time_before64(now, priv->lb_dis_to)) + msleep(jiffies64_to_msecs(priv->lb_dis_to - now)); + + set = BMCR_LOOPBACK; + } + + ret = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, set); + if (ret <= 0) + return ret; + + if (enable) { + /* It takes some time for PHY device to switch into + * loopback mode. */ msleep(100); + } else { + priv->lb_dis_to = get_jiffies_64() + HZ * 3; } - return ret; + return 0; } static int gpy115_loopback(struct phy_device *phydev, bool enable) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 1785f1cead97..c0760cbf534b 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -3076,9 +3076,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_phy_node); * phy_probe - probe and init a PHY device * @dev: device to probe and init * - * Description: Take care of setting up the phy_device structure, - * set the state to READY (the driver's init function should - * set it to STARTING if needed). + * Take care of setting up the phy_device structure, set the state to READY. */ static int phy_probe(struct device *dev) { diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index c02cad6478a8..39e3095796d0 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -255,6 +255,8 @@ struct sfp { unsigned int module_power_mW; unsigned int module_t_start_up; unsigned int module_t_wait; + + bool have_a2; bool tx_fault_ignore; const struct sfp_quirk *quirk; @@ -1453,20 +1455,10 @@ static void sfp_hwmon_probe(struct work_struct *work) static int sfp_hwmon_insert(struct sfp *sfp) { - if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE) - return 0; - - if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) - return 0; - - if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) - /* This driver in general does not support address - * change. - */ - return 0; - - mod_delayed_work(system_wq, &sfp->hwmon_probe, 1); - sfp->hwmon_tries = R_PROBE_RETRY_SLOW; + if (sfp->have_a2 && sfp->id.ext.diagmon & SFP_DIAGMON_DDM) { + mod_delayed_work(system_wq, &sfp->hwmon_probe, 1); + sfp->hwmon_tries = R_PROBE_RETRY_SLOW; + } return 0; } @@ -1916,6 +1908,18 @@ static int sfp_cotsworks_fixup_check(struct sfp *sfp, struct sfp_eeprom_id *id) return 0; } +static int sfp_module_parse_sff8472(struct sfp *sfp) +{ + /* If the module requires address swap mode, warn about it */ + if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) + dev_warn(sfp->dev, + "module address swap to access page 0xA2 is not supported.\n"); + else + sfp->have_a2 = true; + + return 0; +} + static int sfp_sm_mod_probe(struct sfp *sfp, bool report) { /* SFP module inserted - read I2C data */ @@ -2053,10 +2057,11 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) return -EINVAL; } - /* If the module requires address swap mode, warn about it */ - if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) - dev_warn(sfp->dev, - "module address swap to access page 0xA2 is not supported.\n"); + if (sfp->id.ext.sff8472_compliance != SFP_SFF8472_COMPLIANCE_NONE) { + ret = sfp_module_parse_sff8472(sfp); + if (ret < 0) + return ret; + } /* Parse the module power requirement */ ret = sfp_module_parse_power(sfp); @@ -2103,6 +2108,7 @@ static void sfp_sm_mod_remove(struct sfp *sfp) memset(&sfp->id, 0, sizeof(sfp->id)); sfp->module_power_mW = 0; + sfp->have_a2 = false; dev_info(sfp->dev, "module removed\n"); } @@ -2278,7 +2284,11 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) sfp->sm_dev_state != SFP_DEV_UP) break; - if (!(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)) + /* Only use the soft state bits if we have access to the A2h + * memory, which implies that we have some level of SFF-8472 + * compliance. + */ + if (sfp->have_a2) sfp_soft_start_poll(sfp); sfp_module_tx_enable(sfp); diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index df2c5435c5c4..721871184205 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -99,20 +99,13 @@ static irqreturn_t smsc_phy_handle_interrupt(struct phy_device *phydev) static int smsc_phy_config_init(struct phy_device *phydev) { struct smsc_phy_priv *priv = phydev->priv; - int rc; if (!priv->energy_enable || phydev->irq != PHY_POLL) return 0; - rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); - - if (rc < 0) - return rc; - - /* Enable energy detect mode for this SMSC Transceivers */ - rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, - rc | MII_LAN83C185_EDPWRDOWN); - return rc; + /* Enable energy detect power down mode */ + return phy_set_bits(phydev, MII_LAN83C185_CTRL_STATUS, + MII_LAN83C185_EDPWRDOWN); } static int smsc_phy_reset(struct phy_device *phydev) @@ -170,18 +163,15 @@ static int lan87xx_config_aneg(struct phy_device *phydev) static int lan95xx_config_aneg_ext(struct phy_device *phydev) { - int rc; + if (phydev->phy_id == 0x0007c0f0) { /* LAN9500A or LAN9505A */ + /* Extend Manual AutoMDIX timer */ + int rc = phy_set_bits(phydev, PHY_EDPD_CONFIG, + PHY_EDPD_CONFIG_EXT_CROSSOVER_); - if (phydev->phy_id != 0x0007c0f0) /* not (LAN9500A or LAN9505A) */ - return lan87xx_config_aneg(phydev); - - /* Extend Manual AutoMDIX timer */ - rc = phy_read(phydev, PHY_EDPD_CONFIG); - if (rc < 0) - return rc; + if (rc < 0) + return rc; + } - rc |= PHY_EDPD_CONFIG_EXT_CROSSOVER_; - phy_write(phydev, PHY_EDPD_CONFIG, rc); return lan87xx_config_aneg(phydev); } @@ -282,7 +272,6 @@ static void smsc_get_stats(struct phy_device *phydev, static int smsc_phy_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; - struct device_node *of_node = dev->of_node; struct smsc_phy_priv *priv; struct clk *refclk; @@ -292,7 +281,7 @@ static int smsc_phy_probe(struct phy_device *phydev) priv->energy_enable = true; - if (of_property_read_bool(of_node, "smsc,disable-energy-detect")) + if (device_property_present(dev, "smsc,disable-energy-detect")) priv->energy_enable = false; phydev->priv = priv; diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c index d4202d40d47a..7196e927c2cd 100644 --- a/drivers/net/phy/spi_ks8995.c +++ b/drivers/net/phy/spi_ks8995.c @@ -491,7 +491,7 @@ static void ks8995_remove(struct spi_device *spi) static struct spi_driver ks8995_driver = { .driver = { .name = "spi-ks8995", - .of_match_table = of_match_ptr(ks8895_spi_of_match), + .of_match_table = ks8895_spi_of_match, }, .probe = ks8995_probe, .remove = ks8995_remove, |
