diff options
Diffstat (limited to 'drivers/net/phy')
26 files changed, 1531 insertions, 225 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 54874555c921..93b8efc79227 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -44,6 +44,12 @@ config LED_TRIGGER_PHY <Speed in megabits>Mbps OR <Speed in gigabits>Gbps OR link for any speed known to the PHY. +config PHYLIB_LEDS + def_bool OF + depends on LEDS_CLASS=y || LEDS_CLASS=PHYLIB + help + When LED class support is enabled, phylib can automatically + probe LED setting from device tree. config FIXED_PHY tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs" @@ -70,6 +76,7 @@ config AMD_PHY config MESON_GXL_PHY tristate "Amlogic Meson GXL Internal PHY" depends on ARCH_MESON || COMPILE_TEST + select SMSC_PHY help Currently has a driver for the Amlogic Meson GXL Internal PHY @@ -235,6 +242,11 @@ config MICREL_PHY help Supports the KSZ9021, VSC8201, KS8001 PHYs. +config MICROCHIP_T1S_PHY + tristate "Microchip 10BASE-T1S Ethernet PHY" + help + Currently supports the LAN8670, LAN8671, LAN8672 + config MICROCHIP_PHY tristate "Microchip PHYs" help @@ -264,6 +276,12 @@ config NATIONAL_PHY help Currently supports the DP83865 PHY. +config NXP_CBTX_PHY + tristate "NXP 100BASE-TX PHYs" + help + Support the 100BASE-TX PHY integrated on the SJA1110 automotive + switch family. + config NXP_C45_TJA11XX_PHY tristate "NXP C45 TJA11XX PHYs" depends on PTP_1588_CLOCK_OPTIONAL diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index b5138066ba04..f289ab16a1da 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -74,11 +74,13 @@ obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o obj-$(CONFIG_MICREL_PHY) += micrel.o obj-$(CONFIG_MICROCHIP_PHY) += microchip.o obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o +obj-$(CONFIG_MICROCHIP_T1S_PHY) += microchip_t1s.o obj-$(CONFIG_MICROSEMI_PHY) += mscc/ obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o obj-$(CONFIG_NATIONAL_PHY) += national.o obj-$(CONFIG_NCN26000_PHY) += ncn26000.o obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja11xx.o +obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_REALTEK_PHY) += realtek.o diff --git a/drivers/net/phy/aquantia_hwmon.c b/drivers/net/phy/aquantia_hwmon.c index 19c4c280a6cd..0da451e46f69 100644 --- a/drivers/net/phy/aquantia_hwmon.c +++ b/drivers/net/phy/aquantia_hwmon.c @@ -210,7 +210,7 @@ static const struct hwmon_channel_info aqr_hwmon_temp = { .config = aqr_hwmon_temp_config, }; -static const struct hwmon_channel_info *aqr_hwmon_info[] = { +static const struct hwmon_channel_info * const aqr_hwmon_info[] = { &aqr_hwmon_chip, &aqr_hwmon_temp, NULL, diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 22f4458274aa..656136628ffd 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -13,12 +13,11 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool_netlink.h> -#include <linux/of_gpio.h> #include <linux/bitfield.h> -#include <linux/gpio/consumer.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/driver.h> #include <linux/regulator/consumer.h> +#include <linux/of.h> #include <linux/phylink.h> #include <linux/sfp.h> #include <dt-bindings/net/qca-ar803x.h> diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index 9902fb182099..729db441797a 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -40,6 +40,11 @@ static inline int bcm_phy_write_exp_sel(struct phy_device *phydev, return bcm_phy_write_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER, val); } +static inline int bcm_phy_read_exp_sel(struct phy_device *phydev, u16 reg) +{ + return bcm_phy_read_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER); +} + int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val); int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum); diff --git a/drivers/net/phy/bcm54140.c b/drivers/net/phy/bcm54140.c index d8f3024860dc..d43076592f81 100644 --- a/drivers/net/phy/bcm54140.c +++ b/drivers/net/phy/bcm54140.c @@ -364,7 +364,7 @@ static int bcm54140_hwmon_write(struct device *dev, } } -static const struct hwmon_channel_info *bcm54140_hwmon_info[] = { +static const struct hwmon_channel_info * const bcm54140_hwmon_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM), diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 75593e7d1118..f8c17a253f8b 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -45,7 +45,6 @@ struct bcm7xxx_phy_priv { u64 *stats; - struct clk *clk; }; static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev) @@ -487,7 +486,7 @@ static int bcm7xxx_16nm_ephy_afe_config(struct phy_device *phydev) bcm_phy_write_misc(phydev, 0x0038, 0x0002, 0xede0); /* Read CORE_EXPA9 */ - tmp = bcm_phy_read_exp(phydev, 0x00a9); + tmp = bcm_phy_read_exp_sel(phydev, 0x00a9); /* CORE_EXPA9[6:1] is rcalcode[5:0] */ rcalcode = (tmp & 0x7e) / 2; /* Correct RCAL code + 1 is -1% rprogr, LP: +16 */ @@ -811,6 +810,7 @@ static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev, static int bcm7xxx_28nm_probe(struct phy_device *phydev) { struct bcm7xxx_phy_priv *priv; + struct clk *clk; int ret = 0; priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); @@ -825,13 +825,9 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev) if (!priv->stats) return -ENOMEM; - priv->clk = devm_clk_get_optional(&phydev->mdio.dev, NULL); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; + clk = devm_clk_get_optional_enabled(&phydev->mdio.dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); /* Dummy read to a register to workaround an issue upon reset where the * internal inverter may not allow the first MDIO transaction to pass @@ -844,13 +840,6 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev) return ret; } -static void bcm7xxx_28nm_remove(struct phy_device *phydev) -{ - struct bcm7xxx_phy_priv *priv = phydev->priv; - - clk_disable_unprepare(priv->clk); -} - #define BCM7XXX_28NM_GPHY(_oui, _name) \ { \ .phy_id = (_oui), \ @@ -866,7 +855,6 @@ static void bcm7xxx_28nm_remove(struct phy_device *phydev) .get_strings = bcm_phy_get_strings, \ .get_stats = bcm7xxx_28nm_get_phy_stats, \ .probe = bcm7xxx_28nm_probe, \ - .remove = bcm7xxx_28nm_remove, \ } #define BCM7XXX_28NM_EPHY(_oui, _name) \ @@ -882,7 +870,6 @@ static void bcm7xxx_28nm_remove(struct phy_device *phydev) .get_strings = bcm_phy_get_strings, \ .get_stats = bcm7xxx_28nm_get_phy_stats, \ .probe = bcm7xxx_28nm_probe, \ - .remove = bcm7xxx_28nm_remove, \ .read_mmd = bcm7xxx_28nm_ephy_read_mmd, \ .write_mmd = bcm7xxx_28nm_ephy_write_mmd, \ } @@ -908,7 +895,6 @@ static void bcm7xxx_28nm_remove(struct phy_device *phydev) /* PHY_BASIC_FEATURES */ \ .flags = PHY_IS_INTERNAL, \ .probe = bcm7xxx_28nm_probe, \ - .remove = bcm7xxx_28nm_remove, \ .config_init = bcm7xxx_16nm_ephy_config_init, \ .config_aneg = genphy_config_aneg, \ .read_status = genphy_read_status, \ diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 89cd821f1f46..d75f526a20a4 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -26,6 +26,8 @@ #define MII_DP83867_MICR 0x12 #define MII_DP83867_ISR 0x13 #define DP83867_CFG2 0x14 +#define DP83867_LEDCR1 0x18 +#define DP83867_LEDCR2 0x19 #define DP83867_CFG3 0x1e #define DP83867_CTRL 0x1f @@ -150,6 +152,12 @@ /* FLD_THR_CFG */ #define DP83867_FLD_THR_CFG_ENERGY_LOST_THR_MASK 0x7 +#define DP83867_LED_COUNT 4 + +/* LED_DRV bits */ +#define DP83867_LED_DRV_EN(x) BIT((x) * 4) +#define DP83867_LED_DRV_VAL(x) BIT((x) * 4 + 1) + enum { DP83867_PORT_MIRROING_KEEP, DP83867_PORT_MIRROING_EN, @@ -468,8 +476,7 @@ static int dp83867_set_tunable(struct phy_device *phydev, static int dp83867_config_port_mirroring(struct phy_device *phydev) { - struct dp83867_private *dp83867 = - (struct dp83867_private *)phydev->priv; + struct dp83867_private *dp83867 = phydev->priv; if (dp83867->port_mirroring == DP83867_PORT_MIRROING_EN) phy_set_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4, @@ -693,6 +700,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; @@ -946,6 +977,27 @@ static int dp83867_loopback(struct phy_device *phydev, bool enable) enable ? BMCR_LOOPBACK : 0); } +static int +dp83867_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness brightness) +{ + u32 val; + + if (index >= DP83867_LED_COUNT) + return -EINVAL; + + /* DRV_EN==1: output is DRV_VAL */ + val = DP83867_LED_DRV_EN(index); + + if (brightness) + val |= DP83867_LED_DRV_VAL(index); + + return phy_modify(phydev, DP83867_LEDCR2, + DP83867_LED_DRV_VAL(index) | + DP83867_LED_DRV_EN(index), + val); +} + static struct phy_driver dp83867_driver[] = { { .phy_id = DP83867_PHY_ID, @@ -968,11 +1020,13 @@ 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, + + .led_brightness_set = dp83867_led_brightness_set, }, }; module_phy_driver(dp83867_driver); diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index b4ff9c5073a3..9ab5eff502b7 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -588,15 +588,13 @@ static int dp83869_of_init(struct phy_device *phydev) &dp83869_internal_delay[0], delay_size, true); if (dp83869->rx_int_delay < 0) - dp83869->rx_int_delay = - dp83869_internal_delay[DP83869_CLK_DELAY_DEF]; + dp83869->rx_int_delay = DP83869_CLK_DELAY_DEF; dp83869->tx_int_delay = phy_get_internal_delay(phydev, dev, &dp83869_internal_delay[0], delay_size, false); if (dp83869->tx_int_delay < 0) - dp83869->tx_int_delay = - dp83869_internal_delay[DP83869_CLK_DELAY_DEF]; + dp83869->tx_int_delay = DP83869_CLK_DELAY_DEF; return ret; } diff --git a/drivers/net/phy/marvell-88x2222.c b/drivers/net/phy/marvell-88x2222.c index fd9ad4820192..f83cae64585d 100644 --- a/drivers/net/phy/marvell-88x2222.c +++ b/drivers/net/phy/marvell-88x2222.c @@ -487,7 +487,7 @@ static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_supported) = { 0, }; - priv = (struct mv2222_data *)phydev->priv; + priv = phydev->priv; dev = &phydev->mdio.dev; sfp_parse_support(phydev->sfp_bus, id, sfp_supported, interfaces); @@ -524,7 +524,7 @@ static void mv2222_sfp_remove(void *upstream) struct phy_device *phydev = upstream; struct mv2222_data *priv; - priv = (struct mv2222_data *)phydev->priv; + priv = phydev->priv; priv->line_interface = PHY_INTERFACE_MODE_NA; linkmode_zero(priv->supported); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 63a3644d86c9..43b6cb725551 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -144,11 +144,15 @@ /* WOL Event Interrupt Enable */ #define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7) -/* LED Timer Control Register */ -#define MII_88E1318S_PHY_LED_TCR 0x12 -#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) -#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) -#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11) +#define MII_88E1318S_PHY_LED_FUNC 0x10 +#define MII_88E1318S_PHY_LED_FUNC_OFF (0x8) +#define MII_88E1318S_PHY_LED_FUNC_ON (0x9) +#define MII_88E1318S_PHY_LED_FUNC_HI_Z (0xa) +#define MII_88E1318S_PHY_LED_FUNC_BLINK (0xb) +#define MII_88E1318S_PHY_LED_TCR 0x12 +#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) +#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) +#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11) /* Magic Packet MAC address registers */ #define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17 @@ -2735,7 +2739,7 @@ static const struct hwmon_channel_info marvell_hwmon_temp = { .config = marvell_hwmon_temp_config, }; -static const struct hwmon_channel_info *marvell_hwmon_info[] = { +static const struct hwmon_channel_info * const marvell_hwmon_info[] = { &marvell_hwmon_chip, &marvell_hwmon_temp, NULL @@ -2832,6 +2836,63 @@ static int marvell_hwmon_probe(struct phy_device *phydev) } #endif +static int m88e1318_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + int reg; + + reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE, + MII_88E1318S_PHY_LED_FUNC); + if (reg < 0) + return reg; + + switch (index) { + case 0: + case 1: + case 2: + reg &= ~(0xf << (4 * index)); + if (value == LED_OFF) + reg |= MII_88E1318S_PHY_LED_FUNC_OFF << (4 * index); + else + reg |= MII_88E1318S_PHY_LED_FUNC_ON << (4 * index); + break; + default: + return -EINVAL; + } + + return phy_write_paged(phydev, MII_MARVELL_LED_PAGE, + MII_88E1318S_PHY_LED_FUNC, reg); +} + +static int m88e1318_led_blink_set(struct phy_device *phydev, u8 index, + unsigned long *delay_on, + unsigned long *delay_off) +{ + int reg; + + reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE, + MII_88E1318S_PHY_LED_FUNC); + if (reg < 0) + return reg; + + switch (index) { + case 0: + case 1: + case 2: + reg &= ~(0xf << (4 * index)); + reg |= MII_88E1318S_PHY_LED_FUNC_BLINK << (4 * index); + /* Reset default is 84ms */ + *delay_on = 84 / 2; + *delay_off = 84 / 2; + break; + default: + return -EINVAL; + } + + return phy_write_paged(phydev, MII_MARVELL_LED_PAGE, + MII_88E1318S_PHY_LED_FUNC, reg); +} + static int marvell_probe(struct phy_device *phydev) { struct marvell_priv *priv; @@ -3081,6 +3142,8 @@ static struct phy_driver marvell_drivers[] = { .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, + .led_brightness_set = m88e1318_led_brightness_set, + .led_blink_set = m88e1318_led_blink_set, }, { .phy_id = MARVELL_PHY_ID_88E1145, @@ -3187,6 +3250,8 @@ static struct phy_driver marvell_drivers[] = { .cable_test_start = marvell_vct7_cable_test_start, .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start, .cable_test_get_status = marvell_vct7_cable_test_get_status, + .led_brightness_set = m88e1318_led_brightness_set, + .led_blink_set = m88e1318_led_blink_set, }, { .phy_id = MARVELL_PHY_ID_88E1540, @@ -3213,6 +3278,8 @@ static struct phy_driver marvell_drivers[] = { .cable_test_start = marvell_vct7_cable_test_start, .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start, .cable_test_get_status = marvell_vct7_cable_test_get_status, + .led_brightness_set = m88e1318_led_brightness_set, + .led_blink_set = m88e1318_led_blink_set, }, { .phy_id = MARVELL_PHY_ID_88E1545, @@ -3239,6 +3306,8 @@ static struct phy_driver marvell_drivers[] = { .cable_test_start = marvell_vct7_cable_test_start, .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start, .cable_test_get_status = marvell_vct7_cable_test_get_status, + .led_brightness_set = m88e1318_led_brightness_set, + .led_blink_set = m88e1318_led_blink_set, }, { .phy_id = MARVELL_PHY_ID_88E3016, @@ -3380,6 +3449,8 @@ static struct phy_driver marvell_drivers[] = { .get_stats = marvell_get_stats, .get_tunable = m88e1540_get_tunable, .set_tunable = m88e1540_set_tunable, + .led_brightness_set = m88e1318_led_brightness_set, + .led_blink_set = m88e1318_led_blink_set, }, }; diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index 383a9c9f36e5..55d9d7acc32e 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -243,7 +243,7 @@ static const struct hwmon_channel_info mv3310_hwmon_temp = { .config = mv3310_hwmon_temp_config, }; -static const struct hwmon_channel_info *mv3310_hwmon_info[] = { +static const struct hwmon_channel_info * const mv3310_hwmon_info[] = { &mv3310_hwmon_chip, &mv3310_hwmon_temp, NULL, diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c index a6015cd03bff..bb9b33b6bce2 100644 --- a/drivers/net/phy/meson-gxl.c +++ b/drivers/net/phy/meson-gxl.c @@ -13,6 +13,7 @@ #include <linux/phy.h> #include <linux/netdevice.h> #include <linux/bitfield.h> +#include <linux/smscphy.h> #define TSTCNTL 20 #define TSTCNTL_READ BIT(15) @@ -23,18 +24,6 @@ #define TSTCNTL_WRITE_ADDRESS GENMASK(4, 0) #define TSTREAD1 21 #define TSTWRITE 23 -#define INTSRC_FLAG 29 -#define INTSRC_ANEG_PR BIT(1) -#define INTSRC_PARALLEL_FAULT BIT(2) -#define INTSRC_ANEG_LP_ACK BIT(3) -#define INTSRC_LINK_DOWN BIT(4) -#define INTSRC_REMOTE_FAULT BIT(5) -#define INTSRC_ANEG_COMPLETE BIT(6) -#define INTSRC_ENERGY_DETECT BIT(7) -#define INTSRC_MASK 30 - -#define INT_SOURCES (INTSRC_LINK_DOWN | INTSRC_ANEG_COMPLETE | \ - INTSRC_ENERGY_DETECT) #define BANK_ANALOG_DSP 0 #define BANK_WOL 1 @@ -195,59 +184,6 @@ read_status_continue: return genphy_read_status(phydev); } -static int meson_gxl_ack_interrupt(struct phy_device *phydev) -{ - int ret = phy_read(phydev, INTSRC_FLAG); - - return ret < 0 ? ret : 0; -} - -static int meson_gxl_config_intr(struct phy_device *phydev) -{ - int ret; - - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { - /* Ack any pending IRQ */ - ret = meson_gxl_ack_interrupt(phydev); - if (ret) - return ret; - - ret = phy_write(phydev, INTSRC_MASK, INT_SOURCES); - } else { - ret = phy_write(phydev, INTSRC_MASK, 0); - - /* Ack any pending IRQ */ - ret = meson_gxl_ack_interrupt(phydev); - } - - return ret; -} - -static irqreturn_t meson_gxl_handle_interrupt(struct phy_device *phydev) -{ - int irq_status; - - irq_status = phy_read(phydev, INTSRC_FLAG); - if (irq_status < 0) { - phy_error(phydev); - return IRQ_NONE; - } - - irq_status &= INT_SOURCES; - - if (irq_status == 0) - return IRQ_NONE; - - /* Aneg-complete interrupt is used for link-up detection */ - if (phydev->autoneg == AUTONEG_ENABLE && - irq_status == INTSRC_ENERGY_DETECT) - return IRQ_HANDLED; - - phy_trigger_machine(phydev); - - return IRQ_HANDLED; -} - static struct phy_driver meson_gxl_phy[] = { { PHY_ID_MATCH_EXACT(0x01814400), @@ -257,8 +193,8 @@ static struct phy_driver meson_gxl_phy[] = { .soft_reset = genphy_soft_reset, .config_init = meson_gxl_config_init, .read_status = meson_gxl_read_status, - .config_intr = meson_gxl_config_intr, - .handle_interrupt = meson_gxl_handle_interrupt, + .config_intr = smsc_phy_config_intr, + .handle_interrupt = smsc_phy_handle_interrupt, .suspend = genphy_suspend, .resume = genphy_resume, .read_mmd = genphy_read_mmd_unsupported, @@ -268,9 +204,16 @@ static struct phy_driver meson_gxl_phy[] = { .name = "Meson G12A Internal PHY", /* PHY_BASIC_FEATURES */ .flags = PHY_IS_INTERNAL, + .probe = smsc_phy_probe, + .config_init = smsc_phy_config_init, .soft_reset = genphy_soft_reset, - .config_intr = meson_gxl_config_intr, - .handle_interrupt = meson_gxl_handle_interrupt, + .read_status = lan87xx_read_status, + .config_intr = smsc_phy_config_intr, + .handle_interrupt = smsc_phy_handle_interrupt, + + .get_tunable = smsc_phy_get_tunable, + .set_tunable = smsc_phy_set_tunable, + .suspend = genphy_suspend, .resume = genphy_resume, .read_mmd = genphy_read_mmd_unsupported, diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2c84fccef4f6..3f81bb8dac44 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -10,13 +10,13 @@ * Copyright (c) 2014 Johan Hovold <johan@kernel.org> * * Support : Micrel Phys: - * Giga phys: ksz9021, ksz9031, ksz9131 + * Giga phys: ksz9021, ksz9031, ksz9131, lan8841, lan8814 * 100/10 Phys : ksz8001, ksz8721, ksz8737, ksz8041 * ksz8021, ksz8031, ksz8051, * ksz8081, ksz8091, * ksz8061, * Switch : ksz8873, ksz886x - * ksz9477 + * ksz9477, lan8804 */ #include <linux/bitfield.h> @@ -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; @@ -3438,6 +3437,7 @@ static void lan8841_ptp_process_rx_ts(struct kszphy_ptp_priv *ptp_priv) #define LAN8841_PTP_INT_STS_PTP_TX_TS_INT BIT(12) #define LAN8841_PTP_INT_STS_PTP_RX_TS_OVRFL_INT BIT(9) #define LAN8841_PTP_INT_STS_PTP_RX_TS_INT BIT(8) +#define LAN8841_PTP_INT_STS_PTP_GPIO_CAP_INT BIT(2) static void lan8841_ptp_flush_fifo(struct kszphy_ptp_priv *ptp_priv, bool egress) { @@ -3452,6 +3452,67 @@ static void lan8841_ptp_flush_fifo(struct kszphy_ptp_priv *ptp_priv, bool egress phy_read_mmd(phydev, 2, LAN8841_PTP_INT_STS); } +#define LAN8841_PTP_GPIO_CAP_STS 506 +#define LAN8841_PTP_GPIO_SEL 327 +#define LAN8841_PTP_GPIO_SEL_GPIO_SEL(gpio) ((gpio) << 8) +#define LAN8841_PTP_GPIO_RE_LTC_SEC_HI_CAP 498 +#define LAN8841_PTP_GPIO_RE_LTC_SEC_LO_CAP 499 +#define LAN8841_PTP_GPIO_RE_LTC_NS_HI_CAP 500 +#define LAN8841_PTP_GPIO_RE_LTC_NS_LO_CAP 501 +#define LAN8841_PTP_GPIO_FE_LTC_SEC_HI_CAP 502 +#define LAN8841_PTP_GPIO_FE_LTC_SEC_LO_CAP 503 +#define LAN8841_PTP_GPIO_FE_LTC_NS_HI_CAP 504 +#define LAN8841_PTP_GPIO_FE_LTC_NS_LO_CAP 505 + +static void lan8841_gpio_process_cap(struct kszphy_ptp_priv *ptp_priv) +{ + struct phy_device *phydev = ptp_priv->phydev; + struct ptp_clock_event ptp_event = {0}; + int pin, ret, tmp; + s32 sec, nsec; + + pin = ptp_find_pin_unlocked(ptp_priv->ptp_clock, PTP_PF_EXTTS, 0); + if (pin == -1) + return; + + tmp = phy_read_mmd(phydev, 2, LAN8841_PTP_GPIO_CAP_STS); + if (tmp < 0) + return; + + ret = phy_write_mmd(phydev, 2, LAN8841_PTP_GPIO_SEL, + LAN8841_PTP_GPIO_SEL_GPIO_SEL(pin)); + if (ret) + return; + + mutex_lock(&ptp_priv->ptp_lock); + if (tmp & BIT(pin)) { + sec = phy_read_mmd(phydev, 2, LAN8841_PTP_GPIO_RE_LTC_SEC_HI_CAP); + sec <<= 16; + sec |= phy_read_mmd(phydev, 2, LAN8841_PTP_GPIO_RE_LTC_SEC_LO_CAP); + + nsec = phy_read_mmd(phydev, 2, LAN8841_PTP_GPIO_RE_LTC_NS_HI_CAP) & 0x3fff; + nsec <<= 16; + nsec |= phy_read_mmd(phydev, 2, LAN8841_PTP_GPIO_RE_LTC_NS_LO_CAP); + } else { + sec = phy_read_mmd(phydev, 2, LAN8841_PTP_GPIO_FE_LTC_SEC_HI_CAP); + sec <<= 16; + sec |= phy_read_mmd(phydev, 2, LAN8841_PTP_GPIO_FE_LTC_SEC_LO_CAP); + + nsec = phy_read_mmd(phydev, 2, LAN8841_PTP_GPIO_FE_LTC_NS_HI_CAP) & 0x3fff; + nsec <<= 16; + nsec |= phy_read_mmd(phydev, 2, LAN8841_PTP_GPIO_FE_LTC_NS_LO_CAP); + } + mutex_unlock(&ptp_priv->ptp_lock); + ret = phy_write_mmd(phydev, 2, LAN8841_PTP_GPIO_SEL, 0); + if (ret) + return; + + ptp_event.index = 0; + ptp_event.timestamp = ktime_set(sec, nsec); + ptp_event.type = PTP_CLOCK_EXTTS; + ptp_clock_event(ptp_priv->ptp_clock, &ptp_event); +} + static void lan8841_handle_ptp_interrupt(struct phy_device *phydev) { struct kszphy_priv *priv = phydev->priv; @@ -3460,12 +3521,16 @@ static void lan8841_handle_ptp_interrupt(struct phy_device *phydev) do { status = phy_read_mmd(phydev, 2, LAN8841_PTP_INT_STS); + if (status & LAN8841_PTP_INT_STS_PTP_TX_TS_INT) lan8841_ptp_process_tx_ts(ptp_priv); if (status & LAN8841_PTP_INT_STS_PTP_RX_TS_INT) lan8841_ptp_process_rx_ts(ptp_priv); + if (status & LAN8841_PTP_INT_STS_PTP_GPIO_CAP_INT) + lan8841_gpio_process_cap(ptp_priv); + if (status & LAN8841_PTP_INT_STS_PTP_TX_TS_OVRFL_INT) { lan8841_ptp_flush_fifo(ptp_priv, true); skb_queue_purge(&ptp_priv->tx_queue); @@ -3658,6 +3723,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) |