19c102981SAlexandru Ardelean // SPDX-License-Identifier: GPL-2.0+
21f2d109eSYang Shen /*
39c102981SAlexandru Ardelean * Driver for Analog Devices Industrial Ethernet PHYs
49c102981SAlexandru Ardelean *
59c102981SAlexandru Ardelean * Copyright 2019 Analog Devices Inc.
69c102981SAlexandru Ardelean */
79c102981SAlexandru Ardelean #include <linux/kernel.h>
8c83e6163SAlexandru Ardelean #include <linux/bitfield.h>
9fa5bd9c5SAlexandru Ardelean #include <linux/delay.h>
109c102981SAlexandru Ardelean #include <linux/errno.h>
11f2531d45SAlexandru Ardelean #include <linux/ethtool_netlink.h>
129c102981SAlexandru Ardelean #include <linux/init.h>
139c102981SAlexandru Ardelean #include <linux/module.h>
149c102981SAlexandru Ardelean #include <linux/mii.h>
159c102981SAlexandru Ardelean #include <linux/phy.h>
16c83e6163SAlexandru Ardelean #include <linux/property.h>
179c102981SAlexandru Ardelean
189c102981SAlexandru Ardelean #define PHY_ID_ADIN1200 0x0283bc20
199c102981SAlexandru Ardelean #define PHY_ID_ADIN1300 0x0283bc30
209c102981SAlexandru Ardelean
213e32d020SAlexandru Ardelean #define ADIN1300_MII_EXT_REG_PTR 0x0010
223e32d020SAlexandru Ardelean #define ADIN1300_MII_EXT_REG_DATA 0x0011
233e32d020SAlexandru Ardelean
24b422d1b6SAlexandru Ardelean #define ADIN1300_PHY_CTRL1 0x0012
25b422d1b6SAlexandru Ardelean #define ADIN1300_AUTO_MDI_EN BIT(10)
26b422d1b6SAlexandru Ardelean #define ADIN1300_MAN_MDIX_EN BIT(9)
2785ba75bbSAlexandru Ardelean #define ADIN1300_DIAG_CLK_EN BIT(2)
28b422d1b6SAlexandru Ardelean
299fe0b8d6SAlexandru Ardelean #define ADIN1300_RX_ERR_CNT 0x0014
309fe0b8d6SAlexandru Ardelean
3165d7be09SAlexandru Ardelean #define ADIN1300_PHY_CTRL_STATUS2 0x0015
3265d7be09SAlexandru Ardelean #define ADIN1300_NRG_PD_EN BIT(3)
3365d7be09SAlexandru Ardelean #define ADIN1300_NRG_PD_TX_EN BIT(2)
3465d7be09SAlexandru Ardelean #define ADIN1300_NRG_PD_STATUS BIT(1)
3565d7be09SAlexandru Ardelean
362d99b584SAlexandru Ardelean #define ADIN1300_PHY_CTRL2 0x0016
372d99b584SAlexandru Ardelean #define ADIN1300_DOWNSPEED_AN_100_EN BIT(11)
382d99b584SAlexandru Ardelean #define ADIN1300_DOWNSPEED_AN_10_EN BIT(10)
392d99b584SAlexandru Ardelean #define ADIN1300_GROUP_MDIO_EN BIT(6)
402d99b584SAlexandru Ardelean #define ADIN1300_DOWNSPEEDS_EN \
412d99b584SAlexandru Ardelean (ADIN1300_DOWNSPEED_AN_100_EN | ADIN1300_DOWNSPEED_AN_10_EN)
422d99b584SAlexandru Ardelean
432d99b584SAlexandru Ardelean #define ADIN1300_PHY_CTRL3 0x0017
442d99b584SAlexandru Ardelean #define ADIN1300_LINKING_EN BIT(13)
452d99b584SAlexandru Ardelean #define ADIN1300_DOWNSPEED_RETRIES_MSK GENMASK(12, 10)
462d99b584SAlexandru Ardelean
47fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_MASK_REG 0x0018
48fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_MDIO_SYNC_EN BIT(9)
49fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_ANEG_STAT_CHNG_EN BIT(8)
50fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_ANEG_PAGE_RX_EN BIT(6)
51fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_IDLE_ERR_CNT_EN BIT(5)
52fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_MAC_FIFO_OU_EN BIT(4)
53fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_RX_STAT_CHNG_EN BIT(3)
54fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_LINK_STAT_CHNG_EN BIT(2)
55fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_SPEED_CHNG_EN BIT(1)
56fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_HW_IRQ_EN BIT(0)
57fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_MASK_EN \
58fb44b8d6SAlexandru Ardelean (ADIN1300_INT_LINK_STAT_CHNG_EN | ADIN1300_INT_HW_IRQ_EN)
59fb44b8d6SAlexandru Ardelean #define ADIN1300_INT_STATUS_REG 0x0019
60fb44b8d6SAlexandru Ardelean
61b422d1b6SAlexandru Ardelean #define ADIN1300_PHY_STATUS1 0x001a
62b422d1b6SAlexandru Ardelean #define ADIN1300_PAIR_01_SWAP BIT(11)
63b422d1b6SAlexandru Ardelean
64c6aa697cSAlexandru Ardelean /* EEE register addresses, accessible via Clause 22 access using
65c6aa697cSAlexandru Ardelean * ADIN1300_MII_EXT_REG_PTR & ADIN1300_MII_EXT_REG_DATA.
66c6aa697cSAlexandru Ardelean * The bit-fields are the same as specified by IEEE for EEE.
67c6aa697cSAlexandru Ardelean */
68c6aa697cSAlexandru Ardelean #define ADIN1300_EEE_CAP_REG 0x8000
69c6aa697cSAlexandru Ardelean #define ADIN1300_EEE_ADV_REG 0x8001
70c6aa697cSAlexandru Ardelean #define ADIN1300_EEE_LPABLE_REG 0x8002
71c6aa697cSAlexandru Ardelean #define ADIN1300_CLOCK_STOP_REG 0x9400
72c6aa697cSAlexandru Ardelean #define ADIN1300_LPI_WAKE_ERR_CNT_REG 0xa000
73c6aa697cSAlexandru Ardelean
74f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RUN 0xba1b
75f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RUN_EN BIT(0)
76f2531d45SAlexandru Ardelean
77f2531d45SAlexandru Ardelean /*
78f2531d45SAlexandru Ardelean * The XSIM3/2/1 and XSHRT3/2/1 are actually relative.
79f2531d45SAlexandru Ardelean * For CDIAG_DTLD_RSLTS(0) it's ADIN1300_CDIAG_RSLT_XSIM3/2/1
80f2531d45SAlexandru Ardelean * For CDIAG_DTLD_RSLTS(1) it's ADIN1300_CDIAG_RSLT_XSIM3/2/0
81f2531d45SAlexandru Ardelean * For CDIAG_DTLD_RSLTS(2) it's ADIN1300_CDIAG_RSLT_XSIM3/1/0
82f2531d45SAlexandru Ardelean * For CDIAG_DTLD_RSLTS(3) it's ADIN1300_CDIAG_RSLT_XSIM2/1/0
83f2531d45SAlexandru Ardelean */
84f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_DTLD_RSLTS(x) (0xba1d + (x))
85f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RSLT_BUSY BIT(10)
86f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RSLT_XSIM3 BIT(9)
87f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RSLT_XSIM2 BIT(8)
88f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RSLT_XSIM1 BIT(7)
89f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RSLT_SIM BIT(6)
90f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RSLT_XSHRT3 BIT(5)
91f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RSLT_XSHRT2 BIT(4)
92f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RSLT_XSHRT1 BIT(3)
93f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RSLT_SHRT BIT(2)
94f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RSLT_OPEN BIT(1)
95f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_RSLT_GOOD BIT(0)
96f2531d45SAlexandru Ardelean
97f2531d45SAlexandru Ardelean #define ADIN1300_CDIAG_FLT_DIST(x) (0xba21 + (x))
98f2531d45SAlexandru Ardelean
99fa5bd9c5SAlexandru Ardelean #define ADIN1300_GE_SOFT_RESET_REG 0xff0c
100fa5bd9c5SAlexandru Ardelean #define ADIN1300_GE_SOFT_RESET BIT(0)
101fa5bd9c5SAlexandru Ardelean
102ce334216SJosua Mayer #define ADIN1300_GE_CLK_CFG_REG 0xff1f
103ce334216SJosua Mayer #define ADIN1300_GE_CLK_CFG_MASK GENMASK(5, 0)
104ce334216SJosua Mayer #define ADIN1300_GE_CLK_CFG_RCVR_125 BIT(5)
105ce334216SJosua Mayer #define ADIN1300_GE_CLK_CFG_FREE_125 BIT(4)
106ce334216SJosua Mayer #define ADIN1300_GE_CLK_CFG_REF_EN BIT(3)
107ce334216SJosua Mayer #define ADIN1300_GE_CLK_CFG_HRT_RCVR BIT(2)
108ce334216SJosua Mayer #define ADIN1300_GE_CLK_CFG_HRT_FREE BIT(1)
109ce334216SJosua Mayer #define ADIN1300_GE_CLK_CFG_25 BIT(0)
110ce334216SJosua Mayer
111d6200c8fSAlexandru Ardelean #define ADIN1300_GE_RGMII_CFG_REG 0xff23
112c83e6163SAlexandru Ardelean #define ADIN1300_GE_RGMII_RX_MSK GENMASK(8, 6)
113c83e6163SAlexandru Ardelean #define ADIN1300_GE_RGMII_RX_SEL(x) \
114c83e6163SAlexandru Ardelean FIELD_PREP(ADIN1300_GE_RGMII_RX_MSK, x)
115c83e6163SAlexandru Ardelean #define ADIN1300_GE_RGMII_GTX_MSK GENMASK(5, 3)
116c83e6163SAlexandru Ardelean #define ADIN1300_GE_RGMII_GTX_SEL(x) \
117c83e6163SAlexandru Ardelean FIELD_PREP(ADIN1300_GE_RGMII_GTX_MSK, x)
118d6200c8fSAlexandru Ardelean #define ADIN1300_GE_RGMII_RXID_EN BIT(2)
119d6200c8fSAlexandru Ardelean #define ADIN1300_GE_RGMII_TXID_EN BIT(1)
120d6200c8fSAlexandru Ardelean #define ADIN1300_GE_RGMII_EN BIT(0)
121d6200c8fSAlexandru Ardelean
122c83e6163SAlexandru Ardelean /* RGMII internal delay settings for rx and tx for ADIN1300 */
123c83e6163SAlexandru Ardelean #define ADIN1300_RGMII_1_60_NS 0x0001
124c83e6163SAlexandru Ardelean #define ADIN1300_RGMII_1_80_NS 0x0002
125c83e6163SAlexandru Ardelean #define ADIN1300_RGMII_2_00_NS 0x0000
126c83e6163SAlexandru Ardelean #define ADIN1300_RGMII_2_20_NS 0x0006
127c83e6163SAlexandru Ardelean #define ADIN1300_RGMII_2_40_NS 0x0007
128c83e6163SAlexandru Ardelean
129d6200c8fSAlexandru Ardelean #define ADIN1300_GE_RMII_CFG_REG 0xff24
130f1012fb4SAlexandru Ardelean #define ADIN1300_GE_RMII_FIFO_DEPTH_MSK GENMASK(6, 4)
131f1012fb4SAlexandru Ardelean #define ADIN1300_GE_RMII_FIFO_DEPTH_SEL(x) \
132f1012fb4SAlexandru Ardelean FIELD_PREP(ADIN1300_GE_RMII_FIFO_DEPTH_MSK, x)
133d6200c8fSAlexandru Ardelean #define ADIN1300_GE_RMII_EN BIT(0)
134d6200c8fSAlexandru Ardelean
135f1012fb4SAlexandru Ardelean /* RMII fifo depth values */
136f1012fb4SAlexandru Ardelean #define ADIN1300_RMII_4_BITS 0x0000
137f1012fb4SAlexandru Ardelean #define ADIN1300_RMII_8_BITS 0x0001
138f1012fb4SAlexandru Ardelean #define ADIN1300_RMII_12_BITS 0x0002
139f1012fb4SAlexandru Ardelean #define ADIN1300_RMII_16_BITS 0x0003
140f1012fb4SAlexandru Ardelean #define ADIN1300_RMII_20_BITS 0x0004
141f1012fb4SAlexandru Ardelean #define ADIN1300_RMII_24_BITS 0x0005
142f1012fb4SAlexandru Ardelean
143c83e6163SAlexandru Ardelean /**
144c83e6163SAlexandru Ardelean * struct adin_cfg_reg_map - map a config value to aregister value
14519c5a5feSAndrew Lunn * @cfg: value in device configuration
14619c5a5feSAndrew Lunn * @reg: value in the register
147c83e6163SAlexandru Ardelean */
148c83e6163SAlexandru Ardelean struct adin_cfg_reg_map {
149c83e6163SAlexandru Ardelean int cfg;
150c83e6163SAlexandru Ardelean int reg;
151c83e6163SAlexandru Ardelean };
152c83e6163SAlexandru Ardelean
153c83e6163SAlexandru Ardelean static const struct adin_cfg_reg_map adin_rgmii_delays[] = {
154c83e6163SAlexandru Ardelean { 1600, ADIN1300_RGMII_1_60_NS },
155c83e6163SAlexandru Ardelean { 1800, ADIN1300_RGMII_1_80_NS },
156c83e6163SAlexandru Ardelean { 2000, ADIN1300_RGMII_2_00_NS },
157c83e6163SAlexandru Ardelean { 2200, ADIN1300_RGMII_2_20_NS },
158c83e6163SAlexandru Ardelean { 2400, ADIN1300_RGMII_2_40_NS },
159c83e6163SAlexandru Ardelean { },
160c83e6163SAlexandru Ardelean };
161c83e6163SAlexandru Ardelean
162f1012fb4SAlexandru Ardelean static const struct adin_cfg_reg_map adin_rmii_fifo_depths[] = {
163f1012fb4SAlexandru Ardelean { 4, ADIN1300_RMII_4_BITS },
164f1012fb4SAlexandru Ardelean { 8, ADIN1300_RMII_8_BITS },
165f1012fb4SAlexandru Ardelean { 12, ADIN1300_RMII_12_BITS },
166f1012fb4SAlexandru Ardelean { 16, ADIN1300_RMII_16_BITS },
167f1012fb4SAlexandru Ardelean { 20, ADIN1300_RMII_20_BITS },
168f1012fb4SAlexandru Ardelean { 24, ADIN1300_RMII_24_BITS },
169f1012fb4SAlexandru Ardelean { },
170f1012fb4SAlexandru Ardelean };
171f1012fb4SAlexandru Ardelean
172c6aa697cSAlexandru Ardelean /**
173c6aa697cSAlexandru Ardelean * struct adin_clause45_mmd_map - map to convert Clause 45 regs to Clause 22
17419c5a5feSAndrew Lunn * @devad: device address used in Clause 45 access
17519c5a5feSAndrew Lunn * @cl45_regnum: register address defined by Clause 45
17619c5a5feSAndrew Lunn * @adin_regnum: equivalent register address accessible via Clause 22
177c6aa697cSAlexandru Ardelean */
178c6aa697cSAlexandru Ardelean struct adin_clause45_mmd_map {
179c6aa697cSAlexandru Ardelean int devad;
180c6aa697cSAlexandru Ardelean u16 cl45_regnum;
181c6aa697cSAlexandru Ardelean u16 adin_regnum;
182c6aa697cSAlexandru Ardelean };
183c6aa697cSAlexandru Ardelean
184aa63b947SAlexandru Ardelean static const struct adin_clause45_mmd_map adin_clause45_mmd_map[] = {
185c6aa697cSAlexandru Ardelean { MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE, ADIN1300_EEE_CAP_REG },
186c6aa697cSAlexandru Ardelean { MDIO_MMD_AN, MDIO_AN_EEE_LPABLE, ADIN1300_EEE_LPABLE_REG },
187c6aa697cSAlexandru Ardelean { MDIO_MMD_AN, MDIO_AN_EEE_ADV, ADIN1300_EEE_ADV_REG },
188c6aa697cSAlexandru Ardelean { MDIO_MMD_PCS, MDIO_CTRL1, ADIN1300_CLOCK_STOP_REG },
189c6aa697cSAlexandru Ardelean { MDIO_MMD_PCS, MDIO_PCS_EEE_WK_ERR, ADIN1300_LPI_WAKE_ERR_CNT_REG },
190c6aa697cSAlexandru Ardelean };
191c6aa697cSAlexandru Ardelean
1929fe0b8d6SAlexandru Ardelean struct adin_hw_stat {
1939fe0b8d6SAlexandru Ardelean const char *string;
1949fe0b8d6SAlexandru Ardelean u16 reg1;
1959fe0b8d6SAlexandru Ardelean u16 reg2;
1969fe0b8d6SAlexandru Ardelean };
1979fe0b8d6SAlexandru Ardelean
198aa63b947SAlexandru Ardelean static const struct adin_hw_stat adin_hw_stats[] = {
1999fe0b8d6SAlexandru Ardelean { "total_frames_checked_count", 0x940A, 0x940B }, /* hi + lo */
2009fe0b8d6SAlexandru Ardelean { "length_error_frames_count", 0x940C },
2019fe0b8d6SAlexandru Ardelean { "alignment_error_frames_count", 0x940D },
2029fe0b8d6SAlexandru Ardelean { "symbol_error_count", 0x940E },
2039fe0b8d6SAlexandru Ardelean { "oversized_frames_count", 0x940F },
2049fe0b8d6SAlexandru Ardelean { "undersized_frames_count", 0x9410 },
2059fe0b8d6SAlexandru Ardelean { "odd_nibble_frames_count", 0x9411 },
2069fe0b8d6SAlexandru Ardelean { "odd_preamble_packet_count", 0x9412 },
2079fe0b8d6SAlexandru Ardelean { "dribble_bits_frames_count", 0x9413 },
2089fe0b8d6SAlexandru Ardelean { "false_carrier_events_count", 0x9414 },
2099fe0b8d6SAlexandru Ardelean };
2109fe0b8d6SAlexandru Ardelean
2119fe0b8d6SAlexandru Ardelean /**
2129fe0b8d6SAlexandru Ardelean * struct adin_priv - ADIN PHY driver private data
21319c5a5feSAndrew Lunn * @stats: statistic counters for the PHY
2149fe0b8d6SAlexandru Ardelean */
2159fe0b8d6SAlexandru Ardelean struct adin_priv {
2169fe0b8d6SAlexandru Ardelean u64 stats[ARRAY_SIZE(adin_hw_stats)];
2179fe0b8d6SAlexandru Ardelean };
2189fe0b8d6SAlexandru Ardelean
adin_lookup_reg_value(const struct adin_cfg_reg_map * tbl,int cfg)219c83e6163SAlexandru Ardelean static int adin_lookup_reg_value(const struct adin_cfg_reg_map *tbl, int cfg)
220c83e6163SAlexandru Ardelean {
221c83e6163SAlexandru Ardelean size_t i;
222c83e6163SAlexandru Ardelean
223c83e6163SAlexandru Ardelean for (i = 0; tbl[i].cfg; i++) {
224c83e6163SAlexandru Ardelean if (tbl[i].cfg == cfg)
225c83e6163SAlexandru Ardelean return tbl[i].reg;
226c83e6163SAlexandru Ardelean }
227c83e6163SAlexandru Ardelean
228c83e6163SAlexandru Ardelean return -EINVAL;
229c83e6163SAlexandru Ardelean }
230c83e6163SAlexandru Ardelean
adin_get_reg_value(struct phy_device * phydev,const char * prop_name,const struct adin_cfg_reg_map * tbl,u32 dflt)231c83e6163SAlexandru Ardelean static u32 adin_get_reg_value(struct phy_device *phydev,
232c83e6163SAlexandru Ardelean const char *prop_name,
233c83e6163SAlexandru Ardelean const struct adin_cfg_reg_map *tbl,
234c83e6163SAlexandru Ardelean u32 dflt)
235c83e6163SAlexandru Ardelean {
236c83e6163SAlexandru Ardelean struct device *dev = &phydev->mdio.dev;
237c83e6163SAlexandru Ardelean u32 val;
238c83e6163SAlexandru Ardelean int rc;
239c83e6163SAlexandru Ardelean
240c83e6163SAlexandru Ardelean if (device_property_read_u32(dev, prop_name, &val))
241c83e6163SAlexandru Ardelean return dflt;
242c83e6163SAlexandru Ardelean
243c83e6163SAlexandru Ardelean rc = adin_lookup_reg_value(tbl, val);
244c83e6163SAlexandru Ardelean if (rc < 0) {
245c83e6163SAlexandru Ardelean phydev_warn(phydev,
246c83e6163SAlexandru Ardelean "Unsupported value %u for %s using default (%u)\n",
247c83e6163SAlexandru Ardelean val, prop_name, dflt);
248c83e6163SAlexandru Ardelean return dflt;
249c83e6163SAlexandru Ardelean }
250c83e6163SAlexandru Ardelean
251c83e6163SAlexandru Ardelean return rc;
252c83e6163SAlexandru Ardelean }
253c83e6163SAlexandru Ardelean
adin_config_rgmii_mode(struct phy_device * phydev)254d6200c8fSAlexandru Ardelean static int adin_config_rgmii_mode(struct phy_device *phydev)
255d6200c8fSAlexandru Ardelean {
256c83e6163SAlexandru Ardelean u32 val;
257d6200c8fSAlexandru Ardelean int reg;
258d6200c8fSAlexandru Ardelean
259d6200c8fSAlexandru Ardelean if (!phy_interface_is_rgmii(phydev))
260d6200c8fSAlexandru Ardelean return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
261d6200c8fSAlexandru Ardelean ADIN1300_GE_RGMII_CFG_REG,
262d6200c8fSAlexandru Ardelean ADIN1300_GE_RGMII_EN);
263d6200c8fSAlexandru Ardelean
264d6200c8fSAlexandru Ardelean reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_GE_RGMII_CFG_REG);
265d6200c8fSAlexandru Ardelean if (reg < 0)
266d6200c8fSAlexandru Ardelean return reg;
267d6200c8fSAlexandru Ardelean
268d6200c8fSAlexandru Ardelean reg |= ADIN1300_GE_RGMII_EN;
269d6200c8fSAlexandru Ardelean
270d6200c8fSAlexandru Ardelean if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
271d6200c8fSAlexandru Ardelean phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
272d6200c8fSAlexandru Ardelean reg |= ADIN1300_GE_RGMII_RXID_EN;
273c83e6163SAlexandru Ardelean
274c83e6163SAlexandru Ardelean val = adin_get_reg_value(phydev, "adi,rx-internal-delay-ps",
275c83e6163SAlexandru Ardelean adin_rgmii_delays,
276c83e6163SAlexandru Ardelean ADIN1300_RGMII_2_00_NS);
277c83e6163SAlexandru Ardelean reg &= ~ADIN1300_GE_RGMII_RX_MSK;
278c83e6163SAlexandru Ardelean reg |= ADIN1300_GE_RGMII_RX_SEL(val);
279d6200c8fSAlexandru Ardelean } else {
280d6200c8fSAlexandru Ardelean reg &= ~ADIN1300_GE_RGMII_RXID_EN;
281d6200c8fSAlexandru Ardelean }
282d6200c8fSAlexandru Ardelean
283d6200c8fSAlexandru Ardelean if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
284d6200c8fSAlexandru Ardelean phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
285d6200c8fSAlexandru Ardelean reg |= ADIN1300_GE_RGMII_TXID_EN;
286c83e6163SAlexandru Ardelean
287c83e6163SAlexandru Ardelean val = adin_get_reg_value(phydev, "adi,tx-internal-delay-ps",
288c83e6163SAlexandru Ardelean adin_rgmii_delays,
289c83e6163SAlexandru Ardelean ADIN1300_RGMII_2_00_NS);
290c83e6163SAlexandru Ardelean reg &= ~ADIN1300_GE_RGMII_GTX_MSK;
291c83e6163SAlexandru Ardelean reg |= ADIN1300_GE_RGMII_GTX_SEL(val);
292d6200c8fSAlexandru Ardelean } else {
293d6200c8fSAlexandru Ardelean reg &= ~ADIN1300_GE_RGMII_TXID_EN;
294d6200c8fSAlexandru Ardelean }
295d6200c8fSAlexandru Ardelean
296d6200c8fSAlexandru Ardelean return phy_write_mmd(phydev, MDIO_MMD_VEND1,
297d6200c8fSAlexandru Ardelean ADIN1300_GE_RGMII_CFG_REG, reg);
298d6200c8fSAlexandru Ardelean }
299d6200c8fSAlexandru Ardelean
adin_config_rmii_mode(struct phy_device * phydev)300d6200c8fSAlexandru Ardelean static int adin_config_rmii_mode(struct phy_device *phydev)
301d6200c8fSAlexandru Ardelean {
302f1012fb4SAlexandru Ardelean u32 val;
303d6200c8fSAlexandru Ardelean int reg;
304d6200c8fSAlexandru Ardelean
305d6200c8fSAlexandru Ardelean if (phydev->interface != PHY_INTERFACE_MODE_RMII)
306d6200c8fSAlexandru Ardelean return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
307d6200c8fSAlexandru Ardelean ADIN1300_GE_RMII_CFG_REG,
308d6200c8fSAlexandru Ardelean ADIN1300_GE_RMII_EN);
309d6200c8fSAlexandru Ardelean
310d6200c8fSAlexandru Ardelean reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_GE_RMII_CFG_REG);
311d6200c8fSAlexandru Ardelean if (reg < 0)
312d6200c8fSAlexandru Ardelean return reg;
313d6200c8fSAlexandru Ardelean
314d6200c8fSAlexandru Ardelean reg |= ADIN1300_GE_RMII_EN;
315d6200c8fSAlexandru Ardelean
316f1012fb4SAlexandru Ardelean val = adin_get_reg_value(phydev, "adi,fifo-depth-bits",
317f1012fb4SAlexandru Ardelean adin_rmii_fifo_depths,
318f1012fb4SAlexandru Ardelean ADIN1300_RMII_8_BITS);
319f1012fb4SAlexandru Ardelean
320f1012fb4SAlexandru Ardelean reg &= ~ADIN1300_GE_RMII_FIFO_DEPTH_MSK;
321f1012fb4SAlexandru Ardelean reg |= ADIN1300_GE_RMII_FIFO_DEPTH_SEL(val);
322f1012fb4SAlexandru Ardelean
323d6200c8fSAlexandru Ardelean return phy_write_mmd(phydev, MDIO_MMD_VEND1,
324d6200c8fSAlexandru Ardelean ADIN1300_GE_RMII_CFG_REG, reg);
325d6200c8fSAlexandru Ardelean }
326d6200c8fSAlexandru Ardelean
adin_get_downshift(struct phy_device * phydev,u8 * data)3272d99b584SAlexandru Ardelean static int adin_get_downshift(struct phy_device *phydev, u8 *data)
3282d99b584SAlexandru Ardelean {
3292d99b584SAlexandru Ardelean int val, cnt, enable;
3302d99b584SAlexandru Ardelean
3312d99b584SAlexandru Ardelean val = phy_read(phydev, ADIN1300_PHY_CTRL2);
3322d99b584SAlexandru Ardelean if (val < 0)
3332d99b584SAlexandru Ardelean return val;
3342d99b584SAlexandru Ardelean
3352d99b584SAlexandru Ardelean cnt = phy_read(phydev, ADIN1300_PHY_CTRL3);
3362d99b584SAlexandru Ardelean if (cnt < 0)
3372d99b584SAlexandru Ardelean return cnt;
3382d99b584SAlexandru Ardelean
3392d99b584SAlexandru Ardelean enable = FIELD_GET(ADIN1300_DOWNSPEEDS_EN, val);
3402d99b584SAlexandru Ardelean cnt = FIELD_GET(ADIN1300_DOWNSPEED_RETRIES_MSK, cnt);
3412d99b584SAlexandru Ardelean
3422d99b584SAlexandru Ardelean *data = (enable && cnt) ? cnt : DOWNSHIFT_DEV_DISABLE;
3432d99b584SAlexandru Ardelean
3442d99b584SAlexandru Ardelean return 0;
3452d99b584SAlexandru Ardelean }
3462d99b584SAlexandru Ardelean
adin_set_downshift(struct phy_device * phydev,u8 cnt)3472d99b584SAlexandru Ardelean static int adin_set_downshift(struct phy_device *phydev, u8 cnt)
3482d99b584SAlexandru Ardelean {
3492d99b584SAlexandru Ardelean u16 val;
3502d99b584SAlexandru Ardelean int rc;
3512d99b584SAlexandru Ardelean
3522d99b584SAlexandru Ardelean if (cnt == DOWNSHIFT_DEV_DISABLE)
3532d99b584SAlexandru Ardelean return phy_clear_bits(phydev, ADIN1300_PHY_CTRL2,
3542d99b584SAlexandru Ardelean ADIN1300_DOWNSPEEDS_EN);
3552d99b584SAlexandru Ardelean
3562d99b584SAlexandru Ardelean if (cnt > 7)
3572d99b584SAlexandru Ardelean return -E2BIG;
3582d99b584SAlexandru Ardelean
3592d99b584SAlexandru Ardelean val = FIELD_PREP(ADIN1300_DOWNSPEED_RETRIES_MSK, cnt);
3602d99b584SAlexandru Ardelean
3612d99b584SAlexandru Ardelean rc = phy_modify(phydev, ADIN1300_PHY_CTRL3,
36285ba75bbSAlexandru Ardelean ADIN1300_DOWNSPEED_RETRIES_MSK,
3632d99b584SAlexandru Ardelean val);
3642d99b584SAlexandru Ardelean if (rc < 0)
3652d99b584SAlexandru Ardelean return rc;
3662d99b584SAlexandru Ardelean
3672d99b584SAlexandru Ardelean return phy_set_bits(phydev, ADIN1300_PHY_CTRL2,
3682d99b584SAlexandru Ardelean ADIN1300_DOWNSPEEDS_EN);
3692d99b584SAlexandru Ardelean }
3702d99b584SAlexandru Ardelean
adin_get_edpd(struct phy_device * phydev,u16 * tx_interval)37165d7be09SAlexandru Ardelean static int adin_get_edpd(struct phy_device *phydev, u16 *tx_interval)
37265d7be09SAlexandru Ardelean {
37365d7be09SAlexandru Ardelean int val;
37465d7be09SAlexandru Ardelean
37565d7be09SAlexandru Ardelean val = phy_read(phydev, ADIN1300_PHY_CTRL_STATUS2);
37665d7be09SAlexandru Ardelean if (val < 0)
37765d7be09SAlexandru Ardelean return val;
37865d7be09SAlexandru Ardelean
37965d7be09SAlexandru Ardelean if (ADIN1300_NRG_PD_EN & val) {
38065d7be09SAlexandru Ardelean if (val & ADIN1300_NRG_PD_TX_EN)
38165d7be09SAlexandru Ardelean /* default is 1 second */
38265d7be09SAlexandru Ardelean *tx_interval = ETHTOOL_PHY_EDPD_DFLT_TX_MSECS;
38365d7be09SAlexandru Ardelean else
38465d7be09SAlexandru Ardelean *tx_interval = ETHTOOL_PHY_EDPD_NO_TX;
38565d7be09SAlexandru Ardelean } else {
38665d7be09SAlexandru Ardelean *tx_interval = ETHTOOL_PHY_EDPD_DISABLE;
38765d7be09SAlexandru Ardelean }
38865d7be09SAlexandru Ardelean
38965d7be09SAlexandru Ardelean return 0;
39065d7be09SAlexandru Ardelean }
39165d7be09SAlexandru Ardelean
adin_set_edpd(struct phy_device * phydev,u16 tx_interval)39265d7be09SAlexandru Ardelean static int adin_set_edpd(struct phy_device *phydev, u16 tx_interval)
39365d7be09SAlexandru Ardelean {
39465d7be09SAlexandru Ardelean u16 val;
39565d7be09SAlexandru Ardelean
39665d7be09SAlexandru Ardelean if (tx_interval == ETHTOOL_PHY_EDPD_DISABLE)
39765d7be09SAlexandru Ardelean return phy_clear_bits(phydev, ADIN1300_PHY_CTRL_STATUS2,
39865d7be09SAlexandru Ardelean (ADIN1300_NRG_PD_EN | ADIN1300_NRG_PD_TX_EN));
39965d7be09SAlexandru Ardelean
40065d7be09SAlexandru Ardelean val = ADIN1300_NRG_PD_EN;
40165d7be09SAlexandru Ardelean
40265d7be09SAlexandru Ardelean switch (tx_interval) {
40365d7be09SAlexandru Ardelean case 1000: /* 1 second */
404df561f66SGustavo A. R. Silva fallthrough;
40565d7be09SAlexandru Ardelean case ETHTOOL_PHY_EDPD_DFLT_TX_MSECS:
40665d7be09SAlexandru Ardelean val |= ADIN1300_NRG_PD_TX_EN;
407df561f66SGustavo A. R. Silva fallthrough;
40865d7be09SAlexandru Ardelean case ETHTOOL_PHY_EDPD_NO_TX:
40965d7be09SAlexandru Ardelean break;
41065d7be09SAlexandru Ardelean default:
41165d7be09SAlexandru Ardelean return -EINVAL;
41265d7be09SAlexandru Ardelean }
41365d7be09SAlexandru Ardelean
41465d7be09SAlexandru Ardelean return phy_modify(phydev, ADIN1300_PHY_CTRL_STATUS2,
41565d7be09SAlexandru Ardelean (ADIN1300_NRG_PD_EN | ADIN1300_NRG_PD_TX_EN),
41665d7be09SAlexandru Ardelean val);
41765d7be09SAlexandru Ardelean }
41865d7be09SAlexandru Ardelean
adin_get_tunable(struct phy_device * phydev,struct ethtool_tunable * tuna,void * data)4192d99b584SAlexandru Ardelean static int adin_get_tunable(struct phy_device *phydev,
4202d99b584SAlexandru Ardelean struct ethtool_tunable *tuna, void *data)
4212d99b584SAlexandru Ardelean {
4222d99b584SAlexandru Ardelean switch (tuna->id) {
4232d99b584SAlexandru Ardelean case ETHTOOL_PHY_DOWNSHIFT:
4242d99b584SAlexandru Ardelean return adin_get_downshift(phydev, data);
42565d7be09SAlexandru Ardelean case ETHTOOL_PHY_EDPD:
42665d7be09SAlexandru Ardelean return adin_get_edpd(phydev, data);
4272d99b584SAlexandru Ardelean default:
4282d99b584SAlexandru Ardelean return -EOPNOTSUPP;
4292d99b584SAlexandru Ardelean }
4302d99b584SAlexandru Ardelean }
4312d99b584SAlexandru Ardelean
adin_set_tunable(struct phy_device * phydev,struct ethtool_tunable * tuna,const void * data)4322d99b584SAlexandru Ardelean static int adin_set_tunable(struct phy_device *phydev,
4332d99b584SAlexandru Ardelean struct ethtool_tunable *tuna, const void *data)
4342d99b584SAlexandru Ardelean {
4352d99b584SAlexandru Ardelean switch (tuna->id) {
4362d99b584SAlexandru Ardelean case ETHTOOL_PHY_DOWNSHIFT:
4372d99b584SAlexandru Ardelean return adin_set_downshift(phydev, *(const u8 *)data);
43865d7be09SAlexandru Ardelean case ETHTOOL_PHY_EDPD:
43965d7be09SAlexandru Ardelean return adin_set_edpd(phydev, *(const u16 *)data);
4402d99b584SAlexandru Ardelean default:
4412d99b584SAlexandru Ardelean return -EOPNOTSUPP;
4422d99b584SAlexandru Ardelean }
4432d99b584SAlexandru Ardelean }
4442d99b584SAlexandru Ardelean
adin_config_clk_out(struct phy_device * phydev)445ce334216SJosua Mayer static int adin_config_clk_out(struct phy_device *phydev)
446ce334216SJosua Mayer {
447ce334216SJosua Mayer struct device *dev = &phydev->mdio.dev;
448ce334216SJosua Mayer const char *val = NULL;
449ce334216SJosua Mayer u8 sel = 0;
450ce334216SJosua Mayer
451ce334216SJosua Mayer device_property_read_string(dev, "adi,phy-output-clock", &val);
452ce334216SJosua Mayer if (!val) {
453ce334216SJosua Mayer /* property not present, do not enable GP_CLK pin */
454ce334216SJosua Mayer } else if (strcmp(val, "25mhz-reference") == 0) {
455ce334216SJosua Mayer sel |= ADIN1300_GE_CLK_CFG_25;
456ce334216SJosua Mayer } else if (strcmp(val, "125mhz-free-running") == 0) {
457ce334216SJosua Mayer sel |= ADIN1300_GE_CLK_CFG_FREE_125;
458ce334216SJosua Mayer } else if (strcmp(val, "adaptive-free-running") == 0) {
459ce334216SJosua Mayer sel |= ADIN1300_GE_CLK_CFG_HRT_FREE;
460ce334216SJosua Mayer } else {
461ce334216SJosua Mayer phydev_err(phydev, "invalid adi,phy-output-clock\n");
462ce334216SJosua Mayer return -EINVAL;
463ce334216SJosua Mayer }
464ce334216SJosua Mayer
465ce334216SJosua Mayer if (device_property_read_bool(dev, "adi,phy-output-reference-clock"))
466ce334216SJosua Mayer sel |= ADIN1300_GE_CLK_CFG_REF_EN;
467ce334216SJosua Mayer
468ce334216SJosua Mayer return phy_modify_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_GE_CLK_CFG_REG,
469ce334216SJosua Mayer ADIN1300_GE_CLK_CFG_MASK, sel);
470ce334216SJosua Mayer }
471ce334216SJosua Mayer
adin_config_init(struct phy_device * phydev)4729c102981SAlexandru Ardelean static int adin_config_init(struct phy_device *phydev)
4739c102981SAlexandru Ardelean {
474d6200c8fSAlexandru Ardelean int rc;
475d6200c8fSAlexandru Ardelean
476b422d1b6SAlexandru Ardelean phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
477b422d1b6SAlexandru Ardelean
478d6200c8fSAlexandru Ardelean rc = adin_config_rgmii_mode(phydev);
479d6200c8fSAlexandru Ardelean if (rc < 0)
480d6200c8fSAlexandru Ardelean return rc;
481d6200c8fSAlexandru Ardelean
482d6200c8fSAlexandru Ardelean rc = adin_config_rmii_mode(phydev);
483d6200c8fSAlexandru Ardelean if (rc < 0)
484d6200c8fSAlexandru Ardelean return rc;
485d6200c8fSAlexandru Ardelean
4862d99b584SAlexandru Ardelean rc = adin_set_downshift(phydev, 4);
4872d99b584SAlexandru Ardelean if (rc < 0)
4882d99b584SAlexandru Ardelean return rc;
4892d99b584SAlexandru Ardelean
49065d7be09SAlexandru Ardelean rc = adin_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS);
49165d7be09SAlexandru Ardelean if (rc < 0)
49265d7be09SAlexandru Ardelean return rc;
49365d7be09SAlexandru Ardelean
494ce334216SJosua Mayer rc = adin_config_clk_out(phydev);
495ce334216SJosua Mayer if (rc < 0)
496ce334216SJosua Mayer return rc;
497ce334216SJosua Mayer
498d6200c8fSAlexandru Ardelean phydev_dbg(phydev, "PHY is using mode '%s'\n",
499d6200c8fSAlexandru Ardelean phy_modes(phydev->interface));
500d6200c8fSAlexandru Ardelean
501d6200c8fSAlexandru Ardelean return 0;
5029c102981SAlexandru Ardelean }
5039c102981SAlexandru Ardelean
adin_phy_ack_intr(struct phy_device * phydev)504fb44b8d6SAlexandru Ardelean static int adin_phy_ack_intr(struct phy_device *phydev)
505fb44b8d6SAlexandru Ardelean {
506fb44b8d6SAlexandru Ardelean /* Clear pending interrupts */
507fb44b8d6SAlexandru Ardelean int rc = phy_read(phydev, ADIN1300_INT_STATUS_REG);
508fb44b8d6SAlexandru Ardelean
509fb44b8d6SAlexandru Ardelean return rc < 0 ? rc : 0;
510fb44b8d6SAlexandru Ardelean }
511fb44b8d6SAlexandru Ardelean
adin_phy_config_intr(struct phy_device * phydev)512fb44b8d6SAlexandru Ardelean static int adin_phy_config_intr(struct phy_device *phydev)
513fb44b8d6SAlexandru Ardelean {
5141d8300d3SIoana Ciornei int err;
515fb44b8d6SAlexandru Ardelean
5161d8300d3SIoana Ciornei if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
5171d8300d3SIoana Ciornei err = adin_phy_ack_intr(phydev);
5181d8300d3SIoana Ciornei if (err)
5191d8300d3SIoana Ciornei return err;
5201d8300d3SIoana Ciornei
5211d8300d3SIoana Ciornei err = phy_set_bits(phydev, ADIN1300_INT_MASK_REG,
522fb44b8d6SAlexandru Ardelean ADIN1300_INT_MASK_EN);
5231d8300d3SIoana Ciornei } else {
5241d8300d3SIoana Ciornei err = phy_clear_bits(phydev, ADIN1300_INT_MASK_REG,
5251d8300d3SIoana Ciornei ADIN1300_INT_MASK_EN);
5261d8300d3SIoana Ciornei if (err)
5271d8300d3SIoana Ciornei return err;
5281d8300d3SIoana Ciornei
5291d8300d3SIoana Ciornei err = adin_phy_ack_intr(phydev);
5301d8300d3SIoana Ciornei }
5311d8300d3SIoana Ciornei
5321d8300d3SIoana Ciornei return err;
533fb44b8d6SAlexandru Ardelean }
534fb44b8d6SAlexandru Ardelean
adin_phy_handle_interrupt(struct phy_device * phydev)53566d7439eSIoana Ciornei static irqreturn_t adin_phy_handle_interrupt(struct phy_device *phydev)
53666d7439eSIoana Ciornei {
53766d7439eSIoana Ciornei int irq_status;
53866d7439eSIoana Ciornei
53966d7439eSIoana Ciornei irq_status = phy_read(phydev, ADIN1300_INT_STATUS_REG);
54066d7439eSIoana Ciornei if (irq_status < 0) {
54166d7439eSIoana Ciornei phy_error(phydev);
54266d7439eSIoana Ciornei return IRQ_NONE;
54366d7439eSIoana Ciornei }
54466d7439eSIoana Ciornei
54566d7439eSIoana Ciornei if (!(irq_status & ADIN1300_INT_LINK_STAT_CHNG_EN))
54666d7439eSIoana Ciornei return IRQ_NONE;
54766d7439eSIoana Ciornei
54866d7439eSIoana Ciornei phy_trigger_machine(phydev);
54966d7439eSIoana Ciornei
55066d7439eSIoana Ciornei return IRQ_HANDLED;
55166d7439eSIoana Ciornei }
55266d7439eSIoana Ciornei
adin_cl45_to_adin_reg(struct phy_device * phydev,int devad,u16 cl45_regnum)553c6aa697cSAlexandru Ardelean static int adin_cl45_to_adin_reg(struct phy_device *phydev, int devad,
554c6aa697cSAlexandru Ardelean u16 cl45_regnum)
555c6aa697cSAlexandru Ardelean {
556aa63b947SAlexandru Ardelean const struct adin_clause45_mmd_map *m;
557c6aa697cSAlexandru Ardelean int i;
558c6aa697cSAlexandru Ardelean
559c6aa697cSAlexandru Ardelean if (devad == MDIO_MMD_VEND1)
560c6aa697cSAlexandru Ardelean return cl45_regnum;
561c6aa697cSAlexandru Ardelean
562c6aa697cSAlexandru Ardelean for (i = 0; i < ARRAY_SIZE(adin_clause45_mmd_map); i++) {
563c6aa697cSAlexandru Ardelean m = &adin_clause45_mmd_map[i];
564c6aa697cSAlexandru Ardelean if (m->devad == devad && m->cl45_regnum == cl45_regnum)
565c6aa697cSAlexandru Ardelean return m->adin_regnum;
566c6aa697cSAlexandru Ardelean }
567c6aa697cSAlexandru Ardelean
568c6aa697cSAlexandru Ardelean phydev_err(phydev,
569c6aa697cSAlexandru Ardelean "No translation available for devad: %d reg: %04x\n",
570c6aa697cSAlexandru Ardelean devad, cl45_regnum);
571c6aa697cSAlexandru Ardelean
572c6aa697cSAlexandru Ardelean return -EINVAL;
573c6aa697cSAlexandru Ardelean }
574c6aa697cSAlexandru Ardelean
adin_read_mmd(struct phy_device * phydev,int devad,u16 regnum)5753e32d020SAlexandru Ardelean static int adin_read_mmd(struct phy_device *phydev, int devad, u16 regnum)
5763e32d020SAlexandru Ardelean {
5773e32d020SAlexandru Ardelean struct mii_bus *bus = phydev->mdio.bus;
5783e32d020SAlexandru Ardelean int phy_addr = phydev->mdio.addr;
579c6aa697cSAlexandru Ardelean int adin_regnum;
5803e32d020SAlexandru Ardelean int err;
5813e32d020SAlexandru Ardelean
582c6aa697cSAlexandru Ardelean adin_regnum = adin_cl45_to_adin_reg(phydev, devad, regnum);
583c6aa697cSAlexandru Ardelean if (adin_regnum < 0)
584c6aa697cSAlexandru Ardelean return adin_regnum;
585c6aa697cSAlexandru Ardelean
586c6aa697cSAlexandru Ardelean err = __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_PTR,
587c6aa697cSAlexandru Ardelean adin_regnum);
5883e32d020SAlexandru Ardelean if (err)
5893e32d020SAlexandru Ardelean return err;
5903e32d020SAlexandru Ardelean
5913e32d020SAlexandru Ardelean return __mdiobus_read(bus, phy_addr, ADIN1300_MII_EXT_REG_DATA);
5923e32d020SAlexandru Ardelean }
5933e32d020SAlexandru Ardelean
adin_write_mmd(struct phy_device * phydev,int devad,u16 regnum,u16 val)5943e32d020SAlexandru Ardelean static int adin_write_mmd(struct phy_device *phydev, int devad, u16 regnum,
5953e32d020SAlexandru Ardelean u16 val)
5963e32d020SAlexandru Ardelean {
5973e32d020SAlexandru Ardelean struct mii_bus *bus = phydev->mdio.bus;
5983e32d020SAlexandru Ardelean int phy_addr = phydev->mdio.addr;
599c6aa697cSAlexandru Ardelean int adin_regnum;
6003e32d020SAlexandru Ardelean int err;
6013e32d020SAlexandru Ardelean
602c6aa697cSAlexandru Ardelean adin_regnum = adin_cl45_to_adin_reg(phydev, devad, regnum);
603c6aa697cSAlexandru Ardelean if (adin_regnum < 0)
604c6aa697cSAlexandru Ardelean return adin_regnum;
605c6aa697cSAlexandru Ardelean
606c6aa697cSAlexandru Ardelean err = __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_PTR,
607c6aa697cSAlexandru Ardelean adin_regnum);
6083e32d020SAlexandru Ardelean if (err)
6093e32d020SAlexandru Ardelean return err;
6103e32d020SAlexandru Ardelean
6113e32d020SAlexandru Ardelean return __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_DATA, val);
6123e32d020SAlexandru Ardelean }
6133e32d020SAlexandru Ardelean
adin_config_mdix(struct phy_device * phydev)614b422d1b6SAlexandru Ardelean static int adin_config_mdix(struct phy_device *phydev)
615b422d1b6SAlexandru Ardelean {
616b422d1b6SAlexandru Ardelean bool auto_en, mdix_en;
617b422d1b6SAlexandru Ardelean int reg;
618b422d1b6SAlexandru Ardelean
619b422d1b6SAlexandru Ardelean mdix_en = false;
620b422d1b6SAlexandru Ardelean auto_en = false;
621b422d1b6SAlexandru Ardelean switch (phydev->mdix_ctrl) {
622b422d1b6SAlexandru Ardelean case ETH_TP_MDI:
623b422d1b6SAlexandru Ardelean break;
624b422d1b6SAlexandru Ardelean case ETH_TP_MDI_X:
625b422d1b6SAlexandru Ardelean mdix_en = true;
626b422d1b6SAlexandru Ardelean break;
627b422d1b6SAlexandru Ardelean case ETH_TP_MDI_AUTO:
628b422d1b6SAlexandru Ardelean auto_en = true;
629b422d1b6SAlexandru Ardelean break;
630b422d1b6SAlexandru Ardelean default:
631b422d1b6SAlexandru Ardelean return -EINVAL;
632b422d1b6SAlexandru Ardelean }
633b422d1b6SAlexandru Ardelean
634b422d1b6SAlexandru Ardelean reg = phy_read(phydev, ADIN1300_PHY_CTRL1);
635b422d1b6SAlexandru Ardelean if (reg < 0)
636b422d1b6SAlexandru Ardelean return reg;
637b422d1b6SAlexandru Ardelean
638b422d1b6SAlexandru Ardelean if (mdix_en)
639b422d1b6SAlexandru Ardelean reg |= ADIN1300_MAN_MDIX_EN;
640b422d1b6SAlexandru Ardelean else
641b422d1b6SAlexandru Ardelean reg &= ~ADIN1300_MAN_MDIX_EN;
642b422d1b6SAlexandru Ardelean
643b422d1b6SAlexandru Ardelean if (auto_en)
644b422d1b6SAlexandru Ardelean reg |= ADIN1300_AUTO_MDI_EN;
645b422d1b6SAlexandru Ardelean else
646b422d1b6SAlexandru Ardelean reg &= ~ADIN1300_AUTO_MDI_EN;
647b422d1b6SAlexandru Ardelean
648b422d1b6SAlexandru Ardelean return phy_write(phydev, ADIN1300_PHY_CTRL1, reg);
649b422d1b6SAlexandru Ardelean }
650b422d1b6SAlexandru Ardelean
adin_config_aneg(struct phy_device * phydev)651b422d1b6SAlexandru Ardelean static int adin_config_aneg(struct phy_device *phydev)
652b422d1b6SAlexandru Ardelean {
653b422d1b6SAlexandru Ardelean int ret;
654b422d1b6SAlexandru Ardelean
65585ba75bbSAlexandru Ardelean ret = phy_clear_bits(phydev, ADIN1300_PHY_CTRL1, ADIN1300_DIAG_CLK_EN);
65685ba75bbSAlexandru Ardelean if (ret < 0)
65785ba75bbSAlexandru Ardelean return ret;
65885ba75bbSAlexandru Ardelean
65985ba75bbSAlexandru Ardelean ret = phy_set_bits(phydev, ADIN1300_PHY_CTRL3, ADIN1300_LINKING_EN);
66085ba75bbSAlexandru Ardelean if (ret < 0)
66185ba75bbSAlexandru Ardelean return ret;
66285ba75bbSAlexandru Ardelean
663b422d1b6SAlexandru Ardelean ret = adin_config_mdix(phydev);
664b422d1b6SAlexandru Ardelean if (ret)
665b422d1b6SAlexandru Ardelean return ret;
666b422d1b6SAlexandru Ardelean
667b422d1b6SAlexandru Ardelean return genphy_config_aneg(phydev);
668b422d1b6SAlexandru Ardelean }
669b422d1b6SAlexandru Ardelean
adin_mdix_update(struct phy_device * phydev)670b422d1b6SAlexandru Ardelean static int adin_mdix_update(struct phy_device *phydev)
671b422d1b6SAlexandru Ardelean {
672b422d1b6SAlexandru Ardelean bool auto_en, mdix_en;
673b422d1b6SAlexandru Ardelean bool swapped;
674b422d1b6SAlexandru Ardelean int reg;
675b422d1b6SAlexandru Ardelean
676b422d1b6SAlexandru Ardelean reg = phy_read(phydev, ADIN1300_PHY_CTRL1);
677b422d1b6SAlexandru Ardelean if (reg < 0)
678b422d1b6SAlexandru Ardelean return reg;
679b422d1b6SAlexandru Ardelean
680b422d1b6SAlexandru Ardelean auto_en = !!(reg & ADIN1300_AUTO_MDI_EN);
681b422d1b6SAlexandru Ardelean mdix_en = !!(reg & ADIN1300_MAN_MDIX_EN);
682b422d1b6SAlexandru Ardelean
683b422d1b6SAlexandru Ardelean /* If MDI/MDIX is forced, just read it from the control reg */
684b422d1b6SAlexandru Ardelean if (!auto_en) {
685b422d1b6SAlexandru Ardelean if (mdix_en)
686b422d1b6SAlexandru Ardelean phydev->mdix = ETH_TP_MDI_X;
687b422d1b6SAlexandru Ardelean else
688b422d1b6SAlexandru Ardelean phydev->mdix = ETH_TP_MDI;
689b422d1b6SAlexandru Ardelean return 0;
690b422d1b6SAlexandru Ardelean }
691b422d1b6SAlexandru Ardelean
692b422d1b6SAlexandru Ardelean /**
693b422d1b6SAlexandru Ardelean * Otherwise, we need to deduce it from the PHY status2 reg.
694b422d1b6SAlexandru Ardelean * When Auto-MDI is enabled, the ADIN1300_MAN_MDIX_EN bit implies
695b422d1b6SAlexandru Ardelean * a preference for MDIX when it is set.
696b422d1b6SAlexandru Ardelean */
697b422d1b6SAlexandru Ardelean reg = phy_read(phydev, ADIN1300_PHY_STATUS1);
698b422d1b6SAlexandru Ardelean if (reg < 0)
699b422d1b6SAlexandru Ardelean return reg;
700b422d1b6SAlexandru Ardelean
701b422d1b6SAlexandru Ardelean swapped = !!(reg & ADIN1300_PAIR_01_SWAP);
702b422d1b6SAlexandru Ardelean
703b422d1b6SAlexandru Ardelean if (mdix_en != swapped)
704b422d1b6SAlexandru Ardelean phydev->mdix = ETH_TP_MDI_X;
705b422d1b6SAlexandru Ardelean else
706b422d1b6SAlexandru Ardelean phydev->mdix = ETH_TP_MDI;
707b422d1b6SAlexandru Ardelean
708b422d1b6SAlexandru Ardelean return 0;
709b422d1b6SAlexandru Ardelean }
710b422d1b6SAlexandru Ardelean
adin_read_status(struct phy_device * phydev)711b422d1b6SAlexandru Ardelean static int adin_read_status(struct phy_device *phydev)
712b422d1b6SAlexandru Ardelean {
713b422d1b6SAlexandru Ardelean int ret;
714b422d1b6SAlexandru Ardelean
715b422d1b6SAlexandru Ardelean ret = adin_mdix_update(phydev);
716b422d1b6SAlexandru Ardelean if (ret < 0)
717b422d1b6SAlexandru Ardelean return ret;
718b422d1b6SAlexandru Ardelean
719b422d1b6SAlexandru Ardelean return genphy_read_status(phydev);
720b422d1b6SAlexandru Ardelean }
721b422d1b6SAlexandru Ardelean
adin_soft_reset(struct phy_device * phydev)722fa5bd9c5SAlexandru Ardelean static int adin_soft_reset(struct phy_device *phydev)
723fa5bd9c5SAlexandru Ardelean {
724fa5bd9c5SAlexandru Ardelean int rc;
725fa5bd9c5SAlexandru Ardelean
726fa5bd9c5SAlexandru Ardelean /* The reset bit is self-clearing, set it and wait */
727fa5bd9c5SAlexandru Ardelean rc = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
728fa5bd9c5SAlexandru Ardelean ADIN1300_GE_SOFT_RESET_REG,
729fa5bd9c5SAlexandru Ardelean ADIN1300_GE_SOFT_RESET);
730fa5bd9c5SAlexandru Ardelean if (rc < 0)
731fa5bd9c5SAlexandru Ardelean return rc;
732fa5bd9c5SAlexandru Ardelean
7330c58ac1eSDejin Zheng msleep(20);
734fa5bd9c5SAlexandru Ardelean
735fa5bd9c5SAlexandru Ardelean /* If we get a read error something may be wrong */
736fa5bd9c5SAlexandru Ardelean rc = phy_read_mmd(phydev, MDIO_MMD_VEND1,
737fa5bd9c5SAlexandru Ardelean ADIN1300_GE_SOFT_RESET_REG);
738fa5bd9c5SAlexandru Ardelean
739fa5bd9c5SAlexandru Ardelean return rc < 0 ? rc : 0;
740fa5bd9c5SAlexandru Ardelean }
741fa5bd9c5SAlexandru Ardelean
adin_get_sset_count(struct phy_device * phydev)7429fe0b8d6SAlexandru Ardelean static int adin_get_sset_count(struct phy_device *phydev)
7439fe0b8d6SAlexandru Ardelean {
7449fe0b8d6SAlexandru Ardelean return ARRAY_SIZE(adin_hw_stats);
7459fe0b8d6SAlexandru Ardelean }
7469fe0b8d6SAlexandru Ardelean
adin_get_strings(struct phy_device * phydev,u8 * data)7479fe0b8d6SAlexandru Ardelean static void adin_get_strings(struct phy_device *phydev, u8 *data)
7489fe0b8d6SAlexandru Ardelean {
7499fe0b8d6SAlexandru Ardelean int i;
7509fe0b8d6SAlexandru Ardelean
7519fe0b8d6SAlexandru Ardelean for (i = 0; i < ARRAY_SIZE(adin_hw_stats); i++) {
752*fb3ceec1SWolfram Sang strscpy(&data[i * ETH_GSTRING_LEN],
7539fe0b8d6SAlexandru Ardelean adin_hw_stats[i].string, ETH_GSTRING_LEN);
7549fe0b8d6SAlexandru Ardelean }
7559fe0b8d6SAlexandru Ardelean }
7569fe0b8d6SAlexandru Ardelean
adin_read_mmd_stat_regs(struct phy_device * phydev,const struct adin_hw_stat * stat,u32 * val)7579fe0b8d6SAlexandru Ardelean static int adin_read_mmd_stat_regs(struct phy_device *phydev,
758aa63b947SAlexandru Ardelean const struct adin_hw_stat *stat,
7599fe0b8d6SAlexandru Ardelean u32 *val)
7609fe0b8d6SAlexandru Ardelean {
7619fe0b8d6SAlexandru Ardelean int ret;
7629fe0b8d6SAlexandru Ardelean
7639fe0b8d6SAlexandru Ardelean ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, stat->reg1);
7649fe0b8d6SAlexandru Ardelean if (ret < 0)
7659fe0b8d6SAlexandru Ardelean return ret;
7669fe0b8d6SAlexandru Ardelean
7679fe0b8d6SAlexandru Ardelean *val = (ret & 0xffff);
7689fe0b8d6SAlexandru Ardelean
7699fe0b8d6SAlexandru Ardelean if (stat->reg2 == 0)
7709fe0b8d6SAlexandru Ardelean return 0;
7719fe0b8d6SAlexandru Ardelean
7729fe0b8d6SAlexandru Ardelean ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, stat->reg2);
7739fe0b8d6SAlexandru Ardelean if (ret < 0)
7749fe0b8d6SAlexandru Ardelean return ret;
7759fe0b8d6SAlexandru Ardelean
7769fe0b8d6SAlexandru Ardelean *val <<= 16;
7779fe0b8d6SAlexandru Ardelean *val |= (ret & 0xffff);
7789fe0b8d6SAlexandru Ardelean
7799fe0b8d6SAlexandru Ardelean return 0;
7809fe0b8d6SAlexandru Ardelean }
7819fe0b8d6SAlexandru Ardelean
adin_get_stat(struct phy_device * phydev,int i)7829fe0b8d6SAlexandru Ardelean static u64 adin_get_stat(struct phy_device *phydev, int i)
7839fe0b8d6SAlexandru Ardelean {
784aa63b947SAlexandru Ardelean const struct adin_hw_stat *stat = &adin_hw_stats[i];
7859fe0b8d6SAlexandru Ardelean struct adin_priv *priv = phydev->priv;
7869fe0b8d6SAlexandru Ardelean u32 val;
7879fe0b8d6SAlexandru Ardelean int ret;
7889fe0b8d6SAlexandru Ardelean
7899fe0b8d6SAlexandru Ardelean if (stat->reg1 > 0x1f) {
7909fe0b8d6SAlexandru Ardelean ret = adin_read_mmd_stat_regs(phydev, stat, &val);
7919fe0b8d6SAlexandru Ardelean if (ret < 0)
7929fe0b8d6SAlexandru Ardelean return (u64)(~0);
7939fe0b8d6SAlexandru Ardelean } else {
7949fe0b8d6SAlexandru Ardelean ret = phy_read(phydev, stat->reg1);
7959fe0b8d6SAlexandru Ardelean if (ret < 0)
7969fe0b8d6SAlexandru Ardelean return (u64)(~0);
7979fe0b8d6SAlexandru Ardelean val = (ret & 0xffff);
7989fe0b8d6SAlexandru Ardelean }
7999fe0b8d6SAlexandru Ardelean
8009fe0b8d6SAlexandru Ardelean priv->stats[i] += val;
8019fe0b8d6SAlexandru Ardelean
8029fe0b8d6SAlexandru Ardelean return priv->stats[i];
8039fe0b8d6SAlexandru Ardelean }
8049fe0b8d6SAlexandru Ardelean
adin_get_stats(struct phy_device * phydev,struct ethtool_stats * stats,u64 * data)8059fe0b8d6SAlexandru Ardelean static void adin_get_stats(struct phy_device *phydev,
8069fe0b8d6SAlexandru Ardelean struct ethtool_stats *stats, u64 *data)
8079fe0b8d6SAlexandru Ardelean {
8089fe0b8d6SAlexandru Ardelean int i, rc;
8099fe0b8d6SAlexandru Ardelean
8109fe0b8d6SAlexandru Ardelean /* latch copies of all the frame-checker counters */
8119fe0b8d6SAlexandru Ardelean rc = phy_read(phydev, ADIN1300_RX_ERR_CNT);
8129fe0b8d6SAlexandru Ardelean if (rc < 0)
8139fe0b8d6SAlexandru Ardelean return;
8149fe0b8d6SAlexandru Ardelean
8159fe0b8d6SAlexandru Ardelean for (i = 0; i < ARRAY_SIZE(adin_hw_stats); i++)
8169fe0b8d6SAlexandru Ardelean data[i] = adin_get_stat(phydev, i);
8179fe0b8d6SAlexandru Ardelean }
8189fe0b8d6SAlexandru Ardelean
adin_probe(struct phy_device * phydev)8199fe0b8d6SAlexandru Ardelean static int adin_probe(struct phy_device *phydev)
8209fe0b8d6SAlexandru Ardelean {
8219fe0b8d6SAlexandru Ardelean struct device *dev = &phydev->mdio.dev;
8229fe0b8d6SAlexandru Ardelean struct adin_priv *priv;
8239fe0b8d6SAlexandru Ardelean
8249fe0b8d6SAlexandru Ardelean priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
8259fe0b8d6SAlexandru Ardelean if (!priv)
8269fe0b8d6SAlexandru Ardelean return -ENOMEM;
8279fe0b8d6SAlexandru Ardelean
8289fe0b8d6SAlexandru Ardelean phydev->priv = priv;
8299fe0b8d6SAlexandru Ardelean
8309fe0b8d6SAlexandru Ardelean return 0;
8319fe0b8d6SAlexandru Ardelean }
8329fe0b8d6SAlexandru Ardelean
adin_cable_test_start(struct phy_device * phydev)833f2531d45SAlexandru Ardelean static int adin_cable_test_start(struct phy_device *phydev)
834f2531d45SAlexandru Ardelean {
835f2531d45SAlexandru Ardelean int ret;
836f2531d45SAlexandru Ardelean
837f2531d45SAlexandru Ardelean ret = phy_clear_bits(phydev, ADIN1300_PHY_CTRL3, ADIN1300_LINKING_EN);
838f2531d45SAlexandru Ardelean if (ret < 0)
839f2531d45SAlexandru Ardelean return ret;
840f2531d45SAlexandru Ardelean
841f2531d45SAlexandru Ardelean ret = phy_clear_bits(phydev, ADIN1300_PHY_CTRL1, ADIN1300_DIAG_CLK_EN);
842f2531d45SAlexandru Ardelean if (ret < 0)
843f2531d45SAlexandru Ardelean return ret;
844f2531d45SAlexandru Ardelean
845f2531d45SAlexandru Ardelean /* wait a bit for the clock to stabilize */
846f2531d45SAlexandru Ardelean msleep(50);
847f2531d45SAlexandru Ardelean
848f2531d45SAlexandru Ardelean return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_CDIAG_RUN,
849f2531d45SAlexandru Ardelean ADIN1300_CDIAG_RUN_EN);
850f2531d45SAlexandru Ardelean }
851f2531d45SAlexandru Ardelean
adin_cable_test_report_trans(int result)852f2531d45SAlexandru Ardelean static int adin_cable_test_report_trans(int result)
853f2531d45SAlexandru Ardelean {
854f2531d45SAlexandru Ardelean int mask;
855f2531d45SAlexandru Ardelean
856f2531d45SAlexandru Ardelean if (result & ADIN1300_CDIAG_RSLT_GOOD)
857f2531d45SAlexandru Ardelean return ETHTOOL_A_CABLE_RESULT_CODE_OK;
858f2531d45SAlexandru Ardelean if (result & ADIN1300_CDIAG_RSLT_OPEN)
859f2531d45SAlexandru Ardelean return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
860f2531d45SAlexandru Ardelean
861f2531d45SAlexandru Ardelean /* short with other pairs */
862f2531d45SAlexandru Ardelean mask = ADIN1300_CDIAG_RSLT_XSHRT3 |
863f2531d45SAlexandru Ardelean ADIN1300_CDIAG_RSLT_XSHRT2 |
864f2531d45SAlexandru Ardelean ADIN1300_CDIAG_RSLT_XSHRT1;
865f2531d45SAlexandru Ardelean if (result & mask)
866f2531d45SAlexandru Ardelean return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
867f2531d45SAlexandru Ardelean
868f2531d45SAlexandru Ardelean if (result & ADIN1300_CDIAG_RSLT_SHRT)
869f2531d45SAlexandru Ardelean return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
870f2531d45SAlexandru Ardelean
871f2531d45SAlexandru Ardelean return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
872f2531d45SAlexandru Ardelean }
873f2531d45SAlexandru Ardelean
adin_cable_test_report_pair(struct phy_device * phydev,unsigned int pair)874f2531d45SAlexandru Ardelean static int adin_cable_test_report_pair(struct phy_device *phydev,
875f2531d45SAlexandru Ardelean unsigned int pair)
876f2531d45SAlexandru Ardelean {
877f2531d45SAlexandru Ardelean int fault_rslt;
878f2531d45SAlexandru Ardelean int ret;
879f2531d45SAlexandru Ardelean
880f2531d45SAlexandru Ardelean ret = phy_read_mmd(phydev, MDIO_MMD_VEND1,
881f2531d45SAlexandru Ardelean ADIN1300_CDIAG_DTLD_RSLTS(pair));
882f2531d45SAlexandru Ardelean if (ret < 0)
883f2531d45SAlexandru Ardelean return ret;
884f2531d45SAlexandru Ardelean
885f2531d45SAlexandru Ardelean fault_rslt = adin_cable_test_report_trans(ret);
886f2531d45SAlexandru Ardelean
887f2531d45SAlexandru Ardelean ret = ethnl_cable_test_result(phydev, pair, fault_rslt);
888f2531d45SAlexandru Ardelean if (ret < 0)
889f2531d45SAlexandru Ardelean return ret;
890f2531d45SAlexandru Ardelean
891f2531d45SAlexandru Ardelean ret = phy_read_mmd(phydev, MDIO_MMD_VEND1,
892f2531d45SAlexandru Ardelean ADIN1300_CDIAG_FLT_DIST(pair));
893f2531d45SAlexandru Ardelean if (ret < 0)
894f2531d45SAlexandru Ardelean return ret;
895f2531d45SAlexandru Ardelean
896f2531d45SAlexandru Ardelean switch (fault_rslt) {
897f2531d45SAlexandru Ardelean case ETHTOOL_A_CABLE_RESULT_CODE_OPEN:
898f2531d45SAlexandru Ardelean case ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT:
899f2531d45SAlexandru Ardelean case ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT:
900f2531d45SAlexandru Ardelean return ethnl_cable_test_fault_length(phydev, pair, ret * 100);
901f2531d45SAlexandru Ardelean default:
902f2531d45SAlexandru Ardelean return 0;
903f2531d45SAlexandru Ardelean }
904f2531d45SAlexandru Ardelean }
905f2531d45SAlexandru Ardelean
adin_cable_test_report(struct phy_device * phydev)906f2531d45SAlexandru Ardelean static int adin_cable_test_report(struct phy_device *phydev)
907f2531d45SAlexandru Ardelean {
908f2531d45SAlexandru Ardelean unsigned int pair;
909f2531d45SAlexandru Ardelean int ret;
910f2531d45SAlexandru Ardelean
911f2531d45SAlexandru Ardelean for (pair = ETHTOOL_A_CABLE_PAIR_A; pair <= ETHTOOL_A_CABLE_PAIR_D; pair++) {
912f2531d45SAlexandru Ardelean ret = adin_cable_test_report_pair(phydev, pair);
913f2531d45SAlexandru Ardelean if (ret < 0)
914f2531d45SAlexandru Ardelean return ret;
915f2531d45SAlexandru Ardelean }
916f2531d45SAlexandru Ardelean
917f2531d45SAlexandru Ardelean return 0;
918f2531d45SAlexandru Ardelean }
919f2531d45SAlexandru Ardelean
adin_cable_test_get_status(struct phy_device * phydev,bool * finished)920f2531d45SAlexandru Ardelean static int adin_cable_test_get_status(struct phy_device *phydev,
921f2531d45SAlexandru Ardelean bool *finished)
922f2531d45SAlexandru Ardelean {
923f2531d45SAlexandru Ardelean int ret;
924f2531d45SAlexandru Ardelean
925f2531d45SAlexandru Ardelean *finished = false;
926f2531d45SAlexandru Ardelean
927f2531d45SAlexandru Ardelean ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_CDIAG_RUN);
928f2531d45SAlexandru Ardelean if (ret < 0)
929f2531d45SAlexandru Ardelean return ret;
930f2531d45SAlexandru Ardelean
931f2531d45SAlexandru Ardelean if (ret & ADIN1300_CDIAG_RUN_EN)
932f2531d45SAlexandru Ardelean return 0;
933f2531d45SAlexandru Ardelean
934f2531d45SAlexandru Ardelean *finished = true;
935f2531d45SAlexandru Ardelean
936f2531d45SAlexandru Ardelean return adin_cable_test_report(phydev);
937f2531d45SAlexandru Ardelean }
938f2531d45SAlexandru Ardelean
9399c102981SAlexandru Ardelean static struct phy_driver adin_driver[] = {
9409c102981SAlexandru Ardelean {
9419c102981SAlexandru Ardelean PHY_ID_MATCH_MODEL(PHY_ID_ADIN1200),
9429c102981SAlexandru Ardelean .name = "ADIN1200",
943f2531d45SAlexandru Ardelean .flags = PHY_POLL_CABLE_TEST,
9449fe0b8d6SAlexandru Ardelean .probe = adin_probe,
9459c102981SAlexandru Ardelean .config_init = adin_config_init,
946fa5bd9c5SAlexandru Ardelean .soft_reset = adin_soft_reset,
947b422d1b6SAlexandru Ardelean .config_aneg = adin_config_aneg,
948b422d1b6SAlexandru Ardelean .read_status = adin_read_status,
9492d99b584SAlexandru Ardelean .get_tunable = adin_get_tunable,
9502d99b584SAlexandru Ardelean .set_tunable = adin_set_tunable,
951fb44b8d6SAlexandru Ardelean .config_intr = adin_phy_config_intr,
95266d7439eSIoana Ciornei .handle_interrupt = adin_phy_handle_interrupt,
9539fe0b8d6SAlexandru Ardelean .get_sset_count = adin_get_sset_count,
9549fe0b8d6SAlexandru Ardelean .get_strings = adin_get_strings,
9559fe0b8d6SAlexandru Ardelean .get_stats = adin_get_stats,
95649cc4c7dSAlexandru Ardelean .resume = genphy_resume,
95749cc4c7dSAlexandru Ardelean .suspend = genphy_suspend,
9583e32d020SAlexandru Ardelean .read_mmd = adin_read_mmd,
9593e32d020SAlexandru Ardelean .write_mmd = adin_write_mmd,
960f2531d45SAlexandru Ardelean .cable_test_start = adin_cable_test_start,
961f2531d45SAlexandru Ardelean .cable_test_get_status = adin_cable_test_get_status,
9629c102981SAlexandru Ardelean },
9639c102981SAlexandru Ardelean {
9649c102981SAlexandru Ardelean PHY_ID_MATCH_MODEL(PHY_ID_ADIN1300),
9659c102981SAlexandru Ardelean .name = "ADIN1300",
966f2531d45SAlexandru Ardelean .flags = PHY_POLL_CABLE_TEST,
9679fe0b8d6SAlexandru Ardelean .probe = adin_probe,
9689c102981SAlexandru Ardelean .config_init = adin_config_init,
969fa5bd9c5SAlexandru Ardelean .soft_reset = adin_soft_reset,
970b422d1b6SAlexandru Ardelean .config_aneg = adin_config_aneg,
971b422d1b6SAlexandru Ardelean .read_status = adin_read_status,
9722d99b584SAlexandru Ardelean .get_tunable = adin_get_tunable,
9732d99b584SAlexandru Ardelean .set_tunable = adin_set_tunable,
974fb44b8d6SAlexandru Ardelean .config_intr = adin_phy_config_intr,
97566d7439eSIoana Ciornei .handle_interrupt = adin_phy_handle_interrupt,
9769fe0b8d6SAlexandru Ardelean .get_sset_count = adin_get_sset_count,
9779fe0b8d6SAlexandru Ardelean .get_strings = adin_get_strings,
9789fe0b8d6SAlexandru Ardelean .get_stats = adin_get_stats,
97949cc4c7dSAlexandru Ardelean .resume = genphy_resume,
98049cc4c7dSAlexandru Ardelean .suspend = genphy_suspend,
9813e32d020SAlexandru Ardelean .read_mmd = adin_read_mmd,
9823e32d020SAlexandru Ardelean .write_mmd = adin_write_mmd,
983f2531d45SAlexandru Ardelean .cable_test_start = adin_cable_test_start,
984f2531d45SAlexandru Ardelean .cable_test_get_status = adin_cable_test_get_status,
9859c102981SAlexandru Ardelean },
9869c102981SAlexandru Ardelean };
9879c102981SAlexandru Ardelean
9889c102981SAlexandru Ardelean module_phy_driver(adin_driver);
9899c102981SAlexandru Ardelean
9909c102981SAlexandru Ardelean static struct mdio_device_id __maybe_unused adin_tbl[] = {
9919c102981SAlexandru Ardelean { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1200) },
9929c102981SAlexandru Ardelean { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1300) },
9939c102981SAlexandru Ardelean { }
9949c102981SAlexandru Ardelean };
9959c102981SAlexandru Ardelean
9969c102981SAlexandru Ardelean MODULE_DEVICE_TABLE(mdio, adin_tbl);
9979c102981SAlexandru Ardelean MODULE_DESCRIPTION("Analog Devices Industrial Ethernet PHY driver");
9989c102981SAlexandru Ardelean MODULE_LICENSE("GPL");
999