// SPDX-License-Identifier: GPL-2.0+ /* * Motorcomm 8511/8521/8531/8531S PHY driver. * * Author: Peter Geis <[email protected]> * Author: Frank <[email protected]> */ #include <linux/etherdevice.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/phy.h> #include <linux/of.h> #define PHY_ID_YT8511 … #define PHY_ID_YT8521 … #define PHY_ID_YT8531 … #define PHY_ID_YT8531S … /* YT8521/YT8531S Register Overview * UTP Register space | FIBER Register space * ------------------------------------------------------------ * | UTP MII | FIBER MII | * | UTP MMD | | * | UTP Extended | FIBER Extended | * ------------------------------------------------------------ * | Common Extended | * ------------------------------------------------------------ */ /* 0x10 ~ 0x15 , 0x1E and 0x1F are common MII registers of yt phy */ /* Specific Function Control Register */ #define YTPHY_SPECIFIC_FUNCTION_CONTROL_REG … /* 2b00 Manual MDI configuration * 2b01 Manual MDIX configuration * 2b10 Reserved * 2b11 Enable automatic crossover for all modes *default* */ #define YTPHY_SFCR_MDI_CROSSOVER_MODE_MASK … #define YTPHY_SFCR_CROSSOVER_EN … #define YTPHY_SFCR_SQE_TEST_EN … #define YTPHY_SFCR_POLARITY_REVERSAL_EN … #define YTPHY_SFCR_JABBER_DIS … /* Specific Status Register */ #define YTPHY_SPECIFIC_STATUS_REG … #define YTPHY_SSR_SPEED_MODE_OFFSET … #define YTPHY_SSR_SPEED_MODE_MASK … #define YTPHY_SSR_SPEED_10M … #define YTPHY_SSR_SPEED_100M … #define YTPHY_SSR_SPEED_1000M … #define YTPHY_SSR_DUPLEX_OFFSET … #define YTPHY_SSR_DUPLEX … #define YTPHY_SSR_PAGE_RECEIVED … #define YTPHY_SSR_SPEED_DUPLEX_RESOLVED … #define YTPHY_SSR_LINK … #define YTPHY_SSR_MDIX_CROSSOVER … #define YTPHY_SSR_DOWNGRADE … #define YTPHY_SSR_TRANSMIT_PAUSE … #define YTPHY_SSR_RECEIVE_PAUSE … #define YTPHY_SSR_POLARITY … #define YTPHY_SSR_JABBER … /* Interrupt enable Register */ #define YTPHY_INTERRUPT_ENABLE_REG … #define YTPHY_IER_WOL … /* Interrupt Status Register */ #define YTPHY_INTERRUPT_STATUS_REG … #define YTPHY_ISR_AUTONEG_ERR … #define YTPHY_ISR_SPEED_CHANGED … #define YTPHY_ISR_DUPLEX_CHANGED … #define YTPHY_ISR_PAGE_RECEIVED … #define YTPHY_ISR_LINK_FAILED … #define YTPHY_ISR_LINK_SUCCESSED … #define YTPHY_ISR_WOL … #define YTPHY_ISR_WIRESPEED_DOWNGRADE … #define YTPHY_ISR_SERDES_LINK_FAILED … #define YTPHY_ISR_SERDES_LINK_SUCCESSED … #define YTPHY_ISR_POLARITY_CHANGED … #define YTPHY_ISR_JABBER_HAPPENED … /* Speed Auto Downgrade Control Register */ #define YTPHY_SPEED_AUTO_DOWNGRADE_CONTROL_REG … #define YTPHY_SADCR_SPEED_DOWNGRADE_EN … /* If these bits are set to 3, the PHY attempts five times ( 3(set value) + * additional 2) before downgrading, default 0x3 */ #define YTPHY_SADCR_SPEED_RETRY_LIMIT … /* Rx Error Counter Register */ #define YTPHY_RX_ERROR_COUNTER_REG … /* Extended Register's Address Offset Register */ #define YTPHY_PAGE_SELECT … /* Extended Register's Data Register */ #define YTPHY_PAGE_DATA … /* FIBER Auto-Negotiation link partner ability */ #define YTPHY_FLPA_PAUSE … #define YTPHY_FLPA_ASYM_PAUSE … #define YT8511_PAGE_SELECT … #define YT8511_PAGE … #define YT8511_EXT_CLK_GATE … #define YT8511_EXT_DELAY_DRIVE … #define YT8511_EXT_SLEEP_CTRL … /* 2b00 25m from pll * 2b01 25m from xtl *default* * 2b10 62.m from pll * 2b11 125m from pll */ #define YT8511_CLK_125M … #define YT8511_PLLON_SLP … /* RX Delay enabled = 1.8ns 1000T, 8ns 10/100T */ #define YT8511_DELAY_RX … /* TX Gig-E Delay is bits 7:4, default 0x5 * TX Fast-E Delay is bits 15:12, default 0xf * Delay = 150ps * N - 250ps * On = 2000ps, off = 50ps */ #define YT8511_DELAY_GE_TX_EN … #define YT8511_DELAY_GE_TX_DIS … #define YT8511_DELAY_FE_TX_EN … #define YT8511_DELAY_FE_TX_DIS … /* Extended register is different from MMD Register and MII Register. * We can use ytphy_read_ext/ytphy_write_ext/ytphy_modify_ext function to * operate extended register. * Extended Register start */ /* Phy gmii clock gating Register */ #define YT8521_CLOCK_GATING_REG … #define YT8521_CGR_RX_CLK_EN … #define YT8521_EXTREG_SLEEP_CONTROL1_REG … #define YT8521_ESC1R_SLEEP_SW … #define YT8521_ESC1R_PLLON_SLP … /* Phy fiber Link timer cfg2 Register */ #define YT8521_LINK_TIMER_CFG2_REG … #define YT8521_LTCR_EN_AUTOSEN … /* 0xA000, 0xA001, 0xA003, 0xA006 ~ 0xA00A and 0xA012 are common ext registers * of yt8521 phy. There is no need to switch reg space when operating these * registers. */ #define YT8521_REG_SPACE_SELECT_REG … #define YT8521_RSSR_SPACE_MASK … #define YT8521_RSSR_FIBER_SPACE … #define YT8521_RSSR_UTP_SPACE … #define YT8521_RSSR_TO_BE_ARBITRATED … #define YT8521_CHIP_CONFIG_REG … #define YT8521_CCR_SW_RST … #define YT8531_RGMII_LDO_VOL_MASK … #define YT8531_LDO_VOL_3V3 … #define YT8531_LDO_VOL_1V8 … /* 1b0 disable 1.9ns rxc clock delay *default* * 1b1 enable 1.9ns rxc clock delay */ #define YT8521_CCR_RXC_DLY_EN … #define YT8521_CCR_RXC_DLY_1_900_NS … #define YT8521_CCR_MODE_SEL_MASK … #define YT8521_CCR_MODE_UTP_TO_RGMII … #define YT8521_CCR_MODE_FIBER_TO_RGMII … #define YT8521_CCR_MODE_UTP_FIBER_TO_RGMII … #define YT8521_CCR_MODE_UTP_TO_SGMII … #define YT8521_CCR_MODE_SGPHY_TO_RGMAC … #define YT8521_CCR_MODE_SGMAC_TO_RGPHY … #define YT8521_CCR_MODE_UTP_TO_FIBER_AUTO … #define YT8521_CCR_MODE_UTP_TO_FIBER_FORCE … /* 3 phy polling modes,poll mode combines utp and fiber mode*/ #define YT8521_MODE_FIBER … #define YT8521_MODE_UTP … #define YT8521_MODE_POLL … #define YT8521_RGMII_CONFIG1_REG … /* 1b0 use original tx_clk_rgmii *default* * 1b1 use inverted tx_clk_rgmii. */ #define YT8521_RC1R_TX_CLK_SEL_INVERTED … #define YT8521_RC1R_RX_DELAY_MASK … #define YT8521_RC1R_FE_TX_DELAY_MASK … #define YT8521_RC1R_GE_TX_DELAY_MASK … #define YT8521_RC1R_RGMII_0_000_NS … #define YT8521_RC1R_RGMII_0_150_NS … #define YT8521_RC1R_RGMII_0_300_NS … #define YT8521_RC1R_RGMII_0_450_NS … #define YT8521_RC1R_RGMII_0_600_NS … #define YT8521_RC1R_RGMII_0_750_NS … #define YT8521_RC1R_RGMII_0_900_NS … #define YT8521_RC1R_RGMII_1_050_NS … #define YT8521_RC1R_RGMII_1_200_NS … #define YT8521_RC1R_RGMII_1_350_NS … #define YT8521_RC1R_RGMII_1_500_NS … #define YT8521_RC1R_RGMII_1_650_NS … #define YT8521_RC1R_RGMII_1_800_NS … #define YT8521_RC1R_RGMII_1_950_NS … #define YT8521_RC1R_RGMII_2_100_NS … #define YT8521_RC1R_RGMII_2_250_NS … #define YTPHY_MISC_CONFIG_REG … #define YTPHY_MCR_FIBER_SPEED_MASK … #define YTPHY_MCR_FIBER_1000BX … #define YTPHY_MCR_FIBER_100FX … /* WOL MAC ADDR: MACADDR2(highest), MACADDR1(middle), MACADDR0(lowest) */ #define YTPHY_WOL_MACADDR2_REG … #define YTPHY_WOL_MACADDR1_REG … #define YTPHY_WOL_MACADDR0_REG … #define YTPHY_WOL_CONFIG_REG … #define YTPHY_WCR_INTR_SEL … #define YTPHY_WCR_ENABLE … /* 2b00 84ms * 2b01 168ms *default* * 2b10 336ms * 2b11 672ms */ #define YTPHY_WCR_PULSE_WIDTH_MASK … #define YTPHY_WCR_PULSE_WIDTH_672MS … /* 1b0 Interrupt and WOL events is level triggered and active LOW *default* * 1b1 Interrupt and WOL events is pulse triggered and active LOW */ #define YTPHY_WCR_TYPE_PULSE … #define YTPHY_PAD_DRIVE_STRENGTH_REG … #define YT8531_RGMII_RXC_DS_MASK … #define YT8531_RGMII_RXD_DS_HI_MASK … #define YT8531_RGMII_RXD_DS_LOW_MASK … #define YT8531_RGMII_RX_DS_DEFAULT … #define YTPHY_SYNCE_CFG_REG … #define YT8521_SCR_SYNCE_ENABLE … /* 1b0 output 25m clock * 1b1 output 125m clock *default* */ #define YT8521_SCR_CLK_FRE_SEL_125M … #define YT8521_SCR_CLK_SRC_MASK … #define YT8521_SCR_CLK_SRC_PLL_125M … #define YT8521_SCR_CLK_SRC_UTP_RX … #define YT8521_SCR_CLK_SRC_SDS_RX … #define YT8521_SCR_CLK_SRC_REF_25M … #define YT8531_SCR_SYNCE_ENABLE … /* 1b0 output 25m clock *default* * 1b1 output 125m clock */ #define YT8531_SCR_CLK_FRE_SEL_125M … #define YT8531_SCR_CLK_SRC_MASK … #define YT8531_SCR_CLK_SRC_PLL_125M … #define YT8531_SCR_CLK_SRC_UTP_RX … #define YT8531_SCR_CLK_SRC_SDS_RX … #define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL … #define YT8531_SCR_CLK_SRC_REF_25M … #define YT8531_SCR_CLK_SRC_SSC_25M … /* Extended Register end */ #define YTPHY_DTS_OUTPUT_CLK_DIS … #define YTPHY_DTS_OUTPUT_CLK_25M … #define YTPHY_DTS_OUTPUT_CLK_125M … struct yt8521_priv { … }; /** * ytphy_read_ext() - read a PHY's extended register * @phydev: a pointer to a &struct phy_device * @regnum: register number to read * * NOTE:The caller must have taken the MDIO bus lock. * * returns the value of regnum reg or negative error code */ static int ytphy_read_ext(struct phy_device *phydev, u16 regnum) { … } /** * ytphy_read_ext_with_lock() - read a PHY's extended register * @phydev: a pointer to a &struct phy_device * @regnum: register number to read * * returns the value of regnum reg or negative error code */ static int ytphy_read_ext_with_lock(struct phy_device *phydev, u16 regnum) { … } /** * ytphy_write_ext() - write a PHY's extended register * @phydev: a pointer to a &struct phy_device * @regnum: register number to write * @val: value to write to @regnum * * NOTE:The caller must have taken the MDIO bus lock. * * returns 0 or negative error code */ static int ytphy_write_ext(struct phy_device *phydev, u16 regnum, u16 val) { … } /** * ytphy_write_ext_with_lock() - write a PHY's extended register * @phydev: a pointer to a &struct phy_device * @regnum: register number to write * @val: value to write to @regnum * * returns 0 or negative error code */ static int ytphy_write_ext_with_lock(struct phy_device *phydev, u16 regnum, u16 val) { … } /** * ytphy_modify_ext() - bits modify a PHY's extended register * @phydev: a pointer to a &struct phy_device * @regnum: register number to write * @mask: bit mask of bits to clear * @set: bit mask of bits to set * * NOTE: Convenience function which allows a PHY's extended register to be * modified as new register value = (old register value & ~mask) | set. * The caller must have taken the MDIO bus lock. * * returns 0 or negative error code */ static int ytphy_modify_ext(struct phy_device *phydev, u16 regnum, u16 mask, u16 set) { … } /** * ytphy_modify_ext_with_lock() - bits modify a PHY's extended register * @phydev: a pointer to a &struct phy_device * @regnum: register number to write * @mask: bit mask of bits to clear * @set: bit mask of bits to set * * NOTE: Convenience function which allows a PHY's extended register to be * modified as new register value = (old register value & ~mask) | set. * * returns 0 or negative error code */ static int ytphy_modify_ext_with_lock(struct phy_device *phydev, u16 regnum, u16 mask, u16 set) { … } /** * ytphy_get_wol() - report whether wake-on-lan is enabled * @phydev: a pointer to a &struct phy_device * @wol: a pointer to a &struct ethtool_wolinfo * * NOTE: YTPHY_WOL_CONFIG_REG is common ext reg. */ static void ytphy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { … } /** * ytphy_set_wol() - turn wake-on-lan on or off * @phydev: a pointer to a &struct phy_device * @wol: a pointer to a &struct ethtool_wolinfo * * NOTE: YTPHY_WOL_CONFIG_REG, YTPHY_WOL_MACADDR2_REG, YTPHY_WOL_MACADDR1_REG * and YTPHY_WOL_MACADDR0_REG are common ext reg. The * YTPHY_INTERRUPT_ENABLE_REG of UTP is special, fiber also use this register. * * returns 0 or negative errno code */ static int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { … } static int yt8531_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { … } static int yt8511_read_page(struct phy_device *phydev) { return __phy_read(phydev, YT8511_PAGE_SELECT); }; static int yt8511_write_page(struct phy_device *phydev, int page) { return __phy_write(phydev, YT8511_PAGE_SELECT, page); }; static int yt8511_config_init(struct phy_device *phydev) { … } /** * yt8521_read_page() - read reg page * @phydev: a pointer to a &struct phy_device * * returns current reg space of yt8521 (YT8521_RSSR_FIBER_SPACE/ * YT8521_RSSR_UTP_SPACE) or negative errno code */ static int yt8521_read_page(struct phy_device *phydev) { int old_page; old_page = ytphy_read_ext(phydev, YT8521_REG_SPACE_SELECT_REG); if (old_page < 0) return old_page; if ((old_page & YT8521_RSSR_SPACE_MASK) == YT8521_RSSR_FIBER_SPACE) return YT8521_RSSR_FIBER_SPACE; return YT8521_RSSR_UTP_SPACE; }; /** * yt8521_write_page() - write reg page * @phydev: a pointer to a &struct phy_device * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to write. * * returns 0 or negative errno code */ static int yt8521_write_page(struct phy_device *phydev, int page) { int mask = YT8521_RSSR_SPACE_MASK; int set; if ((page & YT8521_RSSR_SPACE_MASK) == YT8521_RSSR_FIBER_SPACE) set = YT8521_RSSR_FIBER_SPACE; else set = YT8521_RSSR_UTP_SPACE; return ytphy_modify_ext(phydev, YT8521_REG_SPACE_SELECT_REG, mask, set); }; /** * struct ytphy_cfg_reg_map - map a config value to a register value * @cfg: value in device configuration * @reg: value in the register */ struct ytphy_cfg_reg_map { … }; static const struct ytphy_cfg_reg_map ytphy_rgmii_delays[] = …; static u32 ytphy_get_delay_reg_value(struct phy_device *phydev, const char *prop_name, const struct ytphy_cfg_reg_map *tbl, int tb_size, u16 *rxc_dly_en, u32 dflt) { … } static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev) { … } static int ytphy_rgmii_clk_delay_config_with_lock(struct phy_device *phydev) { … } /** * struct ytphy_ldo_vol_map - map a current value to a register value * @vol: ldo voltage * @ds: value in the register * @cur: value in device configuration */ struct ytphy_ldo_vol_map { … }; static const struct ytphy_ldo_vol_map yt8531_ldo_vol[] = …; static u32 yt8531_get_ldo_vol(struct phy_device *phydev) { … } static int yt8531_get_ds_map(struct phy_device *phydev, u32 cur) { … } static int yt8531_set_ds(struct phy_device *phydev) { … } /** * yt8521_probe() - read chip config then set suitable polling_mode * @phydev: a pointer to a &struct phy_device * * returns 0 or negative errno code */ static int yt8521_probe(struct phy_device *phydev) { … } static int yt8531_probe(struct phy_device *phydev) { … } /** * ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp * @phydev: a pointer to a &struct phy_device * * NOTE:The caller must have taken the MDIO bus lock. * * returns 0 or negative errno code */ static int ytphy_utp_read_lpa(struct phy_device *phydev) { … } /** * yt8521_adjust_status() - update speed and duplex to phydev. when in fiber * mode, adjust speed and duplex. * @phydev: a pointer to a &struct phy_device * @status: yt8521 status read from YTPHY_SPECIFIC_STATUS_REG * @is_utp: false(yt8521 work in fiber mode) or true(yt8521 work in utp mode) * * NOTE:The caller must have taken the MDIO bus lock. * * returns 0 */ static int yt8521_adjust_status(struct phy_device *phydev, int status, bool is_utp) { … } /** * yt8521_read_status_paged() - determines the speed and duplex of one page * @phydev: a pointer to a &struct phy_device * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to * operate. * * returns 1 (utp or fiber link),0 (no link) or negative errno code */ static int yt8521_read_status_paged(struct phy_device *phydev, int page) { … } /** * yt8521_read_status() - determines the negotiated speed and duplex * @phydev: a pointer to a &struct phy_device * * returns 0 or negative errno code */ static int yt8521_read_status(struct phy_device *phydev) { … } /** * yt8521_modify_bmcr_paged - bits modify a PHY's BMCR register of one page * @phydev: the phy_device struct * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to operate * @mask: bit mask of bits to clear * @set: bit mask of bits to set * * NOTE: Convenience function which allows a PHY's BMCR register to be * modified as new register value = (old register value & ~mask) | set. * YT8521 has two space (utp/fiber) and three mode (utp/fiber/poll), each space * has MII_BMCR. poll mode combines utp and faber,so need do both. * If it is reset, it will wait for completion. * * returns 0 or negative errno code */ static int yt8521_modify_bmcr_paged(struct phy_device *phydev, int page, u16 mask, u16 set) { … } /** * yt8521_modify_utp_fiber_bmcr - bits modify a PHY's BMCR register * @phydev: the phy_device struct * @mask: bit mask of bits to clear * @set: bit mask of bits to set * * NOTE: Convenience function which allows a PHY's BMCR register to be * modified as new register value = (old register value & ~mask) | set. * YT8521 has two space (utp/fiber) and three mode (utp/fiber/poll), each space * has MII_BMCR. poll mode combines utp and faber,so need do both. * * returns 0 or negative errno code */ static int yt8521_modify_utp_fiber_bmcr(struct phy_device *phydev, u16 mask, u16 set) { … } /** * yt8521_soft_reset() - called to issue a PHY software reset * @phydev: a pointer to a &struct phy_device * * returns 0 or negative errno code */ static int yt8521_soft_reset(struct phy_device *phydev) { … } /** * yt8521_suspend() - suspend the hardware * @phydev: a pointer to a &struct phy_device * * returns 0 or negative errno code */ static int yt8521_suspend(struct phy_device *phydev) { … } /** * yt8521_resume() - resume the hardware * @phydev: a pointer to a &struct phy_device * * returns 0 or negative errno code */ static int yt8521_resume(struct phy_device *phydev) { … } /** * yt8521_config_init() - called to initialize the PHY * @phydev: a pointer to a &struct phy_device * * returns 0 or negative errno code */ static int yt8521_config_init(struct phy_device *phydev) { … } static int yt8531_config_init(struct phy_device *phydev) { … } /** * yt8531_link_change_notify() - Adjust the tx clock direction according to * the current speed and dts config. * @phydev: a pointer to a &struct phy_device * * NOTE: This function is only used to adapt to VF2 with JH7110 SoC. Please * keep "motorcomm,tx-clk-adj-enabled" not exist in dts when the soc is not * JH7110. */ static void yt8531_link_change_notify(struct phy_device *phydev) { … } /** * yt8521_prepare_fiber_features() - A small helper function that setup * fiber's features. * @phydev: a pointer to a &struct phy_device * @dst: a pointer to store fiber's features */ static void yt8521_prepare_fiber_features(struct phy_device *phydev, unsigned long *dst) { … } /** * yt8521_fiber_setup_forced - configures/forces speed from @phydev * @phydev: target phy_device struct * * NOTE:The caller must have taken the MDIO bus lock. * * returns 0 or negative errno code */ static int yt8521_fiber_setup_forced(struct phy_device *phydev) { … } /** * ytphy_check_and_restart_aneg - Enable and restart auto-negotiation * @phydev: target phy_device struct * @restart: whether aneg restart is requested * * NOTE:The caller must have taken the MDIO bus lock. * * returns 0 or negative errno code */ static int ytphy_check_and_restart_aneg(struct phy_device *phydev, bool restart) { … } /** * yt8521_fiber_config_aneg - restart auto-negotiation or write * YTPHY_MISC_CONFIG_REG. * @phydev: target phy_device struct * * NOTE:The caller must have taken the MDIO bus lock. * * returns 0 or negative errno code */ static int yt8521_fiber_config_aneg(struct phy_device *phydev) { … } /** * ytphy_setup_master_slave * @phydev: target phy_device struct * * NOTE: The caller must have taken the MDIO bus lock. * * returns 0 or negative errno code */ static int ytphy_setup_master_slave(struct phy_device *phydev) { … } /** * ytphy_utp_config_advert - sanitize and advertise auto-negotiation parameters * @phydev: target phy_device struct * * NOTE: Writes MII_ADVERTISE with the appropriate values, * after sanitizing the values to make sure we only advertise * what is supported. Returns < 0 on error, 0 if the PHY's advertisement * hasn't changed, and > 0 if it has changed. * The caller must have taken the MDIO bus lock. * * returns 0 or negative errno code */ static int ytphy_utp_config_advert(struct phy_device *phydev) { … } /** * ytphy_utp_config_aneg - restart auto-negotiation or write BMCR * @phydev: target phy_device struct * @changed: whether autoneg is requested * * NOTE: If auto-negotiation is enabled, we configure the * advertising, and then restart auto-negotiation. If it is not * enabled, then we write the BMCR. * The caller must have taken the MDIO bus lock. * * returns 0 or negative errno code */ static int ytphy_utp_config_aneg(struct phy_device *phydev, bool changed) { … } /** * yt8521_config_aneg_paged() - switch reg space then call genphy_config_aneg * of one page * @phydev: a pointer to a &struct phy_device * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to * operate. * * returns 0 or negative errno code */ static int yt8521_config_aneg_paged(struct phy_device *phydev, int page) { … } /** * yt8521_config_aneg() - change reg space then call yt8521_config_aneg_paged * @phydev: a pointer to a &struct phy_device * * returns 0 or negative errno code */ static int yt8521_config_aneg(struct phy_device *phydev) { … } /** * yt8521_aneg_done_paged() - determines the auto negotiation result of one * page. * @phydev: a pointer to a &struct phy_device * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to * operate. * * returns 0(no link)or 1(fiber or utp link) or negative errno code */ static int yt8521_aneg_done_paged(struct phy_device *phydev, int page) { … } /** * yt8521_aneg_done() - determines the auto negotiation result * @phydev: a pointer to a &struct phy_device * * returns 0(no link)or 1(fiber or utp link) or negative errno code */ static int yt8521_aneg_done(struct phy_device *phydev) { … } /** * ytphy_utp_read_abilities - read PHY abilities from Clause 22 registers * @phydev: target phy_device struct * * NOTE: Reads the PHY's abilities and populates * phydev->supported accordingly. * The caller must have taken the MDIO bus lock. * * returns 0 or negative errno code */ static int ytphy_utp_read_abilities(struct phy_device *phydev) { … } /** * yt8521_get_features_paged() - read supported link modes for one page * @phydev: a pointer to a &struct phy_device * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to * operate. * * returns 0 or negative errno code */ static int yt8521_get_features_paged(struct phy_device *phydev, int page) { … } /** * yt8521_get_features - switch reg space then call yt8521_get_features_paged * @phydev: target phy_device struct * * returns 0 or negative errno code */ static int yt8521_get_features(struct phy_device *phydev) { … } static struct phy_driver motorcomm_phy_drvs[] = …; module_phy_driver(motorcomm_phy_drvs); MODULE_DESCRIPTION(…) …; MODULE_AUTHOR(…) …; MODULE_AUTHOR(…) …; MODULE_LICENSE(…) …; static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = …; MODULE_DEVICE_TABLE(mdio, motorcomm_tbl);