162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Motorcomm 8511/8521/8531/8531S PHY driver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Peter Geis <pgwipeout@gmail.com>
662306a36Sopenharmony_ci * Author: Frank <Frank.Sae@motor-comm.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/etherdevice.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/phy.h>
1362306a36Sopenharmony_ci#include <linux/of.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define PHY_ID_YT8511		0x0000010a
1662306a36Sopenharmony_ci#define PHY_ID_YT8521		0x0000011a
1762306a36Sopenharmony_ci#define PHY_ID_YT8531		0x4f51e91b
1862306a36Sopenharmony_ci#define PHY_ID_YT8531S		0x4f51e91a
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* YT8521/YT8531S Register Overview
2162306a36Sopenharmony_ci *	UTP Register space	|	FIBER Register space
2262306a36Sopenharmony_ci *  ------------------------------------------------------------
2362306a36Sopenharmony_ci * |	UTP MII			|	FIBER MII		|
2462306a36Sopenharmony_ci * |	UTP MMD			|				|
2562306a36Sopenharmony_ci * |	UTP Extended		|	FIBER Extended		|
2662306a36Sopenharmony_ci *  ------------------------------------------------------------
2762306a36Sopenharmony_ci * |			Common Extended				|
2862306a36Sopenharmony_ci *  ------------------------------------------------------------
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/* 0x10 ~ 0x15 , 0x1E and 0x1F are common MII registers of yt phy */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Specific Function Control Register */
3462306a36Sopenharmony_ci#define YTPHY_SPECIFIC_FUNCTION_CONTROL_REG	0x10
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* 2b00 Manual MDI configuration
3762306a36Sopenharmony_ci * 2b01 Manual MDIX configuration
3862306a36Sopenharmony_ci * 2b10 Reserved
3962306a36Sopenharmony_ci * 2b11 Enable automatic crossover for all modes  *default*
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ci#define YTPHY_SFCR_MDI_CROSSOVER_MODE_MASK	(BIT(6) | BIT(5))
4262306a36Sopenharmony_ci#define YTPHY_SFCR_CROSSOVER_EN			BIT(3)
4362306a36Sopenharmony_ci#define YTPHY_SFCR_SQE_TEST_EN			BIT(2)
4462306a36Sopenharmony_ci#define YTPHY_SFCR_POLARITY_REVERSAL_EN		BIT(1)
4562306a36Sopenharmony_ci#define YTPHY_SFCR_JABBER_DIS			BIT(0)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* Specific Status Register */
4862306a36Sopenharmony_ci#define YTPHY_SPECIFIC_STATUS_REG		0x11
4962306a36Sopenharmony_ci#define YTPHY_SSR_SPEED_MODE_OFFSET		14
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define YTPHY_SSR_SPEED_MODE_MASK		(BIT(15) | BIT(14))
5262306a36Sopenharmony_ci#define YTPHY_SSR_SPEED_10M			0x0
5362306a36Sopenharmony_ci#define YTPHY_SSR_SPEED_100M			0x1
5462306a36Sopenharmony_ci#define YTPHY_SSR_SPEED_1000M			0x2
5562306a36Sopenharmony_ci#define YTPHY_SSR_DUPLEX_OFFSET			13
5662306a36Sopenharmony_ci#define YTPHY_SSR_DUPLEX			BIT(13)
5762306a36Sopenharmony_ci#define YTPHY_SSR_PAGE_RECEIVED			BIT(12)
5862306a36Sopenharmony_ci#define YTPHY_SSR_SPEED_DUPLEX_RESOLVED		BIT(11)
5962306a36Sopenharmony_ci#define YTPHY_SSR_LINK				BIT(10)
6062306a36Sopenharmony_ci#define YTPHY_SSR_MDIX_CROSSOVER		BIT(6)
6162306a36Sopenharmony_ci#define YTPHY_SSR_DOWNGRADE			BIT(5)
6262306a36Sopenharmony_ci#define YTPHY_SSR_TRANSMIT_PAUSE		BIT(3)
6362306a36Sopenharmony_ci#define YTPHY_SSR_RECEIVE_PAUSE			BIT(2)
6462306a36Sopenharmony_ci#define YTPHY_SSR_POLARITY			BIT(1)
6562306a36Sopenharmony_ci#define YTPHY_SSR_JABBER			BIT(0)
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* Interrupt enable Register */
6862306a36Sopenharmony_ci#define YTPHY_INTERRUPT_ENABLE_REG		0x12
6962306a36Sopenharmony_ci#define YTPHY_IER_WOL				BIT(6)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* Interrupt Status Register */
7262306a36Sopenharmony_ci#define YTPHY_INTERRUPT_STATUS_REG		0x13
7362306a36Sopenharmony_ci#define YTPHY_ISR_AUTONEG_ERR			BIT(15)
7462306a36Sopenharmony_ci#define YTPHY_ISR_SPEED_CHANGED			BIT(14)
7562306a36Sopenharmony_ci#define YTPHY_ISR_DUPLEX_CHANGED		BIT(13)
7662306a36Sopenharmony_ci#define YTPHY_ISR_PAGE_RECEIVED			BIT(12)
7762306a36Sopenharmony_ci#define YTPHY_ISR_LINK_FAILED			BIT(11)
7862306a36Sopenharmony_ci#define YTPHY_ISR_LINK_SUCCESSED		BIT(10)
7962306a36Sopenharmony_ci#define YTPHY_ISR_WOL				BIT(6)
8062306a36Sopenharmony_ci#define YTPHY_ISR_WIRESPEED_DOWNGRADE		BIT(5)
8162306a36Sopenharmony_ci#define YTPHY_ISR_SERDES_LINK_FAILED		BIT(3)
8262306a36Sopenharmony_ci#define YTPHY_ISR_SERDES_LINK_SUCCESSED		BIT(2)
8362306a36Sopenharmony_ci#define YTPHY_ISR_POLARITY_CHANGED		BIT(1)
8462306a36Sopenharmony_ci#define YTPHY_ISR_JABBER_HAPPENED		BIT(0)
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/* Speed Auto Downgrade Control Register */
8762306a36Sopenharmony_ci#define YTPHY_SPEED_AUTO_DOWNGRADE_CONTROL_REG	0x14
8862306a36Sopenharmony_ci#define YTPHY_SADCR_SPEED_DOWNGRADE_EN		BIT(5)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* If these bits are set to 3, the PHY attempts five times ( 3(set value) +
9162306a36Sopenharmony_ci * additional 2) before downgrading, default 0x3
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_ci#define YTPHY_SADCR_SPEED_RETRY_LIMIT		(0x3 << 2)
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* Rx Error Counter Register */
9662306a36Sopenharmony_ci#define YTPHY_RX_ERROR_COUNTER_REG		0x15
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/* Extended Register's Address Offset Register */
9962306a36Sopenharmony_ci#define YTPHY_PAGE_SELECT			0x1E
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* Extended Register's Data Register */
10262306a36Sopenharmony_ci#define YTPHY_PAGE_DATA				0x1F
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/* FIBER Auto-Negotiation link partner ability */
10562306a36Sopenharmony_ci#define YTPHY_FLPA_PAUSE			(0x3 << 7)
10662306a36Sopenharmony_ci#define YTPHY_FLPA_ASYM_PAUSE			(0x2 << 7)
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define YT8511_PAGE_SELECT	0x1e
10962306a36Sopenharmony_ci#define YT8511_PAGE		0x1f
11062306a36Sopenharmony_ci#define YT8511_EXT_CLK_GATE	0x0c
11162306a36Sopenharmony_ci#define YT8511_EXT_DELAY_DRIVE	0x0d
11262306a36Sopenharmony_ci#define YT8511_EXT_SLEEP_CTRL	0x27
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/* 2b00 25m from pll
11562306a36Sopenharmony_ci * 2b01 25m from xtl *default*
11662306a36Sopenharmony_ci * 2b10 62.m from pll
11762306a36Sopenharmony_ci * 2b11 125m from pll
11862306a36Sopenharmony_ci */
11962306a36Sopenharmony_ci#define YT8511_CLK_125M		(BIT(2) | BIT(1))
12062306a36Sopenharmony_ci#define YT8511_PLLON_SLP	BIT(14)
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* RX Delay enabled = 1.8ns 1000T, 8ns 10/100T */
12362306a36Sopenharmony_ci#define YT8511_DELAY_RX		BIT(0)
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/* TX Gig-E Delay is bits 7:4, default 0x5
12662306a36Sopenharmony_ci * TX Fast-E Delay is bits 15:12, default 0xf
12762306a36Sopenharmony_ci * Delay = 150ps * N - 250ps
12862306a36Sopenharmony_ci * On = 2000ps, off = 50ps
12962306a36Sopenharmony_ci */
13062306a36Sopenharmony_ci#define YT8511_DELAY_GE_TX_EN	(0xf << 4)
13162306a36Sopenharmony_ci#define YT8511_DELAY_GE_TX_DIS	(0x2 << 4)
13262306a36Sopenharmony_ci#define YT8511_DELAY_FE_TX_EN	(0xf << 12)
13362306a36Sopenharmony_ci#define YT8511_DELAY_FE_TX_DIS	(0x2 << 12)
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/* Extended register is different from MMD Register and MII Register.
13662306a36Sopenharmony_ci * We can use ytphy_read_ext/ytphy_write_ext/ytphy_modify_ext function to
13762306a36Sopenharmony_ci * operate extended register.
13862306a36Sopenharmony_ci * Extended Register  start
13962306a36Sopenharmony_ci */
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/* Phy gmii clock gating Register */
14262306a36Sopenharmony_ci#define YT8521_CLOCK_GATING_REG			0xC
14362306a36Sopenharmony_ci#define YT8521_CGR_RX_CLK_EN			BIT(12)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define YT8521_EXTREG_SLEEP_CONTROL1_REG	0x27
14662306a36Sopenharmony_ci#define YT8521_ESC1R_SLEEP_SW			BIT(15)
14762306a36Sopenharmony_ci#define YT8521_ESC1R_PLLON_SLP			BIT(14)
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/* Phy fiber Link timer cfg2 Register */
15062306a36Sopenharmony_ci#define YT8521_LINK_TIMER_CFG2_REG		0xA5
15162306a36Sopenharmony_ci#define YT8521_LTCR_EN_AUTOSEN			BIT(15)
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/* 0xA000, 0xA001, 0xA003, 0xA006 ~ 0xA00A and 0xA012 are common ext registers
15462306a36Sopenharmony_ci * of yt8521 phy. There is no need to switch reg space when operating these
15562306a36Sopenharmony_ci * registers.
15662306a36Sopenharmony_ci */
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci#define YT8521_REG_SPACE_SELECT_REG		0xA000
15962306a36Sopenharmony_ci#define YT8521_RSSR_SPACE_MASK			BIT(1)
16062306a36Sopenharmony_ci#define YT8521_RSSR_FIBER_SPACE			(0x1 << 1)
16162306a36Sopenharmony_ci#define YT8521_RSSR_UTP_SPACE			(0x0 << 1)
16262306a36Sopenharmony_ci#define YT8521_RSSR_TO_BE_ARBITRATED		(0xFF)
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#define YT8521_CHIP_CONFIG_REG			0xA001
16562306a36Sopenharmony_ci#define YT8521_CCR_SW_RST			BIT(15)
16662306a36Sopenharmony_ci#define YT8531_RGMII_LDO_VOL_MASK		GENMASK(5, 4)
16762306a36Sopenharmony_ci#define YT8531_LDO_VOL_3V3			0x0
16862306a36Sopenharmony_ci#define YT8531_LDO_VOL_1V8			0x2
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/* 1b0 disable 1.9ns rxc clock delay  *default*
17162306a36Sopenharmony_ci * 1b1 enable 1.9ns rxc clock delay
17262306a36Sopenharmony_ci */
17362306a36Sopenharmony_ci#define YT8521_CCR_RXC_DLY_EN			BIT(8)
17462306a36Sopenharmony_ci#define YT8521_CCR_RXC_DLY_1_900_NS		1900
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci#define YT8521_CCR_MODE_SEL_MASK		(BIT(2) | BIT(1) | BIT(0))
17762306a36Sopenharmony_ci#define YT8521_CCR_MODE_UTP_TO_RGMII		0
17862306a36Sopenharmony_ci#define YT8521_CCR_MODE_FIBER_TO_RGMII		1
17962306a36Sopenharmony_ci#define YT8521_CCR_MODE_UTP_FIBER_TO_RGMII	2
18062306a36Sopenharmony_ci#define YT8521_CCR_MODE_UTP_TO_SGMII		3
18162306a36Sopenharmony_ci#define YT8521_CCR_MODE_SGPHY_TO_RGMAC		4
18262306a36Sopenharmony_ci#define YT8521_CCR_MODE_SGMAC_TO_RGPHY		5
18362306a36Sopenharmony_ci#define YT8521_CCR_MODE_UTP_TO_FIBER_AUTO	6
18462306a36Sopenharmony_ci#define YT8521_CCR_MODE_UTP_TO_FIBER_FORCE	7
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci/* 3 phy polling modes,poll mode combines utp and fiber mode*/
18762306a36Sopenharmony_ci#define YT8521_MODE_FIBER			0x1
18862306a36Sopenharmony_ci#define YT8521_MODE_UTP				0x2
18962306a36Sopenharmony_ci#define YT8521_MODE_POLL			0x3
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci#define YT8521_RGMII_CONFIG1_REG		0xA003
19262306a36Sopenharmony_ci/* 1b0 use original tx_clk_rgmii  *default*
19362306a36Sopenharmony_ci * 1b1 use inverted tx_clk_rgmii.
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_ci#define YT8521_RC1R_TX_CLK_SEL_INVERTED		BIT(14)
19662306a36Sopenharmony_ci#define YT8521_RC1R_RX_DELAY_MASK		GENMASK(13, 10)
19762306a36Sopenharmony_ci#define YT8521_RC1R_FE_TX_DELAY_MASK		GENMASK(7, 4)
19862306a36Sopenharmony_ci#define YT8521_RC1R_GE_TX_DELAY_MASK		GENMASK(3, 0)
19962306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_0_000_NS		0
20062306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_0_150_NS		1
20162306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_0_300_NS		2
20262306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_0_450_NS		3
20362306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_0_600_NS		4
20462306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_0_750_NS		5
20562306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_0_900_NS		6
20662306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_1_050_NS		7
20762306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_1_200_NS		8
20862306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_1_350_NS		9
20962306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_1_500_NS		10
21062306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_1_650_NS		11
21162306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_1_800_NS		12
21262306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_1_950_NS		13
21362306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_2_100_NS		14
21462306a36Sopenharmony_ci#define YT8521_RC1R_RGMII_2_250_NS		15
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci#define YTPHY_MISC_CONFIG_REG			0xA006
21762306a36Sopenharmony_ci#define YTPHY_MCR_FIBER_SPEED_MASK		BIT(0)
21862306a36Sopenharmony_ci#define YTPHY_MCR_FIBER_1000BX			(0x1 << 0)
21962306a36Sopenharmony_ci#define YTPHY_MCR_FIBER_100FX			(0x0 << 0)
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/* WOL MAC ADDR: MACADDR2(highest), MACADDR1(middle), MACADDR0(lowest) */
22262306a36Sopenharmony_ci#define YTPHY_WOL_MACADDR2_REG			0xA007
22362306a36Sopenharmony_ci#define YTPHY_WOL_MACADDR1_REG			0xA008
22462306a36Sopenharmony_ci#define YTPHY_WOL_MACADDR0_REG			0xA009
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci#define YTPHY_WOL_CONFIG_REG			0xA00A
22762306a36Sopenharmony_ci#define YTPHY_WCR_INTR_SEL			BIT(6)
22862306a36Sopenharmony_ci#define YTPHY_WCR_ENABLE			BIT(3)
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci/* 2b00 84ms
23162306a36Sopenharmony_ci * 2b01 168ms  *default*
23262306a36Sopenharmony_ci * 2b10 336ms
23362306a36Sopenharmony_ci * 2b11 672ms
23462306a36Sopenharmony_ci */
23562306a36Sopenharmony_ci#define YTPHY_WCR_PULSE_WIDTH_MASK		(BIT(2) | BIT(1))
23662306a36Sopenharmony_ci#define YTPHY_WCR_PULSE_WIDTH_672MS		(BIT(2) | BIT(1))
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci/* 1b0 Interrupt and WOL events is level triggered and active LOW  *default*
23962306a36Sopenharmony_ci * 1b1 Interrupt and WOL events is pulse triggered and active LOW
24062306a36Sopenharmony_ci */
24162306a36Sopenharmony_ci#define YTPHY_WCR_TYPE_PULSE			BIT(0)
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci#define YTPHY_PAD_DRIVE_STRENGTH_REG		0xA010
24462306a36Sopenharmony_ci#define YT8531_RGMII_RXC_DS_MASK		GENMASK(15, 13)
24562306a36Sopenharmony_ci#define YT8531_RGMII_RXD_DS_HI_MASK		BIT(12)		/* Bit 2 of rxd_ds */
24662306a36Sopenharmony_ci#define YT8531_RGMII_RXD_DS_LOW_MASK		GENMASK(5, 4)	/* Bit 1/0 of rxd_ds */
24762306a36Sopenharmony_ci#define YT8531_RGMII_RX_DS_DEFAULT		0x3
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci#define YTPHY_SYNCE_CFG_REG			0xA012
25062306a36Sopenharmony_ci#define YT8521_SCR_SYNCE_ENABLE			BIT(5)
25162306a36Sopenharmony_ci/* 1b0 output 25m clock
25262306a36Sopenharmony_ci * 1b1 output 125m clock  *default*
25362306a36Sopenharmony_ci */
25462306a36Sopenharmony_ci#define YT8521_SCR_CLK_FRE_SEL_125M		BIT(3)
25562306a36Sopenharmony_ci#define YT8521_SCR_CLK_SRC_MASK			GENMASK(2, 1)
25662306a36Sopenharmony_ci#define YT8521_SCR_CLK_SRC_PLL_125M		0
25762306a36Sopenharmony_ci#define YT8521_SCR_CLK_SRC_UTP_RX		1
25862306a36Sopenharmony_ci#define YT8521_SCR_CLK_SRC_SDS_RX		2
25962306a36Sopenharmony_ci#define YT8521_SCR_CLK_SRC_REF_25M		3
26062306a36Sopenharmony_ci#define YT8531_SCR_SYNCE_ENABLE			BIT(6)
26162306a36Sopenharmony_ci/* 1b0 output 25m clock   *default*
26262306a36Sopenharmony_ci * 1b1 output 125m clock
26362306a36Sopenharmony_ci */
26462306a36Sopenharmony_ci#define YT8531_SCR_CLK_FRE_SEL_125M		BIT(4)
26562306a36Sopenharmony_ci#define YT8531_SCR_CLK_SRC_MASK			GENMASK(3, 1)
26662306a36Sopenharmony_ci#define YT8531_SCR_CLK_SRC_PLL_125M		0
26762306a36Sopenharmony_ci#define YT8531_SCR_CLK_SRC_UTP_RX		1
26862306a36Sopenharmony_ci#define YT8531_SCR_CLK_SRC_SDS_RX		2
26962306a36Sopenharmony_ci#define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL	3
27062306a36Sopenharmony_ci#define YT8531_SCR_CLK_SRC_REF_25M		4
27162306a36Sopenharmony_ci#define YT8531_SCR_CLK_SRC_SSC_25M		5
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci/* Extended Register  end */
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci#define YTPHY_DTS_OUTPUT_CLK_DIS		0
27662306a36Sopenharmony_ci#define YTPHY_DTS_OUTPUT_CLK_25M		25000000
27762306a36Sopenharmony_ci#define YTPHY_DTS_OUTPUT_CLK_125M		125000000
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistruct yt8521_priv {
28062306a36Sopenharmony_ci	/* combo_advertising is used for case of YT8521 in combo mode,
28162306a36Sopenharmony_ci	 * this means that yt8521 may work in utp or fiber mode which depends
28262306a36Sopenharmony_ci	 * on which media is connected (YT8521_RSSR_TO_BE_ARBITRATED).
28362306a36Sopenharmony_ci	 */
28462306a36Sopenharmony_ci	__ETHTOOL_DECLARE_LINK_MODE_MASK(combo_advertising);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* YT8521_MODE_FIBER / YT8521_MODE_UTP / YT8521_MODE_POLL*/
28762306a36Sopenharmony_ci	u8 polling_mode;
28862306a36Sopenharmony_ci	u8 strap_mode; /* 8 working modes  */
28962306a36Sopenharmony_ci	/* current reg page of yt8521 phy:
29062306a36Sopenharmony_ci	 * YT8521_RSSR_UTP_SPACE
29162306a36Sopenharmony_ci	 * YT8521_RSSR_FIBER_SPACE
29262306a36Sopenharmony_ci	 * YT8521_RSSR_TO_BE_ARBITRATED
29362306a36Sopenharmony_ci	 */
29462306a36Sopenharmony_ci	u8 reg_page;
29562306a36Sopenharmony_ci};
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/**
29862306a36Sopenharmony_ci * ytphy_read_ext() - read a PHY's extended register
29962306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
30062306a36Sopenharmony_ci * @regnum: register number to read
30162306a36Sopenharmony_ci *
30262306a36Sopenharmony_ci * NOTE:The caller must have taken the MDIO bus lock.
30362306a36Sopenharmony_ci *
30462306a36Sopenharmony_ci * returns the value of regnum reg or negative error code
30562306a36Sopenharmony_ci */
30662306a36Sopenharmony_cistatic int ytphy_read_ext(struct phy_device *phydev, u16 regnum)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	int ret;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	ret = __phy_write(phydev, YTPHY_PAGE_SELECT, regnum);
31162306a36Sopenharmony_ci	if (ret < 0)
31262306a36Sopenharmony_ci		return ret;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return __phy_read(phydev, YTPHY_PAGE_DATA);
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci/**
31862306a36Sopenharmony_ci * ytphy_read_ext_with_lock() - read a PHY's extended register
31962306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
32062306a36Sopenharmony_ci * @regnum: register number to read
32162306a36Sopenharmony_ci *
32262306a36Sopenharmony_ci * returns the value of regnum reg or negative error code
32362306a36Sopenharmony_ci */
32462306a36Sopenharmony_cistatic int ytphy_read_ext_with_lock(struct phy_device *phydev, u16 regnum)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	int ret;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	phy_lock_mdio_bus(phydev);
32962306a36Sopenharmony_ci	ret = ytphy_read_ext(phydev, regnum);
33062306a36Sopenharmony_ci	phy_unlock_mdio_bus(phydev);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return ret;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci/**
33662306a36Sopenharmony_ci * ytphy_write_ext() - write a PHY's extended register
33762306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
33862306a36Sopenharmony_ci * @regnum: register number to write
33962306a36Sopenharmony_ci * @val: value to write to @regnum
34062306a36Sopenharmony_ci *
34162306a36Sopenharmony_ci * NOTE:The caller must have taken the MDIO bus lock.
34262306a36Sopenharmony_ci *
34362306a36Sopenharmony_ci * returns 0 or negative error code
34462306a36Sopenharmony_ci */
34562306a36Sopenharmony_cistatic int ytphy_write_ext(struct phy_device *phydev, u16 regnum, u16 val)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	int ret;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	ret = __phy_write(phydev, YTPHY_PAGE_SELECT, regnum);
35062306a36Sopenharmony_ci	if (ret < 0)
35162306a36Sopenharmony_ci		return ret;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return __phy_write(phydev, YTPHY_PAGE_DATA, val);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/**
35762306a36Sopenharmony_ci * ytphy_write_ext_with_lock() - write a PHY's extended register
35862306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
35962306a36Sopenharmony_ci * @regnum: register number to write
36062306a36Sopenharmony_ci * @val: value to write to @regnum
36162306a36Sopenharmony_ci *
36262306a36Sopenharmony_ci * returns 0 or negative error code
36362306a36Sopenharmony_ci */
36462306a36Sopenharmony_cistatic int ytphy_write_ext_with_lock(struct phy_device *phydev, u16 regnum,
36562306a36Sopenharmony_ci				     u16 val)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	int ret;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	phy_lock_mdio_bus(phydev);
37062306a36Sopenharmony_ci	ret = ytphy_write_ext(phydev, regnum, val);
37162306a36Sopenharmony_ci	phy_unlock_mdio_bus(phydev);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	return ret;
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci/**
37762306a36Sopenharmony_ci * ytphy_modify_ext() - bits modify a PHY's extended register
37862306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
37962306a36Sopenharmony_ci * @regnum: register number to write
38062306a36Sopenharmony_ci * @mask: bit mask of bits to clear
38162306a36Sopenharmony_ci * @set: bit mask of bits to set
38262306a36Sopenharmony_ci *
38362306a36Sopenharmony_ci * NOTE: Convenience function which allows a PHY's extended register to be
38462306a36Sopenharmony_ci * modified as new register value = (old register value & ~mask) | set.
38562306a36Sopenharmony_ci * The caller must have taken the MDIO bus lock.
38662306a36Sopenharmony_ci *
38762306a36Sopenharmony_ci * returns 0 or negative error code
38862306a36Sopenharmony_ci */
38962306a36Sopenharmony_cistatic int ytphy_modify_ext(struct phy_device *phydev, u16 regnum, u16 mask,
39062306a36Sopenharmony_ci			    u16 set)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	int ret;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	ret = __phy_write(phydev, YTPHY_PAGE_SELECT, regnum);
39562306a36Sopenharmony_ci	if (ret < 0)
39662306a36Sopenharmony_ci		return ret;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	return __phy_modify(phydev, YTPHY_PAGE_DATA, mask, set);
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci/**
40262306a36Sopenharmony_ci * ytphy_modify_ext_with_lock() - bits modify a PHY's extended register
40362306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
40462306a36Sopenharmony_ci * @regnum: register number to write
40562306a36Sopenharmony_ci * @mask: bit mask of bits to clear
40662306a36Sopenharmony_ci * @set: bit mask of bits to set
40762306a36Sopenharmony_ci *
40862306a36Sopenharmony_ci * NOTE: Convenience function which allows a PHY's extended register to be
40962306a36Sopenharmony_ci * modified as new register value = (old register value & ~mask) | set.
41062306a36Sopenharmony_ci *
41162306a36Sopenharmony_ci * returns 0 or negative error code
41262306a36Sopenharmony_ci */
41362306a36Sopenharmony_cistatic int ytphy_modify_ext_with_lock(struct phy_device *phydev, u16 regnum,
41462306a36Sopenharmony_ci				      u16 mask, u16 set)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	int ret;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	phy_lock_mdio_bus(phydev);
41962306a36Sopenharmony_ci	ret = ytphy_modify_ext(phydev, regnum, mask, set);
42062306a36Sopenharmony_ci	phy_unlock_mdio_bus(phydev);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	return ret;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci/**
42662306a36Sopenharmony_ci * ytphy_get_wol() - report whether wake-on-lan is enabled
42762306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
42862306a36Sopenharmony_ci * @wol: a pointer to a &struct ethtool_wolinfo
42962306a36Sopenharmony_ci *
43062306a36Sopenharmony_ci * NOTE: YTPHY_WOL_CONFIG_REG is common ext reg.
43162306a36Sopenharmony_ci */
43262306a36Sopenharmony_cistatic void ytphy_get_wol(struct phy_device *phydev,
43362306a36Sopenharmony_ci			  struct ethtool_wolinfo *wol)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	int wol_config;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	wol->supported = WAKE_MAGIC;
43862306a36Sopenharmony_ci	wol->wolopts = 0;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	wol_config = ytphy_read_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG);
44162306a36Sopenharmony_ci	if (wol_config < 0)
44262306a36Sopenharmony_ci		return;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (wol_config & YTPHY_WCR_ENABLE)
44562306a36Sopenharmony_ci		wol->wolopts |= WAKE_MAGIC;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci/**
44962306a36Sopenharmony_ci * ytphy_set_wol() - turn wake-on-lan on or off
45062306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
45162306a36Sopenharmony_ci * @wol: a pointer to a &struct ethtool_wolinfo
45262306a36Sopenharmony_ci *
45362306a36Sopenharmony_ci * NOTE: YTPHY_WOL_CONFIG_REG, YTPHY_WOL_MACADDR2_REG, YTPHY_WOL_MACADDR1_REG
45462306a36Sopenharmony_ci * and YTPHY_WOL_MACADDR0_REG are common ext reg. The
45562306a36Sopenharmony_ci * YTPHY_INTERRUPT_ENABLE_REG of UTP is special, fiber also use this register.
45662306a36Sopenharmony_ci *
45762306a36Sopenharmony_ci * returns 0 or negative errno code
45862306a36Sopenharmony_ci */
45962306a36Sopenharmony_cistatic int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct net_device *p_attached_dev;
46262306a36Sopenharmony_ci	const u16 mac_addr_reg[] = {
46362306a36Sopenharmony_ci		YTPHY_WOL_MACADDR2_REG,
46462306a36Sopenharmony_ci		YTPHY_WOL_MACADDR1_REG,
46562306a36Sopenharmony_ci		YTPHY_WOL_MACADDR0_REG,
46662306a36Sopenharmony_ci	};
46762306a36Sopenharmony_ci	const u8 *mac_addr;
46862306a36Sopenharmony_ci	int old_page;
46962306a36Sopenharmony_ci	int ret = 0;
47062306a36Sopenharmony_ci	u16 mask;
47162306a36Sopenharmony_ci	u16 val;
47262306a36Sopenharmony_ci	u8 i;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (wol->wolopts & WAKE_MAGIC) {
47562306a36Sopenharmony_ci		p_attached_dev = phydev->attached_dev;
47662306a36Sopenharmony_ci		if (!p_attached_dev)
47762306a36Sopenharmony_ci			return -ENODEV;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		mac_addr = (const u8 *)p_attached_dev->dev_addr;
48062306a36Sopenharmony_ci		if (!is_valid_ether_addr(mac_addr))
48162306a36Sopenharmony_ci			return -EINVAL;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci		/* lock mdio bus then switch to utp reg space */
48462306a36Sopenharmony_ci		old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
48562306a36Sopenharmony_ci		if (old_page < 0)
48662306a36Sopenharmony_ci			goto err_restore_page;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci		/* Store the device address for the magic packet */
48962306a36Sopenharmony_ci		for (i = 0; i < 3; i++) {
49062306a36Sopenharmony_ci			ret = ytphy_write_ext(phydev, mac_addr_reg[i],
49162306a36Sopenharmony_ci					      ((mac_addr[i * 2] << 8)) |
49262306a36Sopenharmony_ci						      (mac_addr[i * 2 + 1]));
49362306a36Sopenharmony_ci			if (ret < 0)
49462306a36Sopenharmony_ci				goto err_restore_page;
49562306a36Sopenharmony_ci		}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci		/* Enable WOL feature */
49862306a36Sopenharmony_ci		mask = YTPHY_WCR_PULSE_WIDTH_MASK | YTPHY_WCR_INTR_SEL;
49962306a36Sopenharmony_ci		val = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;
50062306a36Sopenharmony_ci		val |= YTPHY_WCR_TYPE_PULSE | YTPHY_WCR_PULSE_WIDTH_672MS;
50162306a36Sopenharmony_ci		ret = ytphy_modify_ext(phydev, YTPHY_WOL_CONFIG_REG, mask, val);
50262306a36Sopenharmony_ci		if (ret < 0)
50362306a36Sopenharmony_ci			goto err_restore_page;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci		/* Enable WOL interrupt */
50662306a36Sopenharmony_ci		ret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, 0,
50762306a36Sopenharmony_ci				   YTPHY_IER_WOL);
50862306a36Sopenharmony_ci		if (ret < 0)
50962306a36Sopenharmony_ci			goto err_restore_page;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	} else {
51262306a36Sopenharmony_ci		old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
51362306a36Sopenharmony_ci		if (old_page < 0)
51462306a36Sopenharmony_ci			goto err_restore_page;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		/* Disable WOL feature */
51762306a36Sopenharmony_ci		mask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;
51862306a36Sopenharmony_ci		ret = ytphy_modify_ext(phydev, YTPHY_WOL_CONFIG_REG, mask, 0);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		/* Disable WOL interrupt */
52162306a36Sopenharmony_ci		ret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG,
52262306a36Sopenharmony_ci				   YTPHY_IER_WOL, 0);
52362306a36Sopenharmony_ci		if (ret < 0)
52462306a36Sopenharmony_ci			goto err_restore_page;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cierr_restore_page:
52862306a36Sopenharmony_ci	return phy_restore_page(phydev, old_page, ret);
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic int yt8531_set_wol(struct phy_device *phydev,
53262306a36Sopenharmony_ci			  struct ethtool_wolinfo *wol)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	const u16 mac_addr_reg[] = {
53562306a36Sopenharmony_ci		YTPHY_WOL_MACADDR2_REG,
53662306a36Sopenharmony_ci		YTPHY_WOL_MACADDR1_REG,
53762306a36Sopenharmony_ci		YTPHY_WOL_MACADDR0_REG,
53862306a36Sopenharmony_ci	};
53962306a36Sopenharmony_ci	const u8 *mac_addr;
54062306a36Sopenharmony_ci	u16 mask, val;
54162306a36Sopenharmony_ci	int ret;
54262306a36Sopenharmony_ci	u8 i;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	if (wol->wolopts & WAKE_MAGIC) {
54562306a36Sopenharmony_ci		mac_addr = phydev->attached_dev->dev_addr;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		/* Store the device address for the magic packet */
54862306a36Sopenharmony_ci		for (i = 0; i < 3; i++) {
54962306a36Sopenharmony_ci			ret = ytphy_write_ext_with_lock(phydev, mac_addr_reg[i],
55062306a36Sopenharmony_ci							((mac_addr[i * 2] << 8)) |
55162306a36Sopenharmony_ci							(mac_addr[i * 2 + 1]));
55262306a36Sopenharmony_ci			if (ret < 0)
55362306a36Sopenharmony_ci				return ret;
55462306a36Sopenharmony_ci		}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		/* Enable WOL feature */
55762306a36Sopenharmony_ci		mask = YTPHY_WCR_PULSE_WIDTH_MASK | YTPHY_WCR_INTR_SEL;
55862306a36Sopenharmony_ci		val = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;
55962306a36Sopenharmony_ci		val |= YTPHY_WCR_TYPE_PULSE | YTPHY_WCR_PULSE_WIDTH_672MS;
56062306a36Sopenharmony_ci		ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG,
56162306a36Sopenharmony_ci						 mask, val);
56262306a36Sopenharmony_ci		if (ret < 0)
56362306a36Sopenharmony_ci			return ret;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		/* Enable WOL interrupt */
56662306a36Sopenharmony_ci		ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, 0,
56762306a36Sopenharmony_ci				 YTPHY_IER_WOL);
56862306a36Sopenharmony_ci		if (ret < 0)
56962306a36Sopenharmony_ci			return ret;
57062306a36Sopenharmony_ci	} else {
57162306a36Sopenharmony_ci		/* Disable WOL feature */
57262306a36Sopenharmony_ci		mask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;
57362306a36Sopenharmony_ci		ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG,
57462306a36Sopenharmony_ci						 mask, 0);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci		/* Disable WOL interrupt */
57762306a36Sopenharmony_ci		ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG,
57862306a36Sopenharmony_ci				 YTPHY_IER_WOL, 0);
57962306a36Sopenharmony_ci		if (ret < 0)
58062306a36Sopenharmony_ci			return ret;
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	return 0;
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic int yt8511_read_page(struct phy_device *phydev)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	return __phy_read(phydev, YT8511_PAGE_SELECT);
58962306a36Sopenharmony_ci};
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic int yt8511_write_page(struct phy_device *phydev, int page)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	return __phy_write(phydev, YT8511_PAGE_SELECT, page);
59462306a36Sopenharmony_ci};
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic int yt8511_config_init(struct phy_device *phydev)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	int oldpage, ret = 0;
59962306a36Sopenharmony_ci	unsigned int ge, fe;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	oldpage = phy_select_page(phydev, YT8511_EXT_CLK_GATE);
60262306a36Sopenharmony_ci	if (oldpage < 0)
60362306a36Sopenharmony_ci		goto err_restore_page;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* set rgmii delay mode */
60662306a36Sopenharmony_ci	switch (phydev->interface) {
60762306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII:
60862306a36Sopenharmony_ci		ge = YT8511_DELAY_GE_TX_DIS;
60962306a36Sopenharmony_ci		fe = YT8511_DELAY_FE_TX_DIS;
61062306a36Sopenharmony_ci		break;
61162306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_RXID:
61262306a36Sopenharmony_ci		ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_DIS;
61362306a36Sopenharmony_ci		fe = YT8511_DELAY_FE_TX_DIS;
61462306a36Sopenharmony_ci		break;
61562306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_TXID:
61662306a36Sopenharmony_ci		ge = YT8511_DELAY_GE_TX_EN;
61762306a36Sopenharmony_ci		fe = YT8511_DELAY_FE_TX_EN;
61862306a36Sopenharmony_ci		break;
61962306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_ID:
62062306a36Sopenharmony_ci		ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN;
62162306a36Sopenharmony_ci		fe = YT8511_DELAY_FE_TX_EN;
62262306a36Sopenharmony_ci		break;
62362306a36Sopenharmony_ci	default: /* do not support other modes */
62462306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
62562306a36Sopenharmony_ci		goto err_restore_page;
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	ret = __phy_modify(phydev, YT8511_PAGE, (YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN), ge);
62962306a36Sopenharmony_ci	if (ret < 0)
63062306a36Sopenharmony_ci		goto err_restore_page;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	/* set clock mode to 125mhz */
63362306a36Sopenharmony_ci	ret = __phy_modify(phydev, YT8511_PAGE, 0, YT8511_CLK_125M);
63462306a36Sopenharmony_ci	if (ret < 0)
63562306a36Sopenharmony_ci		goto err_restore_page;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	/* fast ethernet delay is in a separate page */
63862306a36Sopenharmony_ci	ret = __phy_write(phydev, YT8511_PAGE_SELECT, YT8511_EXT_DELAY_DRIVE);
63962306a36Sopenharmony_ci	if (ret < 0)
64062306a36Sopenharmony_ci		goto err_restore_page;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	ret = __phy_modify(phydev, YT8511_PAGE, YT8511_DELAY_FE_TX_EN, fe);
64362306a36Sopenharmony_ci	if (ret < 0)
64462306a36Sopenharmony_ci		goto err_restore_page;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/* leave pll enabled in sleep */
64762306a36Sopenharmony_ci	ret = __phy_write(phydev, YT8511_PAGE_SELECT, YT8511_EXT_SLEEP_CTRL);
64862306a36Sopenharmony_ci	if (ret < 0)
64962306a36Sopenharmony_ci		goto err_restore_page;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	ret = __phy_modify(phydev, YT8511_PAGE, 0, YT8511_PLLON_SLP);
65262306a36Sopenharmony_ci	if (ret < 0)
65362306a36Sopenharmony_ci		goto err_restore_page;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cierr_restore_page:
65662306a36Sopenharmony_ci	return phy_restore_page(phydev, oldpage, ret);
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci/**
66062306a36Sopenharmony_ci * yt8521_read_page() - read reg page
66162306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
66262306a36Sopenharmony_ci *
66362306a36Sopenharmony_ci * returns current reg space of yt8521 (YT8521_RSSR_FIBER_SPACE/
66462306a36Sopenharmony_ci * YT8521_RSSR_UTP_SPACE) or negative errno code
66562306a36Sopenharmony_ci */
66662306a36Sopenharmony_cistatic int yt8521_read_page(struct phy_device *phydev)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	int old_page;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	old_page = ytphy_read_ext(phydev, YT8521_REG_SPACE_SELECT_REG);
67162306a36Sopenharmony_ci	if (old_page < 0)
67262306a36Sopenharmony_ci		return old_page;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if ((old_page & YT8521_RSSR_SPACE_MASK) == YT8521_RSSR_FIBER_SPACE)
67562306a36Sopenharmony_ci		return YT8521_RSSR_FIBER_SPACE;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	return YT8521_RSSR_UTP_SPACE;
67862306a36Sopenharmony_ci};
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci/**
68162306a36Sopenharmony_ci * yt8521_write_page() - write reg page
68262306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
68362306a36Sopenharmony_ci * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to write.
68462306a36Sopenharmony_ci *
68562306a36Sopenharmony_ci * returns 0 or negative errno code
68662306a36Sopenharmony_ci */
68762306a36Sopenharmony_cistatic int yt8521_write_page(struct phy_device *phydev, int page)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	int mask = YT8521_RSSR_SPACE_MASK;
69062306a36Sopenharmony_ci	int set;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if ((page & YT8521_RSSR_SPACE_MASK) == YT8521_RSSR_FIBER_SPACE)
69362306a36Sopenharmony_ci		set = YT8521_RSSR_FIBER_SPACE;
69462306a36Sopenharmony_ci	else
69562306a36Sopenharmony_ci		set = YT8521_RSSR_UTP_SPACE;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	return ytphy_modify_ext(phydev, YT8521_REG_SPACE_SELECT_REG, mask, set);
69862306a36Sopenharmony_ci};
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci/**
70162306a36Sopenharmony_ci * struct ytphy_cfg_reg_map - map a config value to a register value
70262306a36Sopenharmony_ci * @cfg: value in device configuration
70362306a36Sopenharmony_ci * @reg: value in the register
70462306a36Sopenharmony_ci */
70562306a36Sopenharmony_cistruct ytphy_cfg_reg_map {
70662306a36Sopenharmony_ci	u32 cfg;
70762306a36Sopenharmony_ci	u32 reg;
70862306a36Sopenharmony_ci};
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic const struct ytphy_cfg_reg_map ytphy_rgmii_delays[] = {
71162306a36Sopenharmony_ci	/* for tx delay / rx delay with YT8521_CCR_RXC_DLY_EN is not set. */
71262306a36Sopenharmony_ci	{ 0,	YT8521_RC1R_RGMII_0_000_NS },
71362306a36Sopenharmony_ci	{ 150,	YT8521_RC1R_RGMII_0_150_NS },
71462306a36Sopenharmony_ci	{ 300,	YT8521_RC1R_RGMII_0_300_NS },
71562306a36Sopenharmony_ci	{ 450,	YT8521_RC1R_RGMII_0_450_NS },
71662306a36Sopenharmony_ci	{ 600,	YT8521_RC1R_RGMII_0_600_NS },
71762306a36Sopenharmony_ci	{ 750,	YT8521_RC1R_RGMII_0_750_NS },
71862306a36Sopenharmony_ci	{ 900,	YT8521_RC1R_RGMII_0_900_NS },
71962306a36Sopenharmony_ci	{ 1050,	YT8521_RC1R_RGMII_1_050_NS },
72062306a36Sopenharmony_ci	{ 1200,	YT8521_RC1R_RGMII_1_200_NS },
72162306a36Sopenharmony_ci	{ 1350,	YT8521_RC1R_RGMII_1_350_NS },
72262306a36Sopenharmony_ci	{ 1500,	YT8521_RC1R_RGMII_1_500_NS },
72362306a36Sopenharmony_ci	{ 1650,	YT8521_RC1R_RGMII_1_650_NS },
72462306a36Sopenharmony_ci	{ 1800,	YT8521_RC1R_RGMII_1_800_NS },
72562306a36Sopenharmony_ci	{ 1950,	YT8521_RC1R_RGMII_1_950_NS },	/* default tx/rx delay */
72662306a36Sopenharmony_ci	{ 2100,	YT8521_RC1R_RGMII_2_100_NS },
72762306a36Sopenharmony_ci	{ 2250,	YT8521_RC1R_RGMII_2_250_NS },
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	/* only for rx delay with YT8521_CCR_RXC_DLY_EN is set. */
73062306a36Sopenharmony_ci	{ 0    + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_0_000_NS },
73162306a36Sopenharmony_ci	{ 150  + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_0_150_NS },
73262306a36Sopenharmony_ci	{ 300  + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_0_300_NS },
73362306a36Sopenharmony_ci	{ 450  + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_0_450_NS },
73462306a36Sopenharmony_ci	{ 600  + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_0_600_NS },
73562306a36Sopenharmony_ci	{ 750  + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_0_750_NS },
73662306a36Sopenharmony_ci	{ 900  + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_0_900_NS },
73762306a36Sopenharmony_ci	{ 1050 + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_1_050_NS },
73862306a36Sopenharmony_ci	{ 1200 + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_1_200_NS },
73962306a36Sopenharmony_ci	{ 1350 + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_1_350_NS },
74062306a36Sopenharmony_ci	{ 1500 + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_1_500_NS },
74162306a36Sopenharmony_ci	{ 1650 + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_1_650_NS },
74262306a36Sopenharmony_ci	{ 1800 + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_1_800_NS },
74362306a36Sopenharmony_ci	{ 1950 + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_1_950_NS },
74462306a36Sopenharmony_ci	{ 2100 + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_2_100_NS },
74562306a36Sopenharmony_ci	{ 2250 + YT8521_CCR_RXC_DLY_1_900_NS,	YT8521_RC1R_RGMII_2_250_NS }
74662306a36Sopenharmony_ci};
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_cistatic u32 ytphy_get_delay_reg_value(struct phy_device *phydev,
74962306a36Sopenharmony_ci				     const char *prop_name,
75062306a36Sopenharmony_ci				     const struct ytphy_cfg_reg_map *tbl,
75162306a36Sopenharmony_ci				     int tb_size,
75262306a36Sopenharmony_ci				     u16 *rxc_dly_en,
75362306a36Sopenharmony_ci				     u32 dflt)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	struct device_node *node = phydev->mdio.dev.of_node;
75662306a36Sopenharmony_ci	int tb_size_half = tb_size / 2;
75762306a36Sopenharmony_ci	u32 val;
75862306a36Sopenharmony_ci	int i;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if (of_property_read_u32(node, prop_name, &val))
76162306a36Sopenharmony_ci		goto err_dts_val;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	/* when rxc_dly_en is NULL, it is get the delay for tx, only half of
76462306a36Sopenharmony_ci	 * tb_size is valid.
76562306a36Sopenharmony_ci	 */
76662306a36Sopenharmony_ci	if (!rxc_dly_en)
76762306a36Sopenharmony_ci		tb_size = tb_size_half;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	for (i = 0; i < tb_size; i++) {
77062306a36Sopenharmony_ci		if (tbl[i].cfg == val) {
77162306a36Sopenharmony_ci			if (rxc_dly_en && i < tb_size_half)
77262306a36Sopenharmony_ci				*rxc_dly_en = 0;
77362306a36Sopenharmony_ci			return tbl[i].reg;
77462306a36Sopenharmony_ci		}
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	phydev_warn(phydev, "Unsupported value %d for %s using default (%u)\n",
77862306a36Sopenharmony_ci		    val, prop_name, dflt);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cierr_dts_val:
78162306a36Sopenharmony_ci	/* when rxc_dly_en is not NULL, it is get the delay for rx.
78262306a36Sopenharmony_ci	 * The rx default in dts and ytphy_rgmii_clk_delay_config is 1950 ps,
78362306a36Sopenharmony_ci	 * so YT8521_CCR_RXC_DLY_EN should not be set.
78462306a36Sopenharmony_ci	 */
78562306a36Sopenharmony_ci	if (rxc_dly_en)
78662306a36Sopenharmony_ci		*rxc_dly_en = 0;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	return dflt;
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic int ytphy_rgmii_clk_delay_config(struct phy_device *phydev)
79262306a36Sopenharmony_ci{
79362306a36Sopenharmony_ci	int tb_size = ARRAY_SIZE(ytphy_rgmii_delays);
79462306a36Sopenharmony_ci	u16 rxc_dly_en = YT8521_CCR_RXC_DLY_EN;
79562306a36Sopenharmony_ci	u32 rx_reg, tx_reg;
79662306a36Sopenharmony_ci	u16 mask, val = 0;
79762306a36Sopenharmony_ci	int ret;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	rx_reg = ytphy_get_delay_reg_value(phydev, "rx-internal-delay-ps",
80062306a36Sopenharmony_ci					   ytphy_rgmii_delays, tb_size,
80162306a36Sopenharmony_ci					   &rxc_dly_en,
80262306a36Sopenharmony_ci					   YT8521_RC1R_RGMII_1_950_NS);
80362306a36Sopenharmony_ci	tx_reg = ytphy_get_delay_reg_value(phydev, "tx-internal-delay-ps",
80462306a36Sopenharmony_ci					   ytphy_rgmii_delays, tb_size, NULL,
80562306a36Sopenharmony_ci					   YT8521_RC1R_RGMII_1_950_NS);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	switch (phydev->interface) {
80862306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII:
80962306a36Sopenharmony_ci		rxc_dly_en = 0;
81062306a36Sopenharmony_ci		break;
81162306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_RXID:
81262306a36Sopenharmony_ci		val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg);
81362306a36Sopenharmony_ci		break;
81462306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_TXID:
81562306a36Sopenharmony_ci		rxc_dly_en = 0;
81662306a36Sopenharmony_ci		val |= FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg);
81762306a36Sopenharmony_ci		break;
81862306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_ID:
81962306a36Sopenharmony_ci		val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg) |
82062306a36Sopenharmony_ci		       FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg);
82162306a36Sopenharmony_ci		break;
82262306a36Sopenharmony_ci	default: /* do not support other modes */
82362306a36Sopenharmony_ci		return -EOPNOTSUPP;
82462306a36Sopenharmony_ci	}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	ret = ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG,
82762306a36Sopenharmony_ci			       YT8521_CCR_RXC_DLY_EN, rxc_dly_en);
82862306a36Sopenharmony_ci	if (ret < 0)
82962306a36Sopenharmony_ci		return ret;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/* Generally, it is not necessary to adjust YT8521_RC1R_FE_TX_DELAY */
83262306a36Sopenharmony_ci	mask = YT8521_RC1R_RX_DELAY_MASK | YT8521_RC1R_GE_TX_DELAY_MASK;
83362306a36Sopenharmony_ci	return ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, mask, val);
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic int ytphy_rgmii_clk_delay_config_with_lock(struct phy_device *phydev)
83762306a36Sopenharmony_ci{
83862306a36Sopenharmony_ci	int ret;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	phy_lock_mdio_bus(phydev);
84162306a36Sopenharmony_ci	ret = ytphy_rgmii_clk_delay_config(phydev);
84262306a36Sopenharmony_ci	phy_unlock_mdio_bus(phydev);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	return ret;
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci/**
84862306a36Sopenharmony_ci * struct ytphy_ldo_vol_map - map a current value to a register value
84962306a36Sopenharmony_ci * @vol: ldo voltage
85062306a36Sopenharmony_ci * @ds:  value in the register
85162306a36Sopenharmony_ci * @cur: value in device configuration
85262306a36Sopenharmony_ci */
85362306a36Sopenharmony_cistruct ytphy_ldo_vol_map {
85462306a36Sopenharmony_ci	u32 vol;
85562306a36Sopenharmony_ci	u32 ds;
85662306a36Sopenharmony_ci	u32 cur;
85762306a36Sopenharmony_ci};
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_cistatic const struct ytphy_ldo_vol_map yt8531_ldo_vol[] = {
86062306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_1V8, .ds = 0, .cur = 1200},
86162306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_1V8, .ds = 1, .cur = 2100},
86262306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_1V8, .ds = 2, .cur = 2700},
86362306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_1V8, .ds = 3, .cur = 2910},
86462306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_1V8, .ds = 4, .cur = 3110},
86562306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_1V8, .ds = 5, .cur = 3600},
86662306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_1V8, .ds = 6, .cur = 3970},
86762306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_1V8, .ds = 7, .cur = 4350},
86862306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_3V3, .ds = 0, .cur = 3070},
86962306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_3V3, .ds = 1, .cur = 4080},
87062306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_3V3, .ds = 2, .cur = 4370},
87162306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_3V3, .ds = 3, .cur = 4680},
87262306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_3V3, .ds = 4, .cur = 5020},
87362306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_3V3, .ds = 5, .cur = 5450},
87462306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_3V3, .ds = 6, .cur = 5740},
87562306a36Sopenharmony_ci	{.vol = YT8531_LDO_VOL_3V3, .ds = 7, .cur = 6140},
87662306a36Sopenharmony_ci};
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic u32 yt8531_get_ldo_vol(struct phy_device *phydev)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	u32 val;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	val = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG);
88362306a36Sopenharmony_ci	val = FIELD_GET(YT8531_RGMII_LDO_VOL_MASK, val);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	return val <= YT8531_LDO_VOL_1V8 ? val : YT8531_LDO_VOL_1V8;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic int yt8531_get_ds_map(struct phy_device *phydev, u32 cur)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	u32 vol;
89162306a36Sopenharmony_ci	int i;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	vol = yt8531_get_ldo_vol(phydev);
89462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(yt8531_ldo_vol); i++) {
89562306a36Sopenharmony_ci		if (yt8531_ldo_vol[i].vol == vol && yt8531_ldo_vol[i].cur == cur)
89662306a36Sopenharmony_ci			return yt8531_ldo_vol[i].ds;
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	return -EINVAL;
90062306a36Sopenharmony_ci}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_cistatic int yt8531_set_ds(struct phy_device *phydev)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	struct device_node *node = phydev->mdio.dev.of_node;
90562306a36Sopenharmony_ci	u32 ds_field_low, ds_field_hi, val;
90662306a36Sopenharmony_ci	int ret, ds;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	/* set rgmii rx clk driver strength */
90962306a36Sopenharmony_ci	if (!of_property_read_u32(node, "motorcomm,rx-clk-drv-microamp", &val)) {
91062306a36Sopenharmony_ci		ds = yt8531_get_ds_map(phydev, val);
91162306a36Sopenharmony_ci		if (ds < 0)
91262306a36Sopenharmony_ci			return dev_err_probe(&phydev->mdio.dev, ds,
91362306a36Sopenharmony_ci					     "No matching current value was found.\n");
91462306a36Sopenharmony_ci	} else {
91562306a36Sopenharmony_ci		ds = YT8531_RGMII_RX_DS_DEFAULT;
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	ret = ytphy_modify_ext_with_lock(phydev,
91962306a36Sopenharmony_ci					 YTPHY_PAD_DRIVE_STRENGTH_REG,
92062306a36Sopenharmony_ci					 YT8531_RGMII_RXC_DS_MASK,
92162306a36Sopenharmony_ci					 FIELD_PREP(YT8531_RGMII_RXC_DS_MASK, ds));
92262306a36Sopenharmony_ci	if (ret < 0)
92362306a36Sopenharmony_ci		return ret;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	/* set rgmii rx data driver strength */
92662306a36Sopenharmony_ci	if (!of_property_read_u32(node, "motorcomm,rx-data-drv-microamp", &val)) {
92762306a36Sopenharmony_ci		ds = yt8531_get_ds_map(phydev, val);
92862306a36Sopenharmony_ci		if (ds < 0)
92962306a36Sopenharmony_ci			return dev_err_probe(&phydev->mdio.dev, ds,
93062306a36Sopenharmony_ci					     "No matching current value was found.\n");
93162306a36Sopenharmony_ci	} else {
93262306a36Sopenharmony_ci		ds = YT8531_RGMII_RX_DS_DEFAULT;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	ds_field_hi = FIELD_GET(BIT(2), ds);
93662306a36Sopenharmony_ci	ds_field_hi = FIELD_PREP(YT8531_RGMII_RXD_DS_HI_MASK, ds_field_hi);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	ds_field_low = FIELD_GET(GENMASK(1, 0), ds);
93962306a36Sopenharmony_ci	ds_field_low = FIELD_PREP(YT8531_RGMII_RXD_DS_LOW_MASK, ds_field_low);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	ret = ytphy_modify_ext_with_lock(phydev,
94262306a36Sopenharmony_ci					 YTPHY_PAD_DRIVE_STRENGTH_REG,
94362306a36Sopenharmony_ci					 YT8531_RGMII_RXD_DS_LOW_MASK | YT8531_RGMII_RXD_DS_HI_MASK,
94462306a36Sopenharmony_ci					 ds_field_low | ds_field_hi);
94562306a36Sopenharmony_ci	if (ret < 0)
94662306a36Sopenharmony_ci		return ret;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	return 0;
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci/**
95262306a36Sopenharmony_ci * yt8521_probe() - read chip config then set suitable polling_mode
95362306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
95462306a36Sopenharmony_ci *
95562306a36Sopenharmony_ci * returns 0 or negative errno code
95662306a36Sopenharmony_ci */
95762306a36Sopenharmony_cistatic int yt8521_probe(struct phy_device *phydev)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	struct device_node *node = phydev->mdio.dev.of_node;
96062306a36Sopenharmony_ci	struct device *dev = &phydev->mdio.dev;
96162306a36Sopenharmony_ci	struct yt8521_priv *priv;
96262306a36Sopenharmony_ci	int chip_config;
96362306a36Sopenharmony_ci	u16 mask, val;
96462306a36Sopenharmony_ci	u32 freq;
96562306a36Sopenharmony_ci	int ret;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
96862306a36Sopenharmony_ci	if (!priv)
96962306a36Sopenharmony_ci		return -ENOMEM;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	phydev->priv = priv;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	chip_config = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG);
97462306a36Sopenharmony_ci	if (chip_config < 0)
97562306a36Sopenharmony_ci		return chip_config;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	priv->strap_mode = chip_config & YT8521_CCR_MODE_SEL_MASK;
97862306a36Sopenharmony_ci	switch (priv->strap_mode) {
97962306a36Sopenharmony_ci	case YT8521_CCR_MODE_FIBER_TO_RGMII:
98062306a36Sopenharmony_ci	case YT8521_CCR_MODE_SGPHY_TO_RGMAC:
98162306a36Sopenharmony_ci	case YT8521_CCR_MODE_SGMAC_TO_RGPHY:
98262306a36Sopenharmony_ci		priv->polling_mode = YT8521_MODE_FIBER;
98362306a36Sopenharmony_ci		priv->reg_page = YT8521_RSSR_FIBER_SPACE;
98462306a36Sopenharmony_ci		phydev->port = PORT_FIBRE;
98562306a36Sopenharmony_ci		break;
98662306a36Sopenharmony_ci	case YT8521_CCR_MODE_UTP_FIBER_TO_RGMII:
98762306a36Sopenharmony_ci	case YT8521_CCR_MODE_UTP_TO_FIBER_AUTO:
98862306a36Sopenharmony_ci	case YT8521_CCR_MODE_UTP_TO_FIBER_FORCE:
98962306a36Sopenharmony_ci		priv->polling_mode = YT8521_MODE_POLL;
99062306a36Sopenharmony_ci		priv->reg_page = YT8521_RSSR_TO_BE_ARBITRATED;
99162306a36Sopenharmony_ci		phydev->port = PORT_NONE;
99262306a36Sopenharmony_ci		break;
99362306a36Sopenharmony_ci	case YT8521_CCR_MODE_UTP_TO_SGMII:
99462306a36Sopenharmony_ci	case YT8521_CCR_MODE_UTP_TO_RGMII:
99562306a36Sopenharmony_ci		priv->polling_mode = YT8521_MODE_UTP;
99662306a36Sopenharmony_ci		priv->reg_page = YT8521_RSSR_UTP_SPACE;
99762306a36Sopenharmony_ci		phydev->port = PORT_TP;
99862306a36Sopenharmony_ci		break;
99962306a36Sopenharmony_ci	}
100062306a36Sopenharmony_ci	/* set default reg space */
100162306a36Sopenharmony_ci	if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
100262306a36Sopenharmony_ci		ret = ytphy_write_ext_with_lock(phydev,
100362306a36Sopenharmony_ci						YT8521_REG_SPACE_SELECT_REG,
100462306a36Sopenharmony_ci						priv->reg_page);
100562306a36Sopenharmony_ci		if (ret < 0)
100662306a36Sopenharmony_ci			return ret;
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (of_property_read_u32(node, "motorcomm,clk-out-frequency-hz", &freq))
101062306a36Sopenharmony_ci		freq = YTPHY_DTS_OUTPUT_CLK_DIS;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	if (phydev->drv->phy_id == PHY_ID_YT8521) {
101362306a36Sopenharmony_ci		switch (freq) {
101462306a36Sopenharmony_ci		case YTPHY_DTS_OUTPUT_CLK_DIS:
101562306a36Sopenharmony_ci			mask = YT8521_SCR_SYNCE_ENABLE;
101662306a36Sopenharmony_ci			val = 0;
101762306a36Sopenharmony_ci			break;
101862306a36Sopenharmony_ci		case YTPHY_DTS_OUTPUT_CLK_25M:
101962306a36Sopenharmony_ci			mask = YT8521_SCR_SYNCE_ENABLE |
102062306a36Sopenharmony_ci			       YT8521_SCR_CLK_SRC_MASK |
102162306a36Sopenharmony_ci			       YT8521_SCR_CLK_FRE_SEL_125M;
102262306a36Sopenharmony_ci			val = YT8521_SCR_SYNCE_ENABLE |
102362306a36Sopenharmony_ci			      FIELD_PREP(YT8521_SCR_CLK_SRC_MASK,
102462306a36Sopenharmony_ci					 YT8521_SCR_CLK_SRC_REF_25M);
102562306a36Sopenharmony_ci			break;
102662306a36Sopenharmony_ci		case YTPHY_DTS_OUTPUT_CLK_125M:
102762306a36Sopenharmony_ci			mask = YT8521_SCR_SYNCE_ENABLE |
102862306a36Sopenharmony_ci			       YT8521_SCR_CLK_SRC_MASK |
102962306a36Sopenharmony_ci			       YT8521_SCR_CLK_FRE_SEL_125M;
103062306a36Sopenharmony_ci			val = YT8521_SCR_SYNCE_ENABLE |
103162306a36Sopenharmony_ci			      YT8521_SCR_CLK_FRE_SEL_125M |
103262306a36Sopenharmony_ci			      FIELD_PREP(YT8521_SCR_CLK_SRC_MASK,
103362306a36Sopenharmony_ci					 YT8521_SCR_CLK_SRC_PLL_125M);
103462306a36Sopenharmony_ci			break;
103562306a36Sopenharmony_ci		default:
103662306a36Sopenharmony_ci			phydev_warn(phydev, "Freq err:%u\n", freq);
103762306a36Sopenharmony_ci			return -EINVAL;
103862306a36Sopenharmony_ci		}
103962306a36Sopenharmony_ci	} else if (phydev->drv->phy_id == PHY_ID_YT8531S) {
104062306a36Sopenharmony_ci		switch (freq) {
104162306a36Sopenharmony_ci		case YTPHY_DTS_OUTPUT_CLK_DIS:
104262306a36Sopenharmony_ci			mask = YT8531_SCR_SYNCE_ENABLE;
104362306a36Sopenharmony_ci			val = 0;
104462306a36Sopenharmony_ci			break;
104562306a36Sopenharmony_ci		case YTPHY_DTS_OUTPUT_CLK_25M:
104662306a36Sopenharmony_ci			mask = YT8531_SCR_SYNCE_ENABLE |
104762306a36Sopenharmony_ci			       YT8531_SCR_CLK_SRC_MASK |
104862306a36Sopenharmony_ci			       YT8531_SCR_CLK_FRE_SEL_125M;
104962306a36Sopenharmony_ci			val = YT8531_SCR_SYNCE_ENABLE |
105062306a36Sopenharmony_ci			      FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
105162306a36Sopenharmony_ci					 YT8531_SCR_CLK_SRC_REF_25M);
105262306a36Sopenharmony_ci			break;
105362306a36Sopenharmony_ci		case YTPHY_DTS_OUTPUT_CLK_125M:
105462306a36Sopenharmony_ci			mask = YT8531_SCR_SYNCE_ENABLE |
105562306a36Sopenharmony_ci			       YT8531_SCR_CLK_SRC_MASK |
105662306a36Sopenharmony_ci			       YT8531_SCR_CLK_FRE_SEL_125M;
105762306a36Sopenharmony_ci			val = YT8531_SCR_SYNCE_ENABLE |
105862306a36Sopenharmony_ci			      YT8531_SCR_CLK_FRE_SEL_125M |
105962306a36Sopenharmony_ci			      FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
106062306a36Sopenharmony_ci					 YT8531_SCR_CLK_SRC_PLL_125M);
106162306a36Sopenharmony_ci			break;
106262306a36Sopenharmony_ci		default:
106362306a36Sopenharmony_ci			phydev_warn(phydev, "Freq err:%u\n", freq);
106462306a36Sopenharmony_ci			return -EINVAL;
106562306a36Sopenharmony_ci		}
106662306a36Sopenharmony_ci	} else {
106762306a36Sopenharmony_ci		phydev_warn(phydev, "PHY id err\n");
106862306a36Sopenharmony_ci		return -EINVAL;
106962306a36Sopenharmony_ci	}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	return ytphy_modify_ext_with_lock(phydev, YTPHY_SYNCE_CFG_REG, mask,
107262306a36Sopenharmony_ci					  val);
107362306a36Sopenharmony_ci}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_cistatic int yt8531_probe(struct phy_device *phydev)
107662306a36Sopenharmony_ci{
107762306a36Sopenharmony_ci	struct device_node *node = phydev->mdio.dev.of_node;
107862306a36Sopenharmony_ci	u16 mask, val;
107962306a36Sopenharmony_ci	u32 freq;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	if (of_property_read_u32(node, "motorcomm,clk-out-frequency-hz", &freq))
108262306a36Sopenharmony_ci		freq = YTPHY_DTS_OUTPUT_CLK_DIS;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	switch (freq) {
108562306a36Sopenharmony_ci	case YTPHY_DTS_OUTPUT_CLK_DIS:
108662306a36Sopenharmony_ci		mask = YT8531_SCR_SYNCE_ENABLE;
108762306a36Sopenharmony_ci		val = 0;
108862306a36Sopenharmony_ci		break;
108962306a36Sopenharmony_ci	case YTPHY_DTS_OUTPUT_CLK_25M:
109062306a36Sopenharmony_ci		mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK |
109162306a36Sopenharmony_ci		       YT8531_SCR_CLK_FRE_SEL_125M;
109262306a36Sopenharmony_ci		val = YT8531_SCR_SYNCE_ENABLE |
109362306a36Sopenharmony_ci		      FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
109462306a36Sopenharmony_ci				 YT8531_SCR_CLK_SRC_REF_25M);
109562306a36Sopenharmony_ci		break;
109662306a36Sopenharmony_ci	case YTPHY_DTS_OUTPUT_CLK_125M:
109762306a36Sopenharmony_ci		mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK |
109862306a36Sopenharmony_ci		       YT8531_SCR_CLK_FRE_SEL_125M;
109962306a36Sopenharmony_ci		val = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_FRE_SEL_125M |
110062306a36Sopenharmony_ci		      FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
110162306a36Sopenharmony_ci				 YT8531_SCR_CLK_SRC_PLL_125M);
110262306a36Sopenharmony_ci		break;
110362306a36Sopenharmony_ci	default:
110462306a36Sopenharmony_ci		phydev_warn(phydev, "Freq err:%u\n", freq);
110562306a36Sopenharmony_ci		return -EINVAL;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	return ytphy_modify_ext_with_lock(phydev, YTPHY_SYNCE_CFG_REG, mask,
110962306a36Sopenharmony_ci					  val);
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci/**
111362306a36Sopenharmony_ci * ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp
111462306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
111562306a36Sopenharmony_ci *
111662306a36Sopenharmony_ci * NOTE:The caller must have taken the MDIO bus lock.
111762306a36Sopenharmony_ci *
111862306a36Sopenharmony_ci * returns 0 or negative errno code
111962306a36Sopenharmony_ci */
112062306a36Sopenharmony_cistatic int ytphy_utp_read_lpa(struct phy_device *phydev)
112162306a36Sopenharmony_ci{
112262306a36Sopenharmony_ci	int lpa, lpagb;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	if (phydev->autoneg == AUTONEG_ENABLE) {
112562306a36Sopenharmony_ci		if (!phydev->autoneg_complete) {
112662306a36Sopenharmony_ci			mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising,
112762306a36Sopenharmony_ci							0);
112862306a36Sopenharmony_ci			mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
112962306a36Sopenharmony_ci			return 0;
113062306a36Sopenharmony_ci		}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci		if (phydev->is_gigabit_capable) {
113362306a36Sopenharmony_ci			lpagb = __phy_read(phydev, MII_STAT1000);
113462306a36Sopenharmony_ci			if (lpagb < 0)
113562306a36Sopenharmony_ci				return lpagb;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci			if (lpagb & LPA_1000MSFAIL) {
113862306a36Sopenharmony_ci				int adv = __phy_read(phydev, MII_CTRL1000);
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci				if (adv < 0)
114162306a36Sopenharmony_ci					return adv;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci				if (adv & CTL1000_ENABLE_MASTER)
114462306a36Sopenharmony_ci					phydev_err(phydev, "Master/Slave resolution failed, maybe conflicting manual settings?\n");
114562306a36Sopenharmony_ci				else
114662306a36Sopenharmony_ci					phydev_err(phydev, "Master/Slave resolution failed\n");
114762306a36Sopenharmony_ci				return -ENOLINK;
114862306a36Sopenharmony_ci			}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci			mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising,
115162306a36Sopenharmony_ci							lpagb);
115262306a36Sopenharmony_ci		}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci		lpa = __phy_read(phydev, MII_LPA);
115562306a36Sopenharmony_ci		if (lpa < 0)
115662306a36Sopenharmony_ci			return lpa;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci		mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa);
115962306a36Sopenharmony_ci	} else {
116062306a36Sopenharmony_ci		linkmode_zero(phydev->lp_advertising);
116162306a36Sopenharmony_ci	}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	return 0;
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci/**
116762306a36Sopenharmony_ci * yt8521_adjust_status() - update speed and duplex to phydev. when in fiber
116862306a36Sopenharmony_ci * mode, adjust speed and duplex.
116962306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
117062306a36Sopenharmony_ci * @status: yt8521 status read from YTPHY_SPECIFIC_STATUS_REG
117162306a36Sopenharmony_ci * @is_utp: false(yt8521 work in fiber mode) or true(yt8521 work in utp mode)
117262306a36Sopenharmony_ci *
117362306a36Sopenharmony_ci * NOTE:The caller must have taken the MDIO bus lock.
117462306a36Sopenharmony_ci *
117562306a36Sopenharmony_ci * returns 0
117662306a36Sopenharmony_ci */
117762306a36Sopenharmony_cistatic int yt8521_adjust_status(struct phy_device *phydev, int status,
117862306a36Sopenharmony_ci				bool is_utp)
117962306a36Sopenharmony_ci{
118062306a36Sopenharmony_ci	int speed_mode, duplex;
118162306a36Sopenharmony_ci	int speed;
118262306a36Sopenharmony_ci	int err;
118362306a36Sopenharmony_ci	int lpa;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	if (is_utp)
118662306a36Sopenharmony_ci		duplex = (status & YTPHY_SSR_DUPLEX) >> YTPHY_SSR_DUPLEX_OFFSET;
118762306a36Sopenharmony_ci	else
118862306a36Sopenharmony_ci		duplex = DUPLEX_FULL;	/* for fiber, it always DUPLEX_FULL */
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	speed_mode = (status & YTPHY_SSR_SPEED_MODE_MASK) >>
119162306a36Sopenharmony_ci		     YTPHY_SSR_SPEED_MODE_OFFSET;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	switch (speed_mode) {
119462306a36Sopenharmony_ci	case YTPHY_SSR_SPEED_10M:
119562306a36Sopenharmony_ci		if (is_utp)
119662306a36Sopenharmony_ci			speed = SPEED_10;
119762306a36Sopenharmony_ci		else
119862306a36Sopenharmony_ci			/* for fiber, it will never run here, default to
119962306a36Sopenharmony_ci			 * SPEED_UNKNOWN
120062306a36Sopenharmony_ci			 */
120162306a36Sopenharmony_ci			speed = SPEED_UNKNOWN;
120262306a36Sopenharmony_ci		break;
120362306a36Sopenharmony_ci	case YTPHY_SSR_SPEED_100M:
120462306a36Sopenharmony_ci		speed = SPEED_100;
120562306a36Sopenharmony_ci		break;
120662306a36Sopenharmony_ci	case YTPHY_SSR_SPEED_1000M:
120762306a36Sopenharmony_ci		speed = SPEED_1000;
120862306a36Sopenharmony_ci		break;
120962306a36Sopenharmony_ci	default:
121062306a36Sopenharmony_ci		speed = SPEED_UNKNOWN;
121162306a36Sopenharmony_ci		break;
121262306a36Sopenharmony_ci	}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	phydev->speed = speed;
121562306a36Sopenharmony_ci	phydev->duplex = duplex;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	if (is_utp) {
121862306a36Sopenharmony_ci		err = ytphy_utp_read_lpa(phydev);
121962306a36Sopenharmony_ci		if (err < 0)
122062306a36Sopenharmony_ci			return err;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci		phy_resolve_aneg_pause(phydev);
122362306a36Sopenharmony_ci	} else {
122462306a36Sopenharmony_ci		lpa = __phy_read(phydev, MII_LPA);
122562306a36Sopenharmony_ci		if (lpa < 0)
122662306a36Sopenharmony_ci			return lpa;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci		/* only support 1000baseX Full */
122962306a36Sopenharmony_ci		linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
123062306a36Sopenharmony_ci				 phydev->lp_advertising, lpa & LPA_1000XFULL);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci		if (!(lpa & YTPHY_FLPA_PAUSE)) {
123362306a36Sopenharmony_ci			phydev->pause = 0;
123462306a36Sopenharmony_ci			phydev->asym_pause = 0;
123562306a36Sopenharmony_ci		} else if ((lpa & YTPHY_FLPA_ASYM_PAUSE)) {
123662306a36Sopenharmony_ci			phydev->pause = 1;
123762306a36Sopenharmony_ci			phydev->asym_pause = 1;
123862306a36Sopenharmony_ci		} else {
123962306a36Sopenharmony_ci			phydev->pause = 1;
124062306a36Sopenharmony_ci			phydev->asym_pause = 0;
124162306a36Sopenharmony_ci		}
124262306a36Sopenharmony_ci	}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	return 0;
124562306a36Sopenharmony_ci}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci/**
124862306a36Sopenharmony_ci * yt8521_read_status_paged() -  determines the speed and duplex of one page
124962306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
125062306a36Sopenharmony_ci * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to
125162306a36Sopenharmony_ci * operate.
125262306a36Sopenharmony_ci *
125362306a36Sopenharmony_ci * returns 1 (utp or fiber link),0 (no link) or negative errno code
125462306a36Sopenharmony_ci */
125562306a36Sopenharmony_cistatic int yt8521_read_status_paged(struct phy_device *phydev, int page)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	int fiber_latch_val;
125862306a36Sopenharmony_ci	int fiber_curr_val;
125962306a36Sopenharmony_ci	int old_page;
126062306a36Sopenharmony_ci	int ret = 0;
126162306a36Sopenharmony_ci	int status;
126262306a36Sopenharmony_ci	int link;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	linkmode_zero(phydev->lp_advertising);
126562306a36Sopenharmony_ci	phydev->duplex = DUPLEX_UNKNOWN;
126662306a36Sopenharmony_ci	phydev->speed = SPEED_UNKNOWN;
126762306a36Sopenharmony_ci	phydev->asym_pause = 0;
126862306a36Sopenharmony_ci	phydev->pause = 0;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	/* YT8521 has two reg space (utp/fiber) for linkup with utp/fiber
127162306a36Sopenharmony_ci	 * respectively. but for utp/fiber combo mode, reg space should be
127262306a36Sopenharmony_ci	 * arbitrated based on media priority. by default, utp takes
127362306a36Sopenharmony_ci	 * priority. reg space should be properly set before read
127462306a36Sopenharmony_ci	 * YTPHY_SPECIFIC_STATUS_REG.
127562306a36Sopenharmony_ci	 */
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	page &= YT8521_RSSR_SPACE_MASK;
127862306a36Sopenharmony_ci	old_page = phy_select_page(phydev, page);
127962306a36Sopenharmony_ci	if (old_page < 0)
128062306a36Sopenharmony_ci		goto err_restore_page;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	/* Read YTPHY_SPECIFIC_STATUS_REG, which indicates the speed and duplex
128362306a36Sopenharmony_ci	 * of the PHY is actually using.
128462306a36Sopenharmony_ci	 */
128562306a36Sopenharmony_ci	ret = __phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG);
128662306a36Sopenharmony_ci	if (ret < 0)
128762306a36Sopenharmony_ci		goto err_restore_page;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	status = ret;
129062306a36Sopenharmony_ci	link = !!(status & YTPHY_SSR_LINK);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	/* When PHY is in fiber mode, speed transferred from 1000Mbps to
129362306a36Sopenharmony_ci	 * 100Mbps,there is not link down from YTPHY_SPECIFIC_STATUS_REG, so
129462306a36Sopenharmony_ci	 * we need check MII_BMSR to identify such case.
129562306a36Sopenharmony_ci	 */
129662306a36Sopenharmony_ci	if (page == YT8521_RSSR_FIBER_SPACE) {
129762306a36Sopenharmony_ci		ret = __phy_read(phydev, MII_BMSR);
129862306a36Sopenharmony_ci		if (ret < 0)
129962306a36Sopenharmony_ci			goto err_restore_page;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci		fiber_latch_val = ret;
130262306a36Sopenharmony_ci		ret = __phy_read(phydev, MII_BMSR);
130362306a36Sopenharmony_ci		if (ret < 0)
130462306a36Sopenharmony_ci			goto err_restore_page;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci		fiber_curr_val = ret;
130762306a36Sopenharmony_ci		if (link && fiber_latch_val != fiber_curr_val) {
130862306a36Sopenharmony_ci			link = 0;
130962306a36Sopenharmony_ci			phydev_info(phydev,
131062306a36Sopenharmony_ci				    "%s, fiber link down detect, latch = %04x, curr = %04x\n",
131162306a36Sopenharmony_ci				    __func__, fiber_latch_val, fiber_curr_val);
131262306a36Sopenharmony_ci		}
131362306a36Sopenharmony_ci	} else {
131462306a36Sopenharmony_ci		/* Read autonegotiation status */
131562306a36Sopenharmony_ci		ret = __phy_read(phydev, MII_BMSR);
131662306a36Sopenharmony_ci		if (ret < 0)
131762306a36Sopenharmony_ci			goto err_restore_page;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci		phydev->autoneg_complete = ret & BMSR_ANEGCOMPLETE ? 1 : 0;
132062306a36Sopenharmony_ci	}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	if (link) {
132362306a36Sopenharmony_ci		if (page == YT8521_RSSR_UTP_SPACE)
132462306a36Sopenharmony_ci			yt8521_adjust_status(phydev, status, true);
132562306a36Sopenharmony_ci		else
132662306a36Sopenharmony_ci			yt8521_adjust_status(phydev, status, false);
132762306a36Sopenharmony_ci	}
132862306a36Sopenharmony_ci	return phy_restore_page(phydev, old_page, link);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_cierr_restore_page:
133162306a36Sopenharmony_ci	return phy_restore_page(phydev, old_page, ret);
133262306a36Sopenharmony_ci}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci/**
133562306a36Sopenharmony_ci * yt8521_read_status() -  determines the negotiated speed and duplex
133662306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
133762306a36Sopenharmony_ci *
133862306a36Sopenharmony_ci * returns 0 or negative errno code
133962306a36Sopenharmony_ci */
134062306a36Sopenharmony_cistatic int yt8521_read_status(struct phy_device *phydev)
134162306a36Sopenharmony_ci{
134262306a36Sopenharmony_ci	struct yt8521_priv *priv = phydev->priv;
134362306a36Sopenharmony_ci	int link_fiber = 0;
134462306a36Sopenharmony_ci	int link_utp;
134562306a36Sopenharmony_ci	int link;
134662306a36Sopenharmony_ci	int ret;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
134962306a36Sopenharmony_ci		link = yt8521_read_status_paged(phydev, priv->reg_page);
135062306a36Sopenharmony_ci		if (link < 0)
135162306a36Sopenharmony_ci			return link;
135262306a36Sopenharmony_ci	} else {
135362306a36Sopenharmony_ci		/* when page is YT8521_RSSR_TO_BE_ARBITRATED, arbitration is
135462306a36Sopenharmony_ci		 * needed. by default, utp is higher priority.
135562306a36Sopenharmony_ci		 */
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci		link_utp = yt8521_read_status_paged(phydev,
135862306a36Sopenharmony_ci						    YT8521_RSSR_UTP_SPACE);
135962306a36Sopenharmony_ci		if (link_utp < 0)
136062306a36Sopenharmony_ci			return link_utp;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci		if (!link_utp) {
136362306a36Sopenharmony_ci			link_fiber = yt8521_read_status_paged(phydev,
136462306a36Sopenharmony_ci							      YT8521_RSSR_FIBER_SPACE);
136562306a36Sopenharmony_ci			if (link_fiber < 0)
136662306a36Sopenharmony_ci				return link_fiber;
136762306a36Sopenharmony_ci		}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci		link = link_utp || link_fiber;
137062306a36Sopenharmony_ci	}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	if (link) {
137362306a36Sopenharmony_ci		if (phydev->link == 0) {
137462306a36Sopenharmony_ci			/* arbitrate reg space based on linkup media type. */
137562306a36Sopenharmony_ci			if (priv->polling_mode == YT8521_MODE_POLL &&
137662306a36Sopenharmony_ci			    priv->reg_page == YT8521_RSSR_TO_BE_ARBITRATED) {
137762306a36Sopenharmony_ci				if (link_fiber)
137862306a36Sopenharmony_ci					priv->reg_page =
137962306a36Sopenharmony_ci						YT8521_RSSR_FIBER_SPACE;
138062306a36Sopenharmony_ci				else
138162306a36Sopenharmony_ci					priv->reg_page = YT8521_RSSR_UTP_SPACE;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci				ret = ytphy_write_ext_with_lock(phydev,
138462306a36Sopenharmony_ci								YT8521_REG_SPACE_SELECT_REG,
138562306a36Sopenharmony_ci								priv->reg_page);
138662306a36Sopenharmony_ci				if (ret < 0)
138762306a36Sopenharmony_ci					return ret;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci				phydev->port = link_fiber ? PORT_FIBRE : PORT_TP;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci				phydev_info(phydev, "%s, link up, media: %s\n",
139262306a36Sopenharmony_ci					    __func__,
139362306a36Sopenharmony_ci					    (phydev->port == PORT_TP) ?
139462306a36Sopenharmony_ci					    "UTP" : "Fiber");
139562306a36Sopenharmony_ci			}
139662306a36Sopenharmony_ci		}
139762306a36Sopenharmony_ci		phydev->link = 1;
139862306a36Sopenharmony_ci	} else {
139962306a36Sopenharmony_ci		if (phydev->link == 1) {
140062306a36Sopenharmony_ci			phydev_info(phydev, "%s, link down, media: %s\n",
140162306a36Sopenharmony_ci				    __func__, (phydev->port == PORT_TP) ?
140262306a36Sopenharmony_ci				    "UTP" : "Fiber");
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci			/* When in YT8521_MODE_POLL mode, need prepare for next
140562306a36Sopenharmony_ci			 * arbitration.
140662306a36Sopenharmony_ci			 */
140762306a36Sopenharmony_ci			if (priv->polling_mode == YT8521_MODE_POLL) {
140862306a36Sopenharmony_ci				priv->reg_page = YT8521_RSSR_TO_BE_ARBITRATED;
140962306a36Sopenharmony_ci				phydev->port = PORT_NONE;
141062306a36Sopenharmony_ci			}
141162306a36Sopenharmony_ci		}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci		phydev->link = 0;
141462306a36Sopenharmony_ci	}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	return 0;
141762306a36Sopenharmony_ci}
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci/**
142062306a36Sopenharmony_ci * yt8521_modify_bmcr_paged - bits modify a PHY's BMCR register of one page
142162306a36Sopenharmony_ci * @phydev: the phy_device struct
142262306a36Sopenharmony_ci * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to operate
142362306a36Sopenharmony_ci * @mask: bit mask of bits to clear
142462306a36Sopenharmony_ci * @set: bit mask of bits to set
142562306a36Sopenharmony_ci *
142662306a36Sopenharmony_ci * NOTE: Convenience function which allows a PHY's BMCR register to be
142762306a36Sopenharmony_ci * modified as new register value = (old register value & ~mask) | set.
142862306a36Sopenharmony_ci * YT8521 has two space (utp/fiber) and three mode (utp/fiber/poll), each space
142962306a36Sopenharmony_ci * has MII_BMCR. poll mode combines utp and faber,so need do both.
143062306a36Sopenharmony_ci * If it is reset, it will wait for completion.
143162306a36Sopenharmony_ci *
143262306a36Sopenharmony_ci * returns 0 or negative errno code
143362306a36Sopenharmony_ci */
143462306a36Sopenharmony_cistatic int yt8521_modify_bmcr_paged(struct phy_device *phydev, int page,
143562306a36Sopenharmony_ci				    u16 mask, u16 set)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	int max_cnt = 500; /* the max wait time of reset ~ 500 ms */
143862306a36Sopenharmony_ci	int old_page;
143962306a36Sopenharmony_ci	int ret = 0;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	old_page = phy_select_page(phydev, page & YT8521_RSSR_SPACE_MASK);
144262306a36Sopenharmony_ci	if (old_page < 0)
144362306a36Sopenharmony_ci		goto err_restore_page;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	ret = __phy_modify(phydev, MII_BMCR, mask, set);
144662306a36Sopenharmony_ci	if (ret < 0)
144762306a36Sopenharmony_ci		goto err_restore_page;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	/* If it is reset, need to wait for the reset to complete */
145062306a36Sopenharmony_ci	if (set == BMCR_RESET) {
145162306a36Sopenharmony_ci		while (max_cnt--) {
145262306a36Sopenharmony_ci			usleep_range(1000, 1100);
145362306a36Sopenharmony_ci			ret = __phy_read(phydev, MII_BMCR);
145462306a36Sopenharmony_ci			if (ret < 0)
145562306a36Sopenharmony_ci				goto err_restore_page;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci			if (!(ret & BMCR_RESET))
145862306a36Sopenharmony_ci				return phy_restore_page(phydev, old_page, 0);
145962306a36Sopenharmony_ci		}
146062306a36Sopenharmony_ci	}
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_cierr_restore_page:
146362306a36Sopenharmony_ci	return phy_restore_page(phydev, old_page, ret);
146462306a36Sopenharmony_ci}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci/**
146762306a36Sopenharmony_ci * yt8521_modify_utp_fiber_bmcr - bits modify a PHY's BMCR register
146862306a36Sopenharmony_ci * @phydev: the phy_device struct
146962306a36Sopenharmony_ci * @mask: bit mask of bits to clear
147062306a36Sopenharmony_ci * @set: bit mask of bits to set
147162306a36Sopenharmony_ci *
147262306a36Sopenharmony_ci * NOTE: Convenience function which allows a PHY's BMCR register to be
147362306a36Sopenharmony_ci * modified as new register value = (old register value & ~mask) | set.
147462306a36Sopenharmony_ci * YT8521 has two space (utp/fiber) and three mode (utp/fiber/poll), each space
147562306a36Sopenharmony_ci * has MII_BMCR. poll mode combines utp and faber,so need do both.
147662306a36Sopenharmony_ci *
147762306a36Sopenharmony_ci * returns 0 or negative errno code
147862306a36Sopenharmony_ci */
147962306a36Sopenharmony_cistatic int yt8521_modify_utp_fiber_bmcr(struct phy_device *phydev, u16 mask,
148062306a36Sopenharmony_ci					u16 set)
148162306a36Sopenharmony_ci{
148262306a36Sopenharmony_ci	struct yt8521_priv *priv = phydev->priv;
148362306a36Sopenharmony_ci	int ret;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
148662306a36Sopenharmony_ci		ret = yt8521_modify_bmcr_paged(phydev, priv->reg_page, mask,
148762306a36Sopenharmony_ci					       set);
148862306a36Sopenharmony_ci		if (ret < 0)
148962306a36Sopenharmony_ci			return ret;
149062306a36Sopenharmony_ci	} else {
149162306a36Sopenharmony_ci		ret = yt8521_modify_bmcr_paged(phydev, YT8521_RSSR_UTP_SPACE,
149262306a36Sopenharmony_ci					       mask, set);
149362306a36Sopenharmony_ci		if (ret < 0)
149462306a36Sopenharmony_ci			return ret;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci		ret = yt8521_modify_bmcr_paged(phydev, YT8521_RSSR_FIBER_SPACE,
149762306a36Sopenharmony_ci					       mask, set);
149862306a36Sopenharmony_ci		if (ret < 0)
149962306a36Sopenharmony_ci			return ret;
150062306a36Sopenharmony_ci	}
150162306a36Sopenharmony_ci	return 0;
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci/**
150562306a36Sopenharmony_ci * yt8521_soft_reset() - called to issue a PHY software reset
150662306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
150762306a36Sopenharmony_ci *
150862306a36Sopenharmony_ci * returns 0 or negative errno code
150962306a36Sopenharmony_ci */
151062306a36Sopenharmony_cistatic int yt8521_soft_reset(struct phy_device *phydev)
151162306a36Sopenharmony_ci{
151262306a36Sopenharmony_ci	return yt8521_modify_utp_fiber_bmcr(phydev, 0, BMCR_RESET);
151362306a36Sopenharmony_ci}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci/**
151662306a36Sopenharmony_ci * yt8521_suspend() - suspend the hardware
151762306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
151862306a36Sopenharmony_ci *
151962306a36Sopenharmony_ci * returns 0 or negative errno code
152062306a36Sopenharmony_ci */
152162306a36Sopenharmony_cistatic int yt8521_suspend(struct phy_device *phydev)
152262306a36Sopenharmony_ci{
152362306a36Sopenharmony_ci	int wol_config;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	/* YTPHY_WOL_CONFIG_REG is common ext reg */
152662306a36Sopenharmony_ci	wol_config = ytphy_read_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG);
152762306a36Sopenharmony_ci	if (wol_config < 0)
152862306a36Sopenharmony_ci		return wol_config;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	/* if wol enable, do nothing */
153162306a36Sopenharmony_ci	if (wol_config & YTPHY_WCR_ENABLE)
153262306a36Sopenharmony_ci		return 0;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	return yt8521_modify_utp_fiber_bmcr(phydev, 0, BMCR_PDOWN);
153562306a36Sopenharmony_ci}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci/**
153862306a36Sopenharmony_ci * yt8521_resume() - resume the hardware
153962306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
154062306a36Sopenharmony_ci *
154162306a36Sopenharmony_ci * returns 0 or negative errno code
154262306a36Sopenharmony_ci */
154362306a36Sopenharmony_cistatic int yt8521_resume(struct phy_device *phydev)
154462306a36Sopenharmony_ci{
154562306a36Sopenharmony_ci	int ret;
154662306a36Sopenharmony_ci	int wol_config;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	/* disable auto sleep */
154962306a36Sopenharmony_ci	ret = ytphy_modify_ext_with_lock(phydev,
155062306a36Sopenharmony_ci					 YT8521_EXTREG_SLEEP_CONTROL1_REG,
155162306a36Sopenharmony_ci					 YT8521_ESC1R_SLEEP_SW, 0);
155262306a36Sopenharmony_ci	if (ret < 0)
155362306a36Sopenharmony_ci		return ret;
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	wol_config = ytphy_read_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG);
155662306a36Sopenharmony_ci	if (wol_config < 0)
155762306a36Sopenharmony_ci		return wol_config;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	/* if wol enable, do nothing */
156062306a36Sopenharmony_ci	if (wol_config & YTPHY_WCR_ENABLE)
156162306a36Sopenharmony_ci		return 0;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	return yt8521_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0);
156462306a36Sopenharmony_ci}
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci/**
156762306a36Sopenharmony_ci * yt8521_config_init() - called to initialize the PHY
156862306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
156962306a36Sopenharmony_ci *
157062306a36Sopenharmony_ci * returns 0 or negative errno code
157162306a36Sopenharmony_ci */
157262306a36Sopenharmony_cistatic int yt8521_config_init(struct phy_device *phydev)
157362306a36Sopenharmony_ci{
157462306a36Sopenharmony_ci	struct device_node *node = phydev->mdio.dev.of_node;
157562306a36Sopenharmony_ci	int old_page;
157662306a36Sopenharmony_ci	int ret = 0;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
157962306a36Sopenharmony_ci	if (old_page < 0)
158062306a36Sopenharmony_ci		goto err_restore_page;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	/* set rgmii delay mode */
158362306a36Sopenharmony_ci	if (phydev->interface != PHY_INTERFACE_MODE_SGMII) {
158462306a36Sopenharmony_ci		ret = ytphy_rgmii_clk_delay_config(phydev);
158562306a36Sopenharmony_ci		if (ret < 0)
158662306a36Sopenharmony_ci			goto err_restore_page;
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	if (of_property_read_bool(node, "motorcomm,auto-sleep-disabled")) {
159062306a36Sopenharmony_ci		/* disable auto sleep */
159162306a36Sopenharmony_ci		ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG,
159262306a36Sopenharmony_ci				       YT8521_ESC1R_SLEEP_SW, 0);
159362306a36Sopenharmony_ci		if (ret < 0)
159462306a36Sopenharmony_ci			goto err_restore_page;
159562306a36Sopenharmony_ci	}
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	if (of_property_read_bool(node, "motorcomm,keep-pll-enabled")) {
159862306a36Sopenharmony_ci		/* enable RXC clock when no wire plug */
159962306a36Sopenharmony_ci		ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG,
160062306a36Sopenharmony_ci				       YT8521_CGR_RX_CLK_EN, 0);
160162306a36Sopenharmony_ci		if (ret < 0)
160262306a36Sopenharmony_ci			goto err_restore_page;
160362306a36Sopenharmony_ci	}
160462306a36Sopenharmony_cierr_restore_page:
160562306a36Sopenharmony_ci	return phy_restore_page(phydev, old_page, ret);
160662306a36Sopenharmony_ci}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_cistatic int yt8531_config_init(struct phy_device *phydev)
160962306a36Sopenharmony_ci{
161062306a36Sopenharmony_ci	struct device_node *node = phydev->mdio.dev.of_node;
161162306a36Sopenharmony_ci	int ret;
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	ret = ytphy_rgmii_clk_delay_config_with_lock(phydev);
161462306a36Sopenharmony_ci	if (ret < 0)
161562306a36Sopenharmony_ci		return ret;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	if (of_property_read_bool(node, "motorcomm,auto-sleep-disabled")) {
161862306a36Sopenharmony_ci		/* disable auto sleep */
161962306a36Sopenharmony_ci		ret = ytphy_modify_ext_with_lock(phydev,
162062306a36Sopenharmony_ci						 YT8521_EXTREG_SLEEP_CONTROL1_REG,
162162306a36Sopenharmony_ci						 YT8521_ESC1R_SLEEP_SW, 0);
162262306a36Sopenharmony_ci		if (ret < 0)
162362306a36Sopenharmony_ci			return ret;
162462306a36Sopenharmony_ci	}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	if (of_property_read_bool(node, "motorcomm,keep-pll-enabled")) {
162762306a36Sopenharmony_ci		/* enable RXC clock when no wire plug */
162862306a36Sopenharmony_ci		ret = ytphy_modify_ext_with_lock(phydev,
162962306a36Sopenharmony_ci						 YT8521_CLOCK_GATING_REG,
163062306a36Sopenharmony_ci						 YT8521_CGR_RX_CLK_EN, 0);
163162306a36Sopenharmony_ci		if (ret < 0)
163262306a36Sopenharmony_ci			return ret;
163362306a36Sopenharmony_ci	}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	ret = yt8531_set_ds(phydev);
163662306a36Sopenharmony_ci	if (ret < 0)
163762306a36Sopenharmony_ci		return ret;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	return 0;
164062306a36Sopenharmony_ci}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci/**
164362306a36Sopenharmony_ci * yt8531_link_change_notify() - Adjust the tx clock direction according to
164462306a36Sopenharmony_ci * the current speed and dts config.
164562306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
164662306a36Sopenharmony_ci *
164762306a36Sopenharmony_ci * NOTE: This function is only used to adapt to VF2 with JH7110 SoC. Please
164862306a36Sopenharmony_ci * keep "motorcomm,tx-clk-adj-enabled" not exist in dts when the soc is not
164962306a36Sopenharmony_ci * JH7110.
165062306a36Sopenharmony_ci */
165162306a36Sopenharmony_cistatic void yt8531_link_change_notify(struct phy_device *phydev)
165262306a36Sopenharmony_ci{
165362306a36Sopenharmony_ci	struct device_node *node = phydev->mdio.dev.of_node;
165462306a36Sopenharmony_ci	bool tx_clk_1000_inverted = false;
165562306a36Sopenharmony_ci	bool tx_clk_100_inverted = false;
165662306a36Sopenharmony_ci	bool tx_clk_10_inverted = false;
165762306a36Sopenharmony_ci	bool tx_clk_adj_enabled = false;
165862306a36Sopenharmony_ci	u16 val = 0;
165962306a36Sopenharmony_ci	int ret;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	if (of_property_read_bool(node, "motorcomm,tx-clk-adj-enabled"))
166262306a36Sopenharmony_ci		tx_clk_adj_enabled = true;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	if (!tx_clk_adj_enabled)
166562306a36Sopenharmony_ci		return;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	if (of_property_read_bool(node, "motorcomm,tx-clk-10-inverted"))
166862306a36Sopenharmony_ci		tx_clk_10_inverted = true;
166962306a36Sopenharmony_ci	if (of_property_read_bool(node, "motorcomm,tx-clk-100-inverted"))
167062306a36Sopenharmony_ci		tx_clk_100_inverted = true;
167162306a36Sopenharmony_ci	if (of_property_read_bool(node, "motorcomm,tx-clk-1000-inverted"))
167262306a36Sopenharmony_ci		tx_clk_1000_inverted = true;
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	if (phydev->speed < 0)
167562306a36Sopenharmony_ci		return;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	switch (phydev->speed) {
167862306a36Sopenharmony_ci	case SPEED_1000:
167962306a36Sopenharmony_ci		if (tx_clk_1000_inverted)
168062306a36Sopenharmony_ci			val = YT8521_RC1R_TX_CLK_SEL_INVERTED;
168162306a36Sopenharmony_ci		break;
168262306a36Sopenharmony_ci	case SPEED_100:
168362306a36Sopenharmony_ci		if (tx_clk_100_inverted)
168462306a36Sopenharmony_ci			val = YT8521_RC1R_TX_CLK_SEL_INVERTED;
168562306a36Sopenharmony_ci		break;
168662306a36Sopenharmony_ci	case SPEED_10:
168762306a36Sopenharmony_ci		if (tx_clk_10_inverted)
168862306a36Sopenharmony_ci			val = YT8521_RC1R_TX_CLK_SEL_INVERTED;
168962306a36Sopenharmony_ci		break;
169062306a36Sopenharmony_ci	default:
169162306a36Sopenharmony_ci		return;
169262306a36Sopenharmony_ci	}
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	ret = ytphy_modify_ext_with_lock(phydev, YT8521_RGMII_CONFIG1_REG,
169562306a36Sopenharmony_ci					 YT8521_RC1R_TX_CLK_SEL_INVERTED, val);
169662306a36Sopenharmony_ci	if (ret < 0)
169762306a36Sopenharmony_ci		phydev_warn(phydev, "Modify TX_CLK_SEL err:%d\n", ret);
169862306a36Sopenharmony_ci}
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci/**
170162306a36Sopenharmony_ci * yt8521_prepare_fiber_features() -  A small helper function that setup
170262306a36Sopenharmony_ci * fiber's features.
170362306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
170462306a36Sopenharmony_ci * @dst: a pointer to store fiber's features
170562306a36Sopenharmony_ci */
170662306a36Sopenharmony_cistatic void yt8521_prepare_fiber_features(struct phy_device *phydev,
170762306a36Sopenharmony_ci					  unsigned long *dst)
170862306a36Sopenharmony_ci{
170962306a36Sopenharmony_ci	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, dst);
171062306a36Sopenharmony_ci	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, dst);
171162306a36Sopenharmony_ci	linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, dst);
171262306a36Sopenharmony_ci	linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, dst);
171362306a36Sopenharmony_ci}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci/**
171662306a36Sopenharmony_ci * yt8521_fiber_setup_forced - configures/forces speed from @phydev
171762306a36Sopenharmony_ci * @phydev: target phy_device struct
171862306a36Sopenharmony_ci *
171962306a36Sopenharmony_ci * NOTE:The caller must have taken the MDIO bus lock.
172062306a36Sopenharmony_ci *
172162306a36Sopenharmony_ci * returns 0 or negative errno code
172262306a36Sopenharmony_ci */
172362306a36Sopenharmony_cistatic int yt8521_fiber_setup_forced(struct phy_device *phydev)
172462306a36Sopenharmony_ci{
172562306a36Sopenharmony_ci	u16 val;
172662306a36Sopenharmony_ci	int ret;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	if (phydev->speed == SPEED_1000)
172962306a36Sopenharmony_ci		val = YTPHY_MCR_FIBER_1000BX;
173062306a36Sopenharmony_ci	else if (phydev->speed == SPEED_100)
173162306a36Sopenharmony_ci		val = YTPHY_MCR_FIBER_100FX;
173262306a36Sopenharmony_ci	else
173362306a36Sopenharmony_ci		return -EINVAL;
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	ret =  __phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);
173662306a36Sopenharmony_ci	if (ret < 0)
173762306a36Sopenharmony_ci		return ret;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	/* disable Fiber auto sensing */
174062306a36Sopenharmony_ci	ret =  ytphy_modify_ext(phydev, YT8521_LINK_TIMER_CFG2_REG,
174162306a36Sopenharmony_ci				YT8521_LTCR_EN_AUTOSEN, 0);
174262306a36Sopenharmony_ci	if (ret < 0)
174362306a36Sopenharmony_ci		return ret;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	ret =  ytphy_modify_ext(phydev, YTPHY_MISC_CONFIG_REG,
174662306a36Sopenharmony_ci				YTPHY_MCR_FIBER_SPEED_MASK, val);
174762306a36Sopenharmony_ci	if (ret < 0)
174862306a36Sopenharmony_ci		return ret;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	return ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG,
175162306a36Sopenharmony_ci				YT8521_CCR_SW_RST, 0);
175262306a36Sopenharmony_ci}
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci/**
175562306a36Sopenharmony_ci * ytphy_check_and_restart_aneg - Enable and restart auto-negotiation
175662306a36Sopenharmony_ci * @phydev: target phy_device struct
175762306a36Sopenharmony_ci * @restart: whether aneg restart is requested
175862306a36Sopenharmony_ci *
175962306a36Sopenharmony_ci * NOTE:The caller must have taken the MDIO bus lock.
176062306a36Sopenharmony_ci *
176162306a36Sopenharmony_ci * returns 0 or negative errno code
176262306a36Sopenharmony_ci */
176362306a36Sopenharmony_cistatic int ytphy_check_and_restart_aneg(struct phy_device *phydev, bool restart)
176462306a36Sopenharmony_ci{
176562306a36Sopenharmony_ci	int ret;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	if (!restart) {
176862306a36Sopenharmony_ci		/* Advertisement hasn't changed, but maybe aneg was never on to
176962306a36Sopenharmony_ci		 * begin with?  Or maybe phy was isolated?
177062306a36Sopenharmony_ci		 */
177162306a36Sopenharmony_ci		ret = __phy_read(phydev, MII_BMCR);
177262306a36Sopenharmony_ci		if (ret < 0)
177362306a36Sopenharmony_ci			return ret;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci		if (!(ret & BMCR_ANENABLE) || (ret & BMCR_ISOLATE))
177662306a36Sopenharmony_ci			restart = true;
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci	/* Enable and Restart Autonegotiation
177962306a36Sopenharmony_ci	 * Don't isolate the PHY if we're negotiating
178062306a36Sopenharmony_ci	 */
178162306a36Sopenharmony_ci	if (restart)
178262306a36Sopenharmony_ci		return __phy_modify(phydev, MII_BMCR, BMCR_ISOLATE,
178362306a36Sopenharmony_ci				    BMCR_ANENABLE | BMCR_ANRESTART);
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	return 0;
178662306a36Sopenharmony_ci}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci/**
178962306a36Sopenharmony_ci * yt8521_fiber_config_aneg - restart auto-negotiation or write
179062306a36Sopenharmony_ci * YTPHY_MISC_CONFIG_REG.
179162306a36Sopenharmony_ci * @phydev: target phy_device struct
179262306a36Sopenharmony_ci *
179362306a36Sopenharmony_ci * NOTE:The caller must have taken the MDIO bus lock.
179462306a36Sopenharmony_ci *
179562306a36Sopenharmony_ci * returns 0 or negative errno code
179662306a36Sopenharmony_ci */
179762306a36Sopenharmony_cistatic int yt8521_fiber_config_aneg(struct phy_device *phydev)
179862306a36Sopenharmony_ci{
179962306a36Sopenharmony_ci	int err, changed = 0;
180062306a36Sopenharmony_ci	int bmcr;
180162306a36Sopenharmony_ci	u16 adv;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	if (phydev->autoneg != AUTONEG_ENABLE)
180462306a36Sopenharmony_ci		return yt8521_fiber_setup_forced(phydev);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	/* enable Fiber auto sensing */
180762306a36Sopenharmony_ci	err =  ytphy_modify_ext(phydev, YT8521_LINK_TIMER_CFG2_REG,
180862306a36Sopenharmony_ci				0, YT8521_LTCR_EN_AUTOSEN);
180962306a36Sopenharmony_ci	if (err < 0)
181062306a36Sopenharmony_ci		return err;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	err =  ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG,
181362306a36Sopenharmony_ci				YT8521_CCR_SW_RST, 0);
181462306a36Sopenharmony_ci	if (err < 0)
181562306a36Sopenharmony_ci		return err;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	bmcr = __phy_read(phydev, MII_BMCR);
181862306a36Sopenharmony_ci	if (bmcr < 0)
181962306a36Sopenharmony_ci		return bmcr;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	/* When it is coming from fiber forced mode, add bmcr power down
182262306a36Sopenharmony_ci	 * and power up to let aneg work fine.
182362306a36Sopenharmony_ci	 */
182462306a36Sopenharmony_ci	if (!(bmcr & BMCR_ANENABLE)) {
182562306a36Sopenharmony_ci		__phy_modify(phydev, MII_BMCR, 0, BMCR_PDOWN);
182662306a36Sopenharmony_ci		usleep_range(1000, 1100);
182762306a36Sopenharmony_ci		__phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);
182862306a36Sopenharmony_ci	}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	adv = linkmode_adv_to_mii_adv_x(phydev->advertising,
183162306a36Sopenharmony_ci					ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	/* Setup fiber advertisement */
183462306a36Sopenharmony_ci	err = __phy_modify_changed(phydev, MII_ADVERTISE,
183562306a36Sopenharmony_ci				   ADVERTISE_1000XHALF | ADVERTISE_1000XFULL |
183662306a36Sopenharmony_ci				   ADVERTISE_1000XPAUSE |
183762306a36Sopenharmony_ci				   ADVERTISE_1000XPSE_ASYM,
183862306a36Sopenharmony_ci				   adv);
183962306a36Sopenharmony_ci	if (err < 0)
184062306a36Sopenharmony_ci		return err;
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	if (err > 0)
184362306a36Sopenharmony_ci		changed = 1;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	return ytphy_check_and_restart_aneg(phydev, changed);
184662306a36Sopenharmony_ci}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci/**
184962306a36Sopenharmony_ci * ytphy_setup_master_slave
185062306a36Sopenharmony_ci * @phydev: target phy_device struct
185162306a36Sopenharmony_ci *
185262306a36Sopenharmony_ci * NOTE: The caller must have taken the MDIO bus lock.
185362306a36Sopenharmony_ci *
185462306a36Sopenharmony_ci * returns 0 or negative errno code
185562306a36Sopenharmony_ci */
185662306a36Sopenharmony_cistatic int ytphy_setup_master_slave(struct phy_device *phydev)
185762306a36Sopenharmony_ci{
185862306a36Sopenharmony_ci	u16 ctl = 0;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	if (!phydev->is_gigabit_capable)
186162306a36Sopenharmony_ci		return 0;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	switch (phydev->master_slave_set) {
186462306a36Sopenharmony_ci	case MASTER_SLAVE_CFG_MASTER_PREFERRED:
186562306a36Sopenharmony_ci		ctl |= CTL1000_PREFER_MASTER;
186662306a36Sopenharmony_ci		break;
186762306a36Sopenharmony_ci	case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
186862306a36Sopenharmony_ci		break;
186962306a36Sopenharmony_ci	case MASTER_SLAVE_CFG_MASTER_FORCE:
187062306a36Sopenharmony_ci		ctl |= CTL1000_AS_MASTER;
187162306a36Sopenharmony_ci		fallthrough;
187262306a36Sopenharmony_ci	case MASTER_SLAVE_CFG_SLAVE_FORCE:
187362306a36Sopenharmony_ci		ctl |= CTL1000_ENABLE_MASTER;
187462306a36Sopenharmony_ci		break;
187562306a36Sopenharmony_ci	case MASTER_SLAVE_CFG_UNKNOWN:
187662306a36Sopenharmony_ci	case MASTER_SLAVE_CFG_UNSUPPORTED:
187762306a36Sopenharmony_ci		return 0;
187862306a36Sopenharmony_ci	default:
187962306a36Sopenharmony_ci		phydev_warn(phydev, "Unsupported Master/Slave mode\n");
188062306a36Sopenharmony_ci		return -EOPNOTSUPP;
188162306a36Sopenharmony_ci	}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	return __phy_modify_changed(phydev, MII_CTRL1000,
188462306a36Sopenharmony_ci				    (CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER |
188562306a36Sopenharmony_ci				    CTL1000_PREFER_MASTER), ctl);
188662306a36Sopenharmony_ci}
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci/**
188962306a36Sopenharmony_ci * ytphy_utp_config_advert - sanitize and advertise auto-negotiation parameters
189062306a36Sopenharmony_ci * @phydev: target phy_device struct
189162306a36Sopenharmony_ci *
189262306a36Sopenharmony_ci * NOTE: Writes MII_ADVERTISE with the appropriate values,
189362306a36Sopenharmony_ci * after sanitizing the values to make sure we only advertise
189462306a36Sopenharmony_ci * what is supported.  Returns < 0 on error, 0 if the PHY's advertisement
189562306a36Sopenharmony_ci * hasn't changed, and > 0 if it has changed.
189662306a36Sopenharmony_ci * The caller must have taken the MDIO bus lock.
189762306a36Sopenharmony_ci *
189862306a36Sopenharmony_ci * returns 0 or negative errno code
189962306a36Sopenharmony_ci */
190062306a36Sopenharmony_cistatic int ytphy_utp_config_advert(struct phy_device *phydev)
190162306a36Sopenharmony_ci{
190262306a36Sopenharmony_ci	int err, bmsr, changed = 0;
190362306a36Sopenharmony_ci	u32 adv;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	/* Only allow advertising what this PHY supports */
190662306a36Sopenharmony_ci	linkmode_and(phydev->advertising, phydev->advertising,
190762306a36Sopenharmony_ci		     phydev->supported);
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	adv = linkmode_adv_to_mii_adv_t(phydev->advertising);
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	/* Setup standard advertisement */
191262306a36Sopenharmony_ci	err = __phy_modify_changed(phydev, MII_ADVERTISE,
191362306a36Sopenharmony_ci				   ADVERTISE_ALL | ADVERTISE_100BASE4 |
191462306a36Sopenharmony_ci				   ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
191562306a36Sopenharmony_ci				   adv);
191662306a36Sopenharmony_ci	if (err < 0)
191762306a36Sopenharmony_ci		return err;
191862306a36Sopenharmony_ci	if (err > 0)
191962306a36Sopenharmony_ci		changed = 1;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	bmsr = __phy_read(phydev, MII_BMSR);
192262306a36Sopenharmony_ci	if (bmsr < 0)
192362306a36Sopenharmony_ci		return bmsr;
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	/* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
192662306a36Sopenharmony_ci	 * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
192762306a36Sopenharmony_ci	 * logical 1.
192862306a36Sopenharmony_ci	 */
192962306a36Sopenharmony_ci	if (!(bmsr & BMSR_ESTATEN))
193062306a36Sopenharmony_ci		return changed;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	err = __phy_modify_changed(phydev, MII_CTRL1000,
193562306a36Sopenharmony_ci				   ADVERTISE_1000FULL | ADVERTISE_1000HALF,
193662306a36Sopenharmony_ci				   adv);
193762306a36Sopenharmony_ci	if (err < 0)
193862306a36Sopenharmony_ci		return err;
193962306a36Sopenharmony_ci	if (err > 0)
194062306a36Sopenharmony_ci		changed = 1;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	return changed;
194362306a36Sopenharmony_ci}
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci/**
194662306a36Sopenharmony_ci * ytphy_utp_config_aneg - restart auto-negotiation or write BMCR
194762306a36Sopenharmony_ci * @phydev: target phy_device struct
194862306a36Sopenharmony_ci * @changed: whether autoneg is requested
194962306a36Sopenharmony_ci *
195062306a36Sopenharmony_ci * NOTE: If auto-negotiation is enabled, we configure the
195162306a36Sopenharmony_ci * advertising, and then restart auto-negotiation.  If it is not
195262306a36Sopenharmony_ci * enabled, then we write the BMCR.
195362306a36Sopenharmony_ci * The caller must have taken the MDIO bus lock.
195462306a36Sopenharmony_ci *
195562306a36Sopenharmony_ci * returns 0 or negative errno code
195662306a36Sopenharmony_ci */
195762306a36Sopenharmony_cistatic int ytphy_utp_config_aneg(struct phy_device *phydev, bool changed)
195862306a36Sopenharmony_ci{
195962306a36Sopenharmony_ci	int err;
196062306a36Sopenharmony_ci	u16 ctl;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	err = ytphy_setup_master_slave(phydev);
196362306a36Sopenharmony_ci	if (err < 0)
196462306a36Sopenharmony_ci		return err;
196562306a36Sopenharmony_ci	else if (err)
196662306a36Sopenharmony_ci		changed = true;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	if (phydev->autoneg != AUTONEG_ENABLE) {
196962306a36Sopenharmony_ci		/* configures/forces speed/duplex from @phydev */
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci		ctl = mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci		return __phy_modify(phydev, MII_BMCR, ~(BMCR_LOOPBACK |
197462306a36Sopenharmony_ci				    BMCR_ISOLATE | BMCR_PDOWN), ctl);
197562306a36Sopenharmony_ci	}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	err = ytphy_utp_config_advert(phydev);
197862306a36Sopenharmony_ci	if (err < 0) /* error */
197962306a36Sopenharmony_ci		return err;
198062306a36Sopenharmony_ci	else if (err)
198162306a36Sopenharmony_ci		changed = true;
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	return ytphy_check_and_restart_aneg(phydev, changed);
198462306a36Sopenharmony_ci}
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci/**
198762306a36Sopenharmony_ci * yt8521_config_aneg_paged() - switch reg space then call genphy_config_aneg
198862306a36Sopenharmony_ci * of one page
198962306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
199062306a36Sopenharmony_ci * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to
199162306a36Sopenharmony_ci * operate.
199262306a36Sopenharmony_ci *
199362306a36Sopenharmony_ci * returns 0 or negative errno code
199462306a36Sopenharmony_ci */
199562306a36Sopenharmony_cistatic int yt8521_config_aneg_paged(struct phy_device *phydev, int page)
199662306a36Sopenharmony_ci{
199762306a36Sopenharmony_ci	__ETHTOOL_DECLARE_LINK_MODE_MASK(fiber_supported);
199862306a36Sopenharmony_ci	struct yt8521_priv *priv = phydev->priv;
199962306a36Sopenharmony_ci	int old_page;
200062306a36Sopenharmony_ci	int ret = 0;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	page &= YT8521_RSSR_SPACE_MASK;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	old_page = phy_select_page(phydev, page);
200562306a36Sopenharmony_ci	if (old_page < 0)
200662306a36Sopenharmony_ci		goto err_restore_page;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	/* If reg_page is YT8521_RSSR_TO_BE_ARBITRATED,
200962306a36Sopenharmony_ci	 * phydev->advertising should be updated.
201062306a36Sopenharmony_ci	 */
201162306a36Sopenharmony_ci	if (priv->reg_page == YT8521_RSSR_TO_BE_ARBITRATED) {
201262306a36Sopenharmony_ci		linkmode_zero(fiber_supported);
201362306a36Sopenharmony_ci		yt8521_prepare_fiber_features(phydev, fiber_supported);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci		/* prepare fiber_supported, then setup advertising. */
201662306a36Sopenharmony_ci		if (page == YT8521_RSSR_FIBER_SPACE) {
201762306a36Sopenharmony_ci			linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
201862306a36Sopenharmony_ci					 fiber_supported);
201962306a36Sopenharmony_ci			linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
202062306a36Sopenharmony_ci					 fiber_supported);
202162306a36Sopenharmony_ci			linkmode_and(phydev->advertising,
202262306a36Sopenharmony_ci				     priv->combo_advertising, fiber_supported);
202362306a36Sopenharmony_ci		} else {
202462306a36Sopenharmony_ci			/* ETHTOOL_LINK_MODE_Autoneg_BIT is also used in utp */
202562306a36Sopenharmony_ci			linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
202662306a36Sopenharmony_ci					   fiber_supported);
202762306a36Sopenharmony_ci			linkmode_andnot(phydev->advertising,
202862306a36Sopenharmony_ci					priv->combo_advertising,
202962306a36Sopenharmony_ci					fiber_supported);
203062306a36Sopenharmony_ci		}
203162306a36Sopenharmony_ci	}
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	if (page == YT8521_RSSR_FIBER_SPACE)
203462306a36Sopenharmony_ci		ret = yt8521_fiber_config_aneg(phydev);
203562306a36Sopenharmony_ci	else
203662306a36Sopenharmony_ci		ret = ytphy_utp_config_aneg(phydev, false);
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_cierr_restore_page:
203962306a36Sopenharmony_ci	return phy_restore_page(phydev, old_page, ret);
204062306a36Sopenharmony_ci}
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci/**
204362306a36Sopenharmony_ci * yt8521_config_aneg() - change reg space then call yt8521_config_aneg_paged
204462306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
204562306a36Sopenharmony_ci *
204662306a36Sopenharmony_ci * returns 0 or negative errno code
204762306a36Sopenharmony_ci */
204862306a36Sopenharmony_cistatic int yt8521_config_aneg(struct phy_device *phydev)
204962306a36Sopenharmony_ci{
205062306a36Sopenharmony_ci	struct yt8521_priv *priv = phydev->priv;
205162306a36Sopenharmony_ci	int ret;
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
205462306a36Sopenharmony_ci		ret = yt8521_config_aneg_paged(phydev, priv->reg_page);
205562306a36Sopenharmony_ci		if (ret < 0)
205662306a36Sopenharmony_ci			return ret;
205762306a36Sopenharmony_ci	} else {
205862306a36Sopenharmony_ci		/* If reg_page is YT8521_RSSR_TO_BE_ARBITRATED,
205962306a36Sopenharmony_ci		 * phydev->advertising need to be saved at first run.
206062306a36Sopenharmony_ci		 * Because it contains the advertising which supported by both
206162306a36Sopenharmony_ci		 * mac and yt8521(utp and fiber).
206262306a36Sopenharmony_ci		 */
206362306a36Sopenharmony_ci		if (linkmode_empty(priv->combo_advertising)) {
206462306a36Sopenharmony_ci			linkmode_copy(priv->combo_advertising,
206562306a36Sopenharmony_ci				      phydev->advertising);
206662306a36Sopenharmony_ci		}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci		ret = yt8521_config_aneg_paged(phydev, YT8521_RSSR_UTP_SPACE);
206962306a36Sopenharmony_ci		if (ret < 0)
207062306a36Sopenharmony_ci			return ret;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci		ret = yt8521_config_aneg_paged(phydev, YT8521_RSSR_FIBER_SPACE);
207362306a36Sopenharmony_ci		if (ret < 0)
207462306a36Sopenharmony_ci			return ret;
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci		/* we don't known which will be link, so restore
207762306a36Sopenharmony_ci		 * phydev->advertising as default value.
207862306a36Sopenharmony_ci		 */
207962306a36Sopenharmony_ci		linkmode_copy(phydev->advertising, priv->combo_advertising);
208062306a36Sopenharmony_ci	}
208162306a36Sopenharmony_ci	return 0;
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci/**
208562306a36Sopenharmony_ci * yt8521_aneg_done_paged() - determines the auto negotiation result of one
208662306a36Sopenharmony_ci * page.
208762306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
208862306a36Sopenharmony_ci * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to
208962306a36Sopenharmony_ci * operate.
209062306a36Sopenharmony_ci *
209162306a36Sopenharmony_ci * returns 0(no link)or 1(fiber or utp link) or negative errno code
209262306a36Sopenharmony_ci */
209362306a36Sopenharmony_cistatic int yt8521_aneg_done_paged(struct phy_device *phydev, int page)
209462306a36Sopenharmony_ci{
209562306a36Sopenharmony_ci	int old_page;
209662306a36Sopenharmony_ci	int ret = 0;
209762306a36Sopenharmony_ci	int link;
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	old_page = phy_select_page(phydev, page & YT8521_RSSR_SPACE_MASK);
210062306a36Sopenharmony_ci	if (old_page < 0)
210162306a36Sopenharmony_ci		goto err_restore_page;
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	ret = __phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG);
210462306a36Sopenharmony_ci	if (ret < 0)
210562306a36Sopenharmony_ci		goto err_restore_page;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	link = !!(ret & YTPHY_SSR_LINK);
210862306a36Sopenharmony_ci	ret = link;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_cierr_restore_page:
211162306a36Sopenharmony_ci	return phy_restore_page(phydev, old_page, ret);
211262306a36Sopenharmony_ci}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci/**
211562306a36Sopenharmony_ci * yt8521_aneg_done() - determines the auto negotiation result
211662306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
211762306a36Sopenharmony_ci *
211862306a36Sopenharmony_ci * returns 0(no link)or 1(fiber or utp link) or negative errno code
211962306a36Sopenharmony_ci */
212062306a36Sopenharmony_cistatic int yt8521_aneg_done(struct phy_device *phydev)
212162306a36Sopenharmony_ci{
212262306a36Sopenharmony_ci	struct yt8521_priv *priv = phydev->priv;
212362306a36Sopenharmony_ci	int link_fiber = 0;
212462306a36Sopenharmony_ci	int link_utp;
212562306a36Sopenharmony_ci	int link;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
212862306a36Sopenharmony_ci		link = yt8521_aneg_done_paged(phydev, priv->reg_page);
212962306a36Sopenharmony_ci	} else {
213062306a36Sopenharmony_ci		link_utp = yt8521_aneg_done_paged(phydev,
213162306a36Sopenharmony_ci						  YT8521_RSSR_UTP_SPACE);
213262306a36Sopenharmony_ci		if (link_utp < 0)
213362306a36Sopenharmony_ci			return link_utp;
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci		if (!link_utp) {
213662306a36Sopenharmony_ci			link_fiber = yt8521_aneg_done_paged(phydev,
213762306a36Sopenharmony_ci							    YT8521_RSSR_FIBER_SPACE);
213862306a36Sopenharmony_ci			if (link_fiber < 0)
213962306a36Sopenharmony_ci				return link_fiber;
214062306a36Sopenharmony_ci		}
214162306a36Sopenharmony_ci		link = link_fiber || link_utp;
214262306a36Sopenharmony_ci		phydev_info(phydev, "%s, link_fiber: %d, link_utp: %d\n",
214362306a36Sopenharmony_ci			    __func__, link_fiber, link_utp);
214462306a36Sopenharmony_ci	}
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	return link;
214762306a36Sopenharmony_ci}
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci/**
215062306a36Sopenharmony_ci * ytphy_utp_read_abilities - read PHY abilities from Clause 22 registers
215162306a36Sopenharmony_ci * @phydev: target phy_device struct
215262306a36Sopenharmony_ci *
215362306a36Sopenharmony_ci * NOTE: Reads the PHY's abilities and populates
215462306a36Sopenharmony_ci * phydev->supported accordingly.
215562306a36Sopenharmony_ci * The caller must have taken the MDIO bus lock.
215662306a36Sopenharmony_ci *
215762306a36Sopenharmony_ci * returns 0 or negative errno code
215862306a36Sopenharmony_ci */
215962306a36Sopenharmony_cistatic int ytphy_utp_read_abilities(struct phy_device *phydev)
216062306a36Sopenharmony_ci{
216162306a36Sopenharmony_ci	int val;
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	linkmode_set_bit_array(phy_basic_ports_array,
216462306a36Sopenharmony_ci			       ARRAY_SIZE(phy_basic_ports_array),
216562306a36Sopenharmony_ci			       phydev->supported);
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	val = __phy_read(phydev, MII_BMSR);
216862306a36Sopenharmony_ci	if (val < 0)
216962306a36Sopenharmony_ci		return val;
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported,
217262306a36Sopenharmony_ci			 val & BMSR_ANEGCAPABLE);
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, phydev->supported,
217562306a36Sopenharmony_ci			 val & BMSR_100FULL);
217662306a36Sopenharmony_ci	linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, phydev->supported,
217762306a36Sopenharmony_ci			 val & BMSR_100HALF);
217862306a36Sopenharmony_ci	linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, phydev->supported,
217962306a36Sopenharmony_ci			 val & BMSR_10FULL);
218062306a36Sopenharmony_ci	linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, phydev->supported,
218162306a36Sopenharmony_ci			 val & BMSR_10HALF);
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	if (val & BMSR_ESTATEN) {
218462306a36Sopenharmony_ci		val = __phy_read(phydev, MII_ESTATUS);
218562306a36Sopenharmony_ci		if (val < 0)
218662306a36Sopenharmony_ci			return val;
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci		linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
218962306a36Sopenharmony_ci				 phydev->supported, val & ESTATUS_1000_TFULL);
219062306a36Sopenharmony_ci		linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
219162306a36Sopenharmony_ci				 phydev->supported, val & ESTATUS_1000_THALF);
219262306a36Sopenharmony_ci		linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
219362306a36Sopenharmony_ci				 phydev->supported, val & ESTATUS_1000_XFULL);
219462306a36Sopenharmony_ci	}
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	return 0;
219762306a36Sopenharmony_ci}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci/**
220062306a36Sopenharmony_ci * yt8521_get_features_paged() -  read supported link modes for one page
220162306a36Sopenharmony_ci * @phydev: a pointer to a &struct phy_device
220262306a36Sopenharmony_ci * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to
220362306a36Sopenharmony_ci * operate.
220462306a36Sopenharmony_ci *
220562306a36Sopenharmony_ci * returns 0 or negative errno code
220662306a36Sopenharmony_ci */
220762306a36Sopenharmony_cistatic int yt8521_get_features_paged(struct phy_device *phydev, int page)
220862306a36Sopenharmony_ci{
220962306a36Sopenharmony_ci	int old_page;
221062306a36Sopenharmony_ci	int ret = 0;
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	page &= YT8521_RSSR_SPACE_MASK;
221362306a36Sopenharmony_ci	old_page = phy_select_page(phydev, page);
221462306a36Sopenharmony_ci	if (old_page < 0)
221562306a36Sopenharmony_ci		goto err_restore_page;
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	if (page == YT8521_RSSR_FIBER_SPACE) {
221862306a36Sopenharmony_ci		linkmode_zero(phydev->supported);
221962306a36Sopenharmony_ci		yt8521_prepare_fiber_features(phydev, phydev->supported);
222062306a36Sopenharmony_ci	} else {
222162306a36Sopenharmony_ci		ret = ytphy_utp_read_abilities(phydev);
222262306a36Sopenharmony_ci		if (ret < 0)
222362306a36Sopenharmony_ci			goto err_restore_page;
222462306a36Sopenharmony_ci	}
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_cierr_restore_page:
222762306a36Sopenharmony_ci	return phy_restore_page(phydev, old_page, ret);
222862306a36Sopenharmony_ci}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci/**
223162306a36Sopenharmony_ci * yt8521_get_features - switch reg space then call yt8521_get_features_paged
223262306a36Sopenharmony_ci * @phydev: target phy_device struct
223362306a36Sopenharmony_ci *
223462306a36Sopenharmony_ci * returns 0 or negative errno code
223562306a36Sopenharmony_ci */
223662306a36Sopenharmony_cistatic int yt8521_get_features(struct phy_device *phydev)
223762306a36Sopenharmony_ci{
223862306a36Sopenharmony_ci	struct yt8521_priv *priv = phydev->priv;
223962306a36Sopenharmony_ci	int ret;
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
224262306a36Sopenharmony_ci		ret = yt8521_get_features_paged(phydev, priv->reg_page);
224362306a36Sopenharmony_ci	} else {
224462306a36Sopenharmony_ci		ret = yt8521_get_features_paged(phydev,
224562306a36Sopenharmony_ci						YT8521_RSSR_UTP_SPACE);
224662306a36Sopenharmony_ci		if (ret < 0)
224762306a36Sopenharmony_ci			return ret;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci		/* add fiber's features to phydev->supported */
225062306a36Sopenharmony_ci		yt8521_prepare_fiber_features(phydev, phydev->supported);
225162306a36Sopenharmony_ci	}
225262306a36Sopenharmony_ci	return ret;
225362306a36Sopenharmony_ci}
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_cistatic struct phy_driver motorcomm_phy_drvs[] = {
225662306a36Sopenharmony_ci	{
225762306a36Sopenharmony_ci		PHY_ID_MATCH_EXACT(PHY_ID_YT8511),
225862306a36Sopenharmony_ci		.name		= "YT8511 Gigabit Ethernet",
225962306a36Sopenharmony_ci		.config_init	= yt8511_config_init,
226062306a36Sopenharmony_ci		.suspend	= genphy_suspend,
226162306a36Sopenharmony_ci		.resume		= genphy_resume,
226262306a36Sopenharmony_ci		.read_page	= yt8511_read_page,
226362306a36Sopenharmony_ci		.write_page	= yt8511_write_page,
226462306a36Sopenharmony_ci	},
226562306a36Sopenharmony_ci	{
226662306a36Sopenharmony_ci		PHY_ID_MATCH_EXACT(PHY_ID_YT8521),
226762306a36Sopenharmony_ci		.name		= "YT8521 Gigabit Ethernet",
226862306a36Sopenharmony_ci		.get_features	= yt8521_get_features,
226962306a36Sopenharmony_ci		.probe		= yt8521_probe,
227062306a36Sopenharmony_ci		.read_page	= yt8521_read_page,
227162306a36Sopenharmony_ci		.write_page	= yt8521_write_page,
227262306a36Sopenharmony_ci		.get_wol	= ytphy_get_wol,
227362306a36Sopenharmony_ci		.set_wol	= ytphy_set_wol,
227462306a36Sopenharmony_ci		.config_aneg	= yt8521_config_aneg,
227562306a36Sopenharmony_ci		.aneg_done	= yt8521_aneg_done,
227662306a36Sopenharmony_ci		.config_init	= yt8521_config_init,
227762306a36Sopenharmony_ci		.read_status	= yt8521_read_status,
227862306a36Sopenharmony_ci		.soft_reset	= yt8521_soft_reset,
227962306a36Sopenharmony_ci		.suspend	= yt8521_suspend,
228062306a36Sopenharmony_ci		.resume		= yt8521_resume,
228162306a36Sopenharmony_ci	},
228262306a36Sopenharmony_ci	{
228362306a36Sopenharmony_ci		PHY_ID_MATCH_EXACT(PHY_ID_YT8531),
228462306a36Sopenharmony_ci		.name		= "YT8531 Gigabit Ethernet",
228562306a36Sopenharmony_ci		.probe		= yt8531_probe,
228662306a36Sopenharmony_ci		.config_init	= yt8531_config_init,
228762306a36Sopenharmony_ci		.suspend	= genphy_suspend,
228862306a36Sopenharmony_ci		.resume		= genphy_resume,
228962306a36Sopenharmony_ci		.get_wol	= ytphy_get_wol,
229062306a36Sopenharmony_ci		.set_wol	= yt8531_set_wol,
229162306a36Sopenharmony_ci		.link_change_notify = yt8531_link_change_notify,
229262306a36Sopenharmony_ci	},
229362306a36Sopenharmony_ci	{
229462306a36Sopenharmony_ci		PHY_ID_MATCH_EXACT(PHY_ID_YT8531S),
229562306a36Sopenharmony_ci		.name		= "YT8531S Gigabit Ethernet",
229662306a36Sopenharmony_ci		.get_features	= yt8521_get_features,
229762306a36Sopenharmony_ci		.probe		= yt8521_probe,
229862306a36Sopenharmony_ci		.read_page	= yt8521_read_page,
229962306a36Sopenharmony_ci		.write_page	= yt8521_write_page,
230062306a36Sopenharmony_ci		.get_wol	= ytphy_get_wol,
230162306a36Sopenharmony_ci		.set_wol	= ytphy_set_wol,
230262306a36Sopenharmony_ci		.config_aneg	= yt8521_config_aneg,
230362306a36Sopenharmony_ci		.aneg_done	= yt8521_aneg_done,
230462306a36Sopenharmony_ci		.config_init	= yt8521_config_init,
230562306a36Sopenharmony_ci		.read_status	= yt8521_read_status,
230662306a36Sopenharmony_ci		.soft_reset	= yt8521_soft_reset,
230762306a36Sopenharmony_ci		.suspend	= yt8521_suspend,
230862306a36Sopenharmony_ci		.resume		= yt8521_resume,
230962306a36Sopenharmony_ci	},
231062306a36Sopenharmony_ci};
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_cimodule_phy_driver(motorcomm_phy_drvs);
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ciMODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S PHY driver");
231562306a36Sopenharmony_ciMODULE_AUTHOR("Peter Geis");
231662306a36Sopenharmony_ciMODULE_AUTHOR("Frank");
231762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_cistatic const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
232062306a36Sopenharmony_ci	{ PHY_ID_MATCH_EXACT(PHY_ID_YT8511) },
232162306a36Sopenharmony_ci	{ PHY_ID_MATCH_EXACT(PHY_ID_YT8521) },
232262306a36Sopenharmony_ci	{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531) },
232362306a36Sopenharmony_ci	{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },
232462306a36Sopenharmony_ci	{ /* sentinel */ }
232562306a36Sopenharmony_ci};
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(mdio, motorcomm_tbl);
2328