blob: 618e014abd2fad748e14154827dfa1f7c27e0cf6 [file] [log] [blame]
Andrew Lunna2443fd2019-01-21 19:05:50 +01001// SPDX-License-Identifier: GPL-2.0+
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00002/*
3 * drivers/net/phy/at803x.c
4 *
Michael Walle96c36712019-11-06 23:36:16 +01005 * Driver for Qualcomm Atheros AR803x PHY
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00006 *
7 * Author: Matus Ujhelyi <ujhelyi.m@gmail.com>
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00008 */
9
10#include <linux/phy.h>
11#include <linux/module.h>
12#include <linux/string.h>
13#include <linux/netdevice.h>
14#include <linux/etherdevice.h>
Michael Walle6cb75762020-05-13 22:38:07 +020015#include <linux/ethtool_netlink.h>
Daniel Mack13a56b42014-06-18 11:01:43 +020016#include <linux/of_gpio.h>
Michael Walle2f664822019-11-06 23:36:14 +010017#include <linux/bitfield.h>
Daniel Mack13a56b42014-06-18 11:01:43 +020018#include <linux/gpio/consumer.h>
Michael Walle2f664822019-11-06 23:36:14 +010019#include <linux/regulator/of_regulator.h>
20#include <linux/regulator/driver.h>
21#include <linux/regulator/consumer.h>
22#include <dt-bindings/net/qca-ar803x.h>
Matus Ujhelyi0ca71112012-10-14 19:07:16 +000023
Oleksij Rempel7dce80c2020-07-19 10:05:30 +020024#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10
25#define AT803X_SFC_ASSERT_CRS BIT(11)
26#define AT803X_SFC_FORCE_LINK BIT(10)
27#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5)
28#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3
29#define AT803X_SFC_MANUAL_MDIX 0x1
30#define AT803X_SFC_MANUAL_MDI 0x0
31#define AT803X_SFC_SQE_TEST BIT(2)
32#define AT803X_SFC_POLARITY_REVERSAL BIT(1)
33#define AT803X_SFC_DISABLE_JABBER BIT(0)
34
Russell King06d5f342019-10-04 17:06:14 +010035#define AT803X_SPECIFIC_STATUS 0x11
36#define AT803X_SS_SPEED_MASK (3 << 14)
37#define AT803X_SS_SPEED_1000 (2 << 14)
38#define AT803X_SS_SPEED_100 (1 << 14)
39#define AT803X_SS_SPEED_10 (0 << 14)
40#define AT803X_SS_DUPLEX BIT(13)
41#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11)
42#define AT803X_SS_MDIX BIT(6)
43
Matus Ujhelyi0ca71112012-10-14 19:07:16 +000044#define AT803X_INTR_ENABLE 0x12
Martin Blumenstingle6e4a552016-01-15 01:55:24 +010045#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15)
46#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14)
47#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13)
48#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12)
49#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11)
50#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10)
51#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5)
52#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1)
53#define AT803X_INTR_ENABLE_WOL BIT(0)
54
Matus Ujhelyi0ca71112012-10-14 19:07:16 +000055#define AT803X_INTR_STATUS 0x13
Martin Blumenstingla46bd632016-01-15 01:55:23 +010056
Daniel Mack13a56b42014-06-18 11:01:43 +020057#define AT803X_SMART_SPEED 0x14
Michael Wallecde0f4f2020-04-28 23:15:02 +020058#define AT803X_SMART_SPEED_ENABLE BIT(5)
59#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2)
60#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1)
Michael Walle6cb75762020-05-13 22:38:07 +020061#define AT803X_CDT 0x16
62#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8)
63#define AT803X_CDT_ENABLE_TEST BIT(0)
64#define AT803X_CDT_STATUS 0x1c
65#define AT803X_CDT_STATUS_STAT_NORMAL 0
66#define AT803X_CDT_STATUS_STAT_SHORT 1
67#define AT803X_CDT_STATUS_STAT_OPEN 2
68#define AT803X_CDT_STATUS_STAT_FAIL 3
69#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8)
70#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0)
Daniel Mack13a56b42014-06-18 11:01:43 +020071#define AT803X_LED_CONTROL 0x18
Martin Blumenstingla46bd632016-01-15 01:55:23 +010072
Matus Ujhelyi0ca71112012-10-14 19:07:16 +000073#define AT803X_DEVICE_ADDR 0x03
74#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
75#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
76#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
Zefir Kurtisif62265b2016-10-24 12:40:54 +020077#define AT803X_REG_CHIP_CONFIG 0x1f
78#define AT803X_BT_BX_REG_SEL 0x8000
Martin Blumenstingla46bd632016-01-15 01:55:23 +010079
Mugunthan V N1ca6d1b2013-06-03 20:10:06 +000080#define AT803X_DEBUG_ADDR 0x1D
81#define AT803X_DEBUG_DATA 0x1E
Martin Blumenstingla46bd632016-01-15 01:55:23 +010082
Zefir Kurtisif62265b2016-10-24 12:40:54 +020083#define AT803X_MODE_CFG_MASK 0x0F
84#define AT803X_MODE_CFG_SGMII 0x01
85
Ansuel Smithd0e13fd2021-05-14 23:00:14 +020086#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
87#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
Zefir Kurtisif62265b2016-10-24 12:40:54 +020088
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +010089#define AT803X_DEBUG_REG_0 0x00
90#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
Martin Blumenstingla46bd632016-01-15 01:55:23 +010091
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +010092#define AT803X_DEBUG_REG_5 0x05
93#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
Matus Ujhelyi0ca71112012-10-14 19:07:16 +000094
Ansuel Smith272833b2021-05-14 23:00:15 +020095#define AT803X_DEBUG_REG_3C 0x3C
96
97#define AT803X_DEBUG_REG_3D 0x3D
98
Michael Walle2f664822019-11-06 23:36:14 +010099#define AT803X_DEBUG_REG_1F 0x1F
100#define AT803X_DEBUG_PLL_ON BIT(2)
101#define AT803X_DEBUG_RGMII_1V8 BIT(3)
102
Ansuel Smith272833b2021-05-14 23:00:15 +0200103#define MDIO_AZ_DEBUG 0x800D
104
Michael Walle2f664822019-11-06 23:36:14 +0100105/* AT803x supports either the XTAL input pad, an internal PLL or the
106 * DSP as clock reference for the clock output pad. The XTAL reference
107 * is only used for 25 MHz output, all other frequencies need the PLL.
108 * The DSP as a clock reference is used in synchronous ethernet
109 * applications.
110 *
111 * By default the PLL is only enabled if there is a link. Otherwise
112 * the PHY will go into low power state and disabled the PLL. You can
113 * set the PLL_ON bit (see debug register 0x1f) to keep the PLL always
114 * enabled.
115 */
116#define AT803X_MMD7_CLK25M 0x8016
117#define AT803X_CLK_OUT_MASK GENMASK(4, 2)
118#define AT803X_CLK_OUT_25MHZ_XTAL 0
119#define AT803X_CLK_OUT_25MHZ_DSP 1
120#define AT803X_CLK_OUT_50MHZ_PLL 2
121#define AT803X_CLK_OUT_50MHZ_DSP 3
122#define AT803X_CLK_OUT_62_5MHZ_PLL 4
123#define AT803X_CLK_OUT_62_5MHZ_DSP 5
124#define AT803X_CLK_OUT_125MHZ_PLL 6
125#define AT803X_CLK_OUT_125MHZ_DSP 7
126
Michael Walle428061f2019-11-06 23:36:15 +0100127/* The AR8035 has another mask which is compatible with the AR8031/AR8033 mask
128 * but doesn't support choosing between XTAL/PLL and DSP.
Michael Walle2f664822019-11-06 23:36:14 +0100129 */
130#define AT8035_CLK_OUT_MASK GENMASK(4, 3)
131
132#define AT803X_CLK_OUT_STRENGTH_MASK GENMASK(8, 7)
133#define AT803X_CLK_OUT_STRENGTH_FULL 0
134#define AT803X_CLK_OUT_STRENGTH_HALF 1
135#define AT803X_CLK_OUT_STRENGTH_QUARTER 2
136
Ansuel Smithd0e13fd2021-05-14 23:00:14 +0200137#define AT803X_DEFAULT_DOWNSHIFT 5
138#define AT803X_MIN_DOWNSHIFT 2
139#define AT803X_MAX_DOWNSHIFT 9
Michael Wallecde0f4f2020-04-28 23:15:02 +0200140
Russell King390b4ca2021-01-14 10:45:49 +0000141#define AT803X_MMD3_SMARTEEE_CTL1 0x805b
142#define AT803X_MMD3_SMARTEEE_CTL2 0x805c
143#define AT803X_MMD3_SMARTEEE_CTL3 0x805d
144#define AT803X_MMD3_SMARTEEE_CTL3_LPI_EN BIT(8)
145
Ansuel Smithd0e13fd2021-05-14 23:00:14 +0200146#define ATH9331_PHY_ID 0x004dd041
147#define ATH8030_PHY_ID 0x004dd076
148#define ATH8031_PHY_ID 0x004dd074
149#define ATH8032_PHY_ID 0x004dd023
150#define ATH8035_PHY_ID 0x004dd072
Michael Walle0465d8f2020-05-22 11:53:31 +0200151#define AT8030_PHY_ID_MASK 0xffffffef
Daniel Mackbd8ca172014-06-18 11:01:42 +0200152
Ansuel Smithb4df02b2021-09-19 18:28:15 +0200153#define QCA8327_A_PHY_ID 0x004dd033
154#define QCA8327_B_PHY_ID 0x004dd034
Ansuel Smith272833b2021-05-14 23:00:15 +0200155#define QCA8337_PHY_ID 0x004dd036
156#define QCA8K_PHY_ID_MASK 0xffffffff
157
158#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
159
Ansuel Smithd0e13fd2021-05-14 23:00:14 +0200160#define AT803X_PAGE_FIBER 0
161#define AT803X_PAGE_COPPER 1
162
163/* don't turn off internal PLL */
164#define AT803X_KEEP_PLL_ENABLED BIT(0)
165#define AT803X_DISABLE_SMARTEEE BIT(1)
David Bauerc329e5a2021-04-15 03:26:50 +0200166
Michael Walle96c36712019-11-06 23:36:16 +0100167MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver");
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000168MODULE_AUTHOR("Matus Ujhelyi");
169MODULE_LICENSE("GPL");
170
Ansuel Smith272833b2021-05-14 23:00:15 +0200171enum stat_access_type {
172 PHY,
173 MMD
174};
175
176struct at803x_hw_stat {
177 const char *string;
178 u8 reg;
179 u32 mask;
180 enum stat_access_type access_type;
181};
182
183static struct at803x_hw_stat at803x_hw_stats[] = {
184 { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
185 { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
186 { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
187};
188
Michael Walle2f664822019-11-06 23:36:14 +0100189struct at803x_priv {
190 int flags;
Michael Walle2f664822019-11-06 23:36:14 +0100191 u16 clk_25m_reg;
192 u16 clk_25m_mask;
Russell King390b4ca2021-01-14 10:45:49 +0000193 u8 smarteee_lpi_tw_1g;
194 u8 smarteee_lpi_tw_100m;
Michael Walle2f664822019-11-06 23:36:14 +0100195 struct regulator_dev *vddio_rdev;
196 struct regulator_dev *vddh_rdev;
197 struct regulator *vddio;
Ansuel Smith272833b2021-05-14 23:00:15 +0200198 u64 stats[ARRAY_SIZE(at803x_hw_stats)];
Michael Walle2f664822019-11-06 23:36:14 +0100199};
200
Daniel Mack13a56b42014-06-18 11:01:43 +0200201struct at803x_context {
202 u16 bmcr;
203 u16 advertise;
204 u16 control1000;
205 u16 int_enable;
206 u16 smart_speed;
207 u16 led_control;
208};
209
Ansuel Smith272833b2021-05-14 23:00:15 +0200210static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
211{
212 int ret;
213
214 ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
215 if (ret < 0)
216 return ret;
217
218 return phy_write(phydev, AT803X_DEBUG_DATA, data);
219}
220
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100221static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
222{
223 int ret;
224
225 ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
226 if (ret < 0)
227 return ret;
228
229 return phy_read(phydev, AT803X_DEBUG_DATA);
230}
231
232static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
233 u16 clear, u16 set)
234{
235 u16 val;
236 int ret;
237
238 ret = at803x_debug_reg_read(phydev, reg);
239 if (ret < 0)
240 return ret;
241
242 val = ret & 0xffff;
243 val &= ~clear;
244 val |= set;
245
246 return phy_write(phydev, AT803X_DEBUG_DATA, val);
247}
248
David Bauerc329e5a2021-04-15 03:26:50 +0200249static int at803x_write_page(struct phy_device *phydev, int page)
250{
251 int mask;
252 int set;
253
254 if (page == AT803X_PAGE_COPPER) {
255 set = AT803X_BT_BX_REG_SEL;
256 mask = 0;
257 } else {
258 set = 0;
259 mask = AT803X_BT_BX_REG_SEL;
260 }
261
262 return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set);
263}
264
265static int at803x_read_page(struct phy_device *phydev)
266{
267 int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG);
268
269 if (ccr < 0)
270 return ccr;
271
272 if (ccr & AT803X_BT_BX_REG_SEL)
273 return AT803X_PAGE_COPPER;
274
275 return AT803X_PAGE_FIBER;
276}
277
Vinod Koul6d4cd042019-02-21 15:53:15 +0530278static int at803x_enable_rx_delay(struct phy_device *phydev)
279{
280 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
281 AT803X_DEBUG_RX_CLK_DLY_EN);
282}
283
284static int at803x_enable_tx_delay(struct phy_device *phydev)
285{
286 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
287 AT803X_DEBUG_TX_CLK_DLY_EN);
288}
289
Vinod Koul43f2ebd2019-02-21 15:53:14 +0530290static int at803x_disable_rx_delay(struct phy_device *phydev)
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100291{
Vinod Koulcd28d1d2019-01-21 14:43:17 +0530292 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
293 AT803X_DEBUG_RX_CLK_DLY_EN, 0);
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100294}
295
Vinod Koul43f2ebd2019-02-21 15:53:14 +0530296static int at803x_disable_tx_delay(struct phy_device *phydev)
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100297{
Vinod Koulcd28d1d2019-01-21 14:43:17 +0530298 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5,
299 AT803X_DEBUG_TX_CLK_DLY_EN, 0);
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100300}
301
Daniel Mack13a56b42014-06-18 11:01:43 +0200302/* save relevant PHY registers to private copy */
303static void at803x_context_save(struct phy_device *phydev,
304 struct at803x_context *context)
305{
306 context->bmcr = phy_read(phydev, MII_BMCR);
307 context->advertise = phy_read(phydev, MII_ADVERTISE);
308 context->control1000 = phy_read(phydev, MII_CTRL1000);
309 context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE);
310 context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED);
311 context->led_control = phy_read(phydev, AT803X_LED_CONTROL);
312}
313
314/* restore relevant PHY registers from private copy */
315static void at803x_context_restore(struct phy_device *phydev,
316 const struct at803x_context *context)
317{
318 phy_write(phydev, MII_BMCR, context->bmcr);
319 phy_write(phydev, MII_ADVERTISE, context->advertise);
320 phy_write(phydev, MII_CTRL1000, context->control1000);
321 phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable);
322 phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed);
323 phy_write(phydev, AT803X_LED_CONTROL, context->led_control);
324}
325
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000326static int at803x_set_wol(struct phy_device *phydev,
327 struct ethtool_wolinfo *wol)
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000328{
329 struct net_device *ndev = phydev->attached_dev;
330 const u8 *mac;
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000331 int ret;
332 u32 value;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000333 unsigned int i, offsets[] = {
334 AT803X_LOC_MAC_ADDR_32_47_OFFSET,
335 AT803X_LOC_MAC_ADDR_16_31_OFFSET,
336 AT803X_LOC_MAC_ADDR_0_15_OFFSET,
337 };
338
339 if (!ndev)
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000340 return -ENODEV;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000341
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000342 if (wol->wolopts & WAKE_MAGIC) {
343 mac = (const u8 *) ndev->dev_addr;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000344
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000345 if (!is_valid_ether_addr(mac))
Dan Murphyfc755682017-10-10 12:42:56 -0500346 return -EINVAL;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000347
Carlo Caione0e021392019-01-25 12:35:10 +0000348 for (i = 0; i < 3; i++)
349 phy_write_mmd(phydev, AT803X_DEVICE_ADDR, offsets[i],
350 mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000351
352 value = phy_read(phydev, AT803X_INTR_ENABLE);
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100353 value |= AT803X_INTR_ENABLE_WOL;
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000354 ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
355 if (ret)
356 return ret;
357 value = phy_read(phydev, AT803X_INTR_STATUS);
358 } else {
359 value = phy_read(phydev, AT803X_INTR_ENABLE);
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100360 value &= (~AT803X_INTR_ENABLE_WOL);
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000361 ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
362 if (ret)
363 return ret;
364 value = phy_read(phydev, AT803X_INTR_STATUS);
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000365 }
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000366
367 return ret;
368}
369
370static void at803x_get_wol(struct phy_device *phydev,
371 struct ethtool_wolinfo *wol)
372{
373 u32 value;
374
375 wol->supported = WAKE_MAGIC;
376 wol->wolopts = 0;
377
378 value = phy_read(phydev, AT803X_INTR_ENABLE);
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100379 if (value & AT803X_INTR_ENABLE_WOL)
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000380 wol->wolopts |= WAKE_MAGIC;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000381}
382
Ansuel Smith272833b2021-05-14 23:00:15 +0200383static int at803x_get_sset_count(struct phy_device *phydev)
384{
385 return ARRAY_SIZE(at803x_hw_stats);
386}
387
388static void at803x_get_strings(struct phy_device *phydev, u8 *data)
389{
390 int i;
391
392 for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) {
393 strscpy(data + i * ETH_GSTRING_LEN,
394 at803x_hw_stats[i].string, ETH_GSTRING_LEN);
395 }
396}
397
398static u64 at803x_get_stat(struct phy_device *phydev, int i)
399{
400 struct at803x_hw_stat stat = at803x_hw_stats[i];
401 struct at803x_priv *priv = phydev->priv;
402 int val;
403 u64 ret;
404
405 if (stat.access_type == MMD)
406 val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
407 else
408 val = phy_read(phydev, stat.reg);
409
410 if (val < 0) {
411 ret = U64_MAX;
412 } else {
413 val = val & stat.mask;
414 priv->stats[i] += val;
415 ret = priv->stats[i];
416 }
417
418 return ret;
419}
420
421static void at803x_get_stats(struct phy_device *phydev,
422 struct ethtool_stats *stats, u64 *data)
423{
424 int i;
425
426 for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++)
427 data[i] = at803x_get_stat(phydev, i);
428}
429
Daniel Mack6229ed12013-09-21 16:53:02 +0200430static int at803x_suspend(struct phy_device *phydev)
431{
432 int value;
433 int wol_enabled;
434
Daniel Mack6229ed12013-09-21 16:53:02 +0200435 value = phy_read(phydev, AT803X_INTR_ENABLE);
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100436 wol_enabled = value & AT803X_INTR_ENABLE_WOL;
Daniel Mack6229ed12013-09-21 16:53:02 +0200437
Daniel Mack6229ed12013-09-21 16:53:02 +0200438 if (wol_enabled)
Russell Kingfea23fb2018-01-02 10:58:58 +0000439 value = BMCR_ISOLATE;
Daniel Mack6229ed12013-09-21 16:53:02 +0200440 else
Russell Kingfea23fb2018-01-02 10:58:58 +0000441 value = BMCR_PDOWN;
Daniel Mack6229ed12013-09-21 16:53:02 +0200442
Russell Kingfea23fb2018-01-02 10:58:58 +0000443 phy_modify(phydev, MII_BMCR, 0, value);
Daniel Mack6229ed12013-09-21 16:53:02 +0200444
445 return 0;
446}
447
448static int at803x_resume(struct phy_device *phydev)
449{
Russell Kingf1028522018-01-05 16:07:10 +0000450 return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
Daniel Mack6229ed12013-09-21 16:53:02 +0200451}
452
Michael Walle2f664822019-11-06 23:36:14 +0100453static int at803x_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
454 unsigned int selector)
455{
456 struct phy_device *phydev = rdev_get_drvdata(rdev);
457
458 if (selector)
459 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
460 0, AT803X_DEBUG_RGMII_1V8);
461 else
462 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
463 AT803X_DEBUG_RGMII_1V8, 0);
464}
465
466static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
467{
468 struct phy_device *phydev = rdev_get_drvdata(rdev);
469 int val;
470
471 val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
472 if (val < 0)
473 return val;
474
475 return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
476}
477
Rikard Falkeborn3faaf532020-08-27 00:56:06 +0200478static const struct regulator_ops vddio_regulator_ops = {
Michael Walle2f664822019-11-06 23:36:14 +0100479 .list_voltage = regulator_list_voltage_table,
480 .set_voltage_sel = at803x_rgmii_reg_set_voltage_sel,
481 .get_voltage_sel = at803x_rgmii_reg_get_voltage_sel,
482};
483
484static const unsigned int vddio_voltage_table[] = {
485 1500000,
486 1800000,
487};
488
489static const struct regulator_desc vddio_desc = {
490 .name = "vddio",
491 .of_match = of_match_ptr("vddio-regulator"),
492 .n_voltages = ARRAY_SIZE(vddio_voltage_table),
493 .volt_table = vddio_voltage_table,
494 .ops = &vddio_regulator_ops,
495 .type = REGULATOR_VOLTAGE,
496 .owner = THIS_MODULE,
497};
498
Rikard Falkeborn3faaf532020-08-27 00:56:06 +0200499static const struct regulator_ops vddh_regulator_ops = {
Michael Walle2f664822019-11-06 23:36:14 +0100500};
501
502static const struct regulator_desc vddh_desc = {
503 .name = "vddh",
504 .of_match = of_match_ptr("vddh-regulator"),
505 .n_voltages = 1,
506 .fixed_uV = 2500000,
507 .ops = &vddh_regulator_ops,
508 .type = REGULATOR_VOLTAGE,
509 .owner = THIS_MODULE,
510};
511
512static int at8031_register_regulators(struct phy_device *phydev)
513{
514 struct at803x_priv *priv = phydev->priv;
515 struct device *dev = &phydev->mdio.dev;
516 struct regulator_config config = { };
517
518 config.dev = dev;
519 config.driver_data = phydev;
520
521 priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
522 if (IS_ERR(priv->vddio_rdev)) {
523 phydev_err(phydev, "failed to register VDDIO regulator\n");
524 return PTR_ERR(priv->vddio_rdev);
525 }
526
527 priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
528 if (IS_ERR(priv->vddh_rdev)) {
529 phydev_err(phydev, "failed to register VDDH regulator\n");
530 return PTR_ERR(priv->vddh_rdev);
531 }
532
533 return 0;
534}
535
Michael Walle2f664822019-11-06 23:36:14 +0100536static int at803x_parse_dt(struct phy_device *phydev)
537{
538 struct device_node *node = phydev->mdio.dev.of_node;
539 struct at803x_priv *priv = phydev->priv;
Russell King390b4ca2021-01-14 10:45:49 +0000540 u32 freq, strength, tw;
Andrew Lunn3f2edd32020-07-07 03:49:33 +0200541 unsigned int sel;
Michael Walle2f664822019-11-06 23:36:14 +0100542 int ret;
543
544 if (!IS_ENABLED(CONFIG_OF_MDIO))
545 return 0;
546
Russell King390b4ca2021-01-14 10:45:49 +0000547 if (of_property_read_bool(node, "qca,disable-smarteee"))
548 priv->flags |= AT803X_DISABLE_SMARTEEE;
549
550 if (!of_property_read_u32(node, "qca,smarteee-tw-us-1g", &tw)) {
551 if (!tw || tw > 255) {
552 phydev_err(phydev, "invalid qca,smarteee-tw-us-1g\n");
553 return -EINVAL;
554 }
555 priv->smarteee_lpi_tw_1g = tw;
556 }
557
558 if (!of_property_read_u32(node, "qca,smarteee-tw-us-100m", &tw)) {
559 if (!tw || tw > 255) {
560 phydev_err(phydev, "invalid qca,smarteee-tw-us-100m\n");
561 return -EINVAL;
562 }
563 priv->smarteee_lpi_tw_100m = tw;
564 }
565
Michael Walle2f664822019-11-06 23:36:14 +0100566 ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq);
567 if (!ret) {
Michael Walle2f664822019-11-06 23:36:14 +0100568 switch (freq) {
569 case 25000000:
570 sel = AT803X_CLK_OUT_25MHZ_XTAL;
571 break;
572 case 50000000:
573 sel = AT803X_CLK_OUT_50MHZ_PLL;
574 break;
575 case 62500000:
576 sel = AT803X_CLK_OUT_62_5MHZ_PLL;
577 break;
578 case 125000000:
579 sel = AT803X_CLK_OUT_125MHZ_PLL;
580 break;
581 default:
582 phydev_err(phydev, "invalid qca,clk-out-frequency\n");
583 return -EINVAL;
584 }
585
Andrew Lunn3f2edd32020-07-07 03:49:33 +0200586 priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel);
587 priv->clk_25m_mask |= AT803X_CLK_OUT_MASK;
Michael Walle2f664822019-11-06 23:36:14 +0100588
589 /* Fixup for the AR8030/AR8035. This chip has another mask and
590 * doesn't support the DSP reference. Eg. the lowest bit of the
591 * mask. The upper two bits select the same frequencies. Mask
592 * the lowest bit here.
593 *
594 * Warning:
595 * There was no datasheet for the AR8030 available so this is
596 * just a guess. But the AR8035 is listed as pin compatible
597 * to the AR8030 so there might be a good chance it works on
598 * the AR8030 too.
599 */
Russell King8887ca52021-07-20 14:33:49 +0100600 if (phydev->drv->phy_id == ATH8030_PHY_ID ||
601 phydev->drv->phy_id == ATH8035_PHY_ID) {
Oleksij Rempelb1f4c202020-04-01 11:57:32 +0200602 priv->clk_25m_reg &= AT8035_CLK_OUT_MASK;
603 priv->clk_25m_mask &= AT8035_CLK_OUT_MASK;
Michael Walle2f664822019-11-06 23:36:14 +0100604 }
605 }
606
607 ret = of_property_read_u32(node, "qca,clk-out-strength", &strength);
608 if (!ret) {
609 priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK;
610 switch (strength) {
611 case AR803X_STRENGTH_FULL:
612 priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL;
613 break;
614 case AR803X_STRENGTH_HALF:
615 priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF;
616 break;
617 case AR803X_STRENGTH_QUARTER:
618 priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER;
619 break;
620 default:
621 phydev_err(phydev, "invalid qca,clk-out-strength\n");
622 return -EINVAL;
623 }
624 }
625
Michael Walle428061f2019-11-06 23:36:15 +0100626 /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
627 * options.
628 */
Russell King8887ca52021-07-20 14:33:49 +0100629 if (phydev->drv->phy_id == ATH8031_PHY_ID) {
Michael Walle2f664822019-11-06 23:36:14 +0100630 if (of_property_read_bool(node, "qca,keep-pll-enabled"))
631 priv->flags |= AT803X_KEEP_PLL_ENABLED;
632
633 ret = at8031_register_regulators(phydev);
634 if (ret < 0)
635 return ret;
636
637 priv->vddio = devm_regulator_get_optional(&phydev->mdio.dev,
638 "vddio");
639 if (IS_ERR(priv->vddio)) {
640 phydev_err(phydev, "failed to get VDDIO regulator\n");
641 return PTR_ERR(priv->vddio);
642 }
Michael Walle2f664822019-11-06 23:36:14 +0100643 }
644
645 return 0;
646}
647
648static int at803x_probe(struct phy_device *phydev)
649{
650 struct device *dev = &phydev->mdio.dev;
651 struct at803x_priv *priv;
David Bauerc329e5a2021-04-15 03:26:50 +0200652 int ret;
Michael Walle2f664822019-11-06 23:36:14 +0100653
654 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
655 if (!priv)
656 return -ENOMEM;
657
658 phydev->priv = priv;
659
David Bauerc329e5a2021-04-15 03:26:50 +0200660 ret = at803x_parse_dt(phydev);
661 if (ret)
662 return ret;
663
Michael Walle8f7e8762021-04-20 12:29:29 +0200664 if (priv->vddio) {
665 ret = regulator_enable(priv->vddio);
666 if (ret < 0)
667 return ret;
668 }
669
David Bauerc329e5a2021-04-15 03:26:50 +0200670 /* Some bootloaders leave the fiber page selected.
671 * Switch to the copper page, as otherwise we read
672 * the PHY capabilities from the fiber side.
673 */
Russell King8887ca52021-07-20 14:33:49 +0100674 if (phydev->drv->phy_id == ATH8031_PHY_ID) {
Michael Walle8f7e8762021-04-20 12:29:29 +0200675 phy_lock_mdio_bus(phydev);
676 ret = at803x_write_page(phydev, AT803X_PAGE_COPPER);
677 phy_unlock_mdio_bus(phydev);
678 if (ret)
679 goto err;
David Bauerc329e5a2021-04-15 03:26:50 +0200680 }
681
Michael Walle8f7e8762021-04-20 12:29:29 +0200682 return 0;
683
684err:
685 if (priv->vddio)
686 regulator_disable(priv->vddio);
687
David Bauerc329e5a2021-04-15 03:26:50 +0200688 return ret;
Michael Walle2f664822019-11-06 23:36:14 +0100689}
690
Michael Walle2318ca82020-01-30 18:54:02 +0100691static void at803x_remove(struct phy_device *phydev)
692{
693 struct at803x_priv *priv = phydev->priv;
694
695 if (priv->vddio)
696 regulator_disable(priv->vddio);
697}
698
David Bauerb8561502021-06-27 12:16:07 +0200699static int at803x_get_features(struct phy_device *phydev)
700{
701 int err;
702
703 err = genphy_read_abilities(phydev);
704 if (err)
705 return err;
706
Vladimir Olteanf5621a02021-07-20 20:24:33 +0300707 if (phydev->drv->phy_id != ATH8031_PHY_ID)
David Bauerb8561502021-06-27 12:16:07 +0200708 return 0;
709
710 /* AR8031/AR8033 have different status registers
711 * for copper and fiber operation. However, the
712 * extended status register is the same for both
713 * operation modes.
714 *
715 * As a result of that, ESTATUS_1000_XFULL is set
716 * to 1 even when operating in copper TP mode.
717 *
718 * Remove this mode from the supported link modes,
719 * as this driver currently only supports copper
720 * operation.
721 */
722 linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
723 phydev->supported);
724 return 0;
725}
726
Russell King390b4ca2021-01-14 10:45:49 +0000727static int at803x_smarteee_config(struct phy_device *phydev)
728{
729 struct at803x_priv *priv = phydev->priv;
730 u16 mask = 0, val = 0;
731 int ret;
732
733 if (priv->flags & AT803X_DISABLE_SMARTEEE)
734 return phy_modify_mmd(phydev, MDIO_MMD_PCS,
735 AT803X_MMD3_SMARTEEE_CTL3,
736 AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, 0);
737
738 if (priv->smarteee_lpi_tw_1g) {
739 mask |= 0xff00;
740 val |= priv->smarteee_lpi_tw_1g << 8;
741 }
742 if (priv->smarteee_lpi_tw_100m) {
743 mask |= 0x00ff;
744 val |= priv->smarteee_lpi_tw_100m;
745 }
746 if (!mask)
747 return 0;
748
749 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL1,
750 mask, val);
751 if (ret)
752 return ret;
753
754 return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3,
755 AT803X_MMD3_SMARTEEE_CTL3_LPI_EN,
756 AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
757}
758
Michael Walle2f664822019-11-06 23:36:14 +0100759static int at803x_clk_out_config(struct phy_device *phydev)
760{
761 struct at803x_priv *priv = phydev->priv;
Michael Walle2f664822019-11-06 23:36:14 +0100762
763 if (!priv->clk_25m_mask)
764 return 0;
765
Russell Kinga45c1c12021-01-10 14:54:36 +0000766 return phy_modify_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M,
767 priv->clk_25m_mask, priv->clk_25m_reg);
Michael Walle2f664822019-11-06 23:36:14 +0100768}
769
770static int at8031_pll_config(struct phy_device *phydev)
771{
772 struct at803x_priv *priv = phydev->priv;
773
774 /* The default after hardware reset is PLL OFF. After a soft reset, the
775 * values are retained.
776 */
777 if (priv->flags & AT803X_KEEP_PLL_ENABLED)
778 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
779 0, AT803X_DEBUG_PLL_ON);
780 else
781 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
782 AT803X_DEBUG_PLL_ON, 0);
783}
784
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000785static int at803x_config_init(struct phy_device *phydev)
786{
Mugunthan V N1ca6d1b2013-06-03 20:10:06 +0000787 int ret;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000788
Vinod Koul6d4cd042019-02-21 15:53:15 +0530789 /* The RX and TX delay default is:
790 * after HW reset: RX delay enabled and TX delay disabled
791 * after SW reset: RX delay enabled, while TX delay retains the
792 * value before reset.
Vinod Koul6d4cd042019-02-21 15:53:15 +0530793 */
Vinod Koul6d4cd042019-02-21 15:53:15 +0530794 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
André Draszikbb0ce4c2019-08-09 12:20:25 +0100795 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
Vinod Koul6d4cd042019-02-21 15:53:15 +0530796 ret = at803x_enable_rx_delay(phydev);
André Draszikbb0ce4c2019-08-09 12:20:25 +0100797 else
798 ret = at803x_disable_rx_delay(phydev);
799 if (ret < 0)
800 return ret;
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100801
Vinod Koul6d4cd042019-02-21 15:53:15 +0530802 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
André Draszikbb0ce4c2019-08-09 12:20:25 +0100803 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
Vinod Koul6d4cd042019-02-21 15:53:15 +0530804 ret = at803x_enable_tx_delay(phydev);
André Draszikbb0ce4c2019-08-09 12:20:25 +0100805 else
806 ret = at803x_disable_tx_delay(phydev);
Michael Walle2f664822019-11-06 23:36:14 +0100807 if (ret < 0)
808 return ret;
Mugunthan V N1ca6d1b2013-06-03 20:10:06 +0000809
Russell King390b4ca2021-01-14 10:45:49 +0000810 ret = at803x_smarteee_config(phydev);
811 if (ret < 0)
812 return ret;
813
Michael Walle2f664822019-11-06 23:36:14 +0100814 ret = at803x_clk_out_config(phydev);
815 if (ret < 0)
816 return ret;
817
Russell King8887ca52021-07-20 14:33:49 +0100818 if (phydev->drv->phy_id == ATH8031_PHY_ID) {
Michael Walle2f664822019-11-06 23:36:14 +0100819 ret = at8031_pll_config(phydev);
820 if (ret < 0)
821 return ret;
822 }
823
Russell King3c51fa52021-01-12 22:59:43 +0000824 /* Ar803x extended next page bit is enabled by default. Cisco
825 * multigig switches read this bit and attempt to negotiate 10Gbps
826 * rates even if the next page bit is disabled. This is incorrect
827 * behaviour but we still need to accommodate it. XNP is only needed
828 * for 10Gbps support, so disable XNP.
829 */
830 return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0);
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000831}
832
Zhao Qiang77a99392014-03-28 15:39:41 +0800833static int at803x_ack_interrupt(struct phy_device *phydev)
834{
835 int err;
836
Martin Blumenstingla46bd632016-01-15 01:55:23 +0100837 err = phy_read(phydev, AT803X_INTR_STATUS);
Zhao Qiang77a99392014-03-28 15:39:41 +0800838
839 return (err < 0) ? err : 0;
840}
841
842static int at803x_config_intr(struct phy_device *phydev)
843{
844 int err;
845 int value;
846
Martin Blumenstingla46bd632016-01-15 01:55:23 +0100847 value = phy_read(phydev, AT803X_INTR_ENABLE);
Zhao Qiang77a99392014-03-28 15:39:41 +0800848
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100849 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
Ioana Ciorneia3417882020-11-01 14:51:00 +0200850 /* Clear any pending interrupts */
851 err = at803x_ack_interrupt(phydev);
852 if (err)
853 return err;
854
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100855 value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
856 value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
857 value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
858 value |= AT803X_INTR_ENABLE_LINK_FAIL;
859 value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
860
861 err = phy_write(phydev, AT803X_INTR_ENABLE, value);
Ioana Ciorneia3417882020-11-01 14:51:00 +0200862 } else {
Martin Blumenstingla46bd632016-01-15 01:55:23 +0100863 err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
Ioana Ciorneia3417882020-11-01 14:51:00 +0200864 if (err)
865 return err;
866
867 /* Clear any pending interrupts */
868 err = at803x_ack_interrupt(phydev);
869 }
Zhao Qiang77a99392014-03-28 15:39:41 +0800870
871 return err;
872}
873
Ioana Ciornei29773092020-11-01 14:50:59 +0200874static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev)
875{
876 int irq_status, int_enabled;
877
878 irq_status = phy_read(phydev, AT803X_INTR_STATUS);
879 if (irq_status < 0) {
880 phy_error(phydev);
881 return IRQ_NONE;
882 }
883
884 /* Read the current enabled interrupts */
885 int_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
886 if (int_enabled < 0) {
887 phy_error(phydev);
888 return IRQ_NONE;
889 }
890
891 /* See if this was one of our enabled interrupts */
892 if (!(irq_status & int_enabled))
893 return IRQ_NONE;
894
895 phy_trigger_machine(phydev);
896
897 return IRQ_HANDLED;
898}
899
Daniel Mack13a56b42014-06-18 11:01:43 +0200900static void at803x_link_change_notify(struct phy_device *phydev)
901{
Daniel Mack13a56b42014-06-18 11:01:43 +0200902 /*
903 * Conduct a hardware reset for AT8030 every time a link loss is
904 * signalled. This is necessary to circumvent a hardware bug that
905 * occurs when the cable is unplugged while TX packets are pending
906 * in the FIFO. In such cases, the FIFO enters an error mode it
907 * cannot recover from by software.
908 */
David Bauer6110ed22019-04-17 23:59:22 +0200909 if (phydev->state == PHY_NOLINK && phydev->mdio.reset_gpio) {
Heiner Kallweit5c5f6262019-03-19 19:56:51 +0100910 struct at803x_context context;
Daniel Mack13a56b42014-06-18 11:01:43 +0200911
Heiner Kallweit5c5f6262019-03-19 19:56:51 +0100912 at803x_context_save(phydev, &context);
Daniel Mack13a56b42014-06-18 11:01:43 +0200913
Heiner Kallweit5c5f6262019-03-19 19:56:51 +0100914 phy_device_reset(phydev, 1);
915 msleep(1);
916 phy_device_reset(phydev, 0);
917 msleep(1);
Daniel Mack13a56b42014-06-18 11:01:43 +0200918
Heiner Kallweit5c5f6262019-03-19 19:56:51 +0100919 at803x_context_restore(phydev, &context);
Daniel Mack13a56b42014-06-18 11:01:43 +0200920
Heiner Kallweit5c5f6262019-03-19 19:56:51 +0100921 phydev_dbg(phydev, "%s(): phy was reset\n", __func__);
Daniel Mack13a56b42014-06-18 11:01:43 +0200922 }
923}
924
Russell King06d5f342019-10-04 17:06:14 +0100925static int at803x_read_status(struct phy_device *phydev)
926{
927 int ss, err, old_link = phydev->link;
928
929 /* Update the link, but return if there was an error */
930 err = genphy_update_link(phydev);
931 if (err)
932 return err;
933
934 /* why bother the PHY if nothing can have changed */
935 if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
936 return 0;
937
938 phydev->speed = SPEED_UNKNOWN;
939 phydev->duplex = DUPLEX_UNKNOWN;
940 phydev->pause = 0;
941 phydev->asym_pause = 0;
942
943 err = genphy_read_lpa(phydev);
944 if (err < 0)
945 return err;
946
947 /* Read the AT8035 PHY-Specific Status register, which indicates the
948 * speed and duplex that the PHY is actually using, irrespective of
949 * whether we are in autoneg mode or not.
950 */
951 ss = phy_read(phydev, AT803X_SPECIFIC_STATUS);
952 if (ss < 0)
953 return ss;
954
955 if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
Oleksij Rempel7dce80c2020-07-19 10:05:30 +0200956 int sfc;
957
958 sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
959 if (sfc < 0)
960 return sfc;
961
Russell King06d5f342019-10-04 17:06:14 +0100962 switch (ss & AT803X_SS_SPEED_MASK) {
963 case AT803X_SS_SPEED_10:
964 phydev->speed = SPEED_10;
965 break;
966 case AT803X_SS_SPEED_100:
967 phydev->speed = SPEED_100;
968 break;
969 case AT803X_SS_SPEED_1000:
970 phydev->speed = SPEED_1000;
971 break;
972 }
973 if (ss & AT803X_SS_DUPLEX)
974 phydev->duplex = DUPLEX_FULL;
975 else
976 phydev->duplex = DUPLEX_HALF;
Oleksij Rempel7dce80c2020-07-19 10:05:30 +0200977
Russell King06d5f342019-10-04 17:06:14 +0100978 if (ss & AT803X_SS_MDIX)
979 phydev->mdix = ETH_TP_MDI_X;
980 else
981 phydev->mdix = ETH_TP_MDI;
Oleksij Rempel7dce80c2020-07-19 10:05:30 +0200982
983 switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) {
984 case AT803X_SFC_MANUAL_MDI:
985 phydev->mdix_ctrl = ETH_TP_MDI;
986 break;
987 case AT803X_SFC_MANUAL_MDIX:
988 phydev->mdix_ctrl = ETH_TP_MDI_X;
989 break;
990 case AT803X_SFC_AUTOMATIC_CROSSOVER:
991 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
992 break;
993 }
Russell King06d5f342019-10-04 17:06:14 +0100994 }
995
996 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
997 phy_resolve_aneg_pause(phydev);
998
999 return 0;
1000}
1001
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001002static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl)
1003{
1004 u16 val;
1005
1006 switch (ctrl) {
1007 case ETH_TP_MDI:
1008 val = AT803X_SFC_MANUAL_MDI;
1009 break;
1010 case ETH_TP_MDI_X:
1011 val = AT803X_SFC_MANUAL_MDIX;
1012 break;
1013 case ETH_TP_MDI_AUTO:
1014 val = AT803X_SFC_AUTOMATIC_CROSSOVER;
1015 break;
1016 default:
1017 return 0;
1018 }
1019
1020 return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL,
1021 AT803X_SFC_MDI_CROSSOVER_MODE_M,
1022 FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
1023}
1024
1025static int at803x_config_aneg(struct phy_device *phydev)
1026{
1027 int ret;
1028
1029 ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
1030 if (ret < 0)
1031 return ret;
1032
1033 /* Changes of the midx bits are disruptive to the normal operation;
1034 * therefore any changes to these registers must be followed by a
1035 * software reset to take effect.
1036 */
1037 if (ret == 1) {
1038 ret = genphy_soft_reset(phydev);
1039 if (ret < 0)
1040 return ret;
1041 }
1042
1043 return genphy_config_aneg(phydev);
1044}
1045
Michael Wallecde0f4f2020-04-28 23:15:02 +02001046static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
1047{
1048 int val;
1049
1050 val = phy_read(phydev, AT803X_SMART_SPEED);
1051 if (val < 0)
1052 return val;
1053
1054 if (val & AT803X_SMART_SPEED_ENABLE)
1055 *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2;
1056 else
1057 *d = DOWNSHIFT_DEV_DISABLE;
1058
1059 return 0;
1060}
1061
1062static int at803x_set_downshift(struct phy_device *phydev, u8 cnt)
1063{
1064 u16 mask, set;
1065 int ret;
1066
1067 switch (cnt) {
1068 case DOWNSHIFT_DEV_DEFAULT_COUNT:
1069 cnt = AT803X_DEFAULT_DOWNSHIFT;
1070 fallthrough;
1071 case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT:
1072 set = AT803X_SMART_SPEED_ENABLE |
1073 AT803X_SMART_SPEED_BYPASS_TIMER |
1074 FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2);
1075 mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK;
1076 break;
1077 case DOWNSHIFT_DEV_DISABLE:
1078 set = 0;
1079 mask = AT803X_SMART_SPEED_ENABLE |
1080 AT803X_SMART_SPEED_BYPASS_TIMER;
1081 break;
1082 default:
1083 return -EINVAL;
1084 }
1085
1086 ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set);
1087
1088 /* After changing the smart speed settings, we need to perform a
1089 * software reset, use phy_init_hw() to make sure we set the
1090 * reapply any values which might got lost during software reset.
1091 */
1092 if (ret == 1)
1093 ret = phy_init_hw(phydev);
1094
1095 return ret;
1096}
1097
1098static int at803x_get_tunable(struct phy_device *phydev,
1099 struct ethtool_tunable *tuna, void *data)
1100{
1101 switch (tuna->id) {
1102 case ETHTOOL_PHY_DOWNSHIFT:
1103 return at803x_get_downshift(phydev, data);
1104 default:
1105 return -EOPNOTSUPP;
1106 }
1107}
1108
1109static int at803x_set_tunable(struct phy_device *phydev,
1110 struct ethtool_tunable *tuna, const void *data)
1111{
1112 switch (tuna->id) {
1113 case ETHTOOL_PHY_DOWNSHIFT:
1114 return at803x_set_downshift(phydev, *(const u8 *)data);
1115 default:
1116 return -EOPNOTSUPP;
1117 }
1118}
1119
Michael Walle6cb75762020-05-13 22:38:07 +02001120static int at803x_cable_test_result_trans(u16 status)
1121{
1122 switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
1123 case AT803X_CDT_STATUS_STAT_NORMAL:
1124 return ETHTOOL_A_CABLE_RESULT_CODE_OK;
1125 case AT803X_CDT_STATUS_STAT_SHORT:
1126 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
1127 case AT803X_CDT_STATUS_STAT_OPEN:
1128 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
1129 case AT803X_CDT_STATUS_STAT_FAIL:
1130 default:
1131 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
1132 }
1133}
1134
1135static bool at803x_cdt_test_failed(u16 status)
1136{
1137 return FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status) ==
1138 AT803X_CDT_STATUS_STAT_FAIL;
1139}
1140
1141static bool at803x_cdt_fault_length_valid(u16 status)
1142{
1143 switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
1144 case AT803X_CDT_STATUS_STAT_OPEN:
1145 case AT803X_CDT_STATUS_STAT_SHORT:
1146 return true;
1147 }
1148 return false;
1149}
1150
1151static int at803x_cdt_fault_length(u16 status)
1152{
1153 int dt;
1154
1155 /* According to the datasheet the distance to the fault is
1156 * DELTA_TIME * 0.824 meters.
1157 *
1158 * The author suspect the correct formula is:
1159 *
1160 * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2
1161 *
1162 * where c is the speed of light, VF is the velocity factor of
1163 * the twisted pair cable, 125MHz the counter frequency and
1164 * we need to divide by 2 because the hardware will measure the
1165 * round trip time to the fault and back to the PHY.
1166 *
1167 * With a VF of 0.69 we get the factor 0.824 mentioned in the
1168 * datasheet.
1169 */
1170 dt = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, status);
1171
1172 return (dt * 824) / 10;
1173}
1174
1175static int at803x_cdt_start(struct phy_device *phydev, int pair)
1176{
1177 u16 cdt;
1178
1179 cdt = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) |
1180 AT803X_CDT_ENABLE_TEST;
1181
1182 return phy_write(phydev, AT803X_CDT, cdt);
1183}
1184
1185static int at803x_cdt_wait_for_completion(struct phy_device *phydev)
1186{
1187 int val, ret;
1188
1189 /* One test run takes about 25ms */
1190 ret = phy_read_poll_timeout(phydev, AT803X_CDT, val,
1191 !(val & AT803X_CDT_ENABLE_TEST),
1192 30000, 100000, true);
1193
1194 return ret < 0 ? ret : 0;
1195}
1196
1197static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair)
1198{
1199 static const int ethtool_pair[] = {
1200 ETHTOOL_A_CABLE_PAIR_A,
1201 ETHTOOL_A_CABLE_PAIR_B,
1202 ETHTOOL_A_CABLE_PAIR_C,
1203 ETHTOOL_A_CABLE_PAIR_D,
1204 };
1205 int ret, val;
1206
1207 ret = at803x_cdt_start(phydev, pair);
1208 if (ret)
1209 return ret;
1210
1211 ret = at803x_cdt_wait_for_completion(phydev);
1212 if (ret)
1213 return ret;
1214
1215 val = phy_read(phydev, AT803X_CDT_STATUS);
1216 if (val < 0)
1217 return val;
1218
1219 if (at803x_cdt_test_failed(val))
1220 return 0;
1221
1222 ethnl_cable_test_result(phydev, ethtool_pair[pair],
1223 at803x_cable_test_result_trans(val));
1224
1225 if (at803x_cdt_fault_length_valid(val))
1226 ethnl_cable_test_fault_length(phydev, ethtool_pair[pair],
1227 at803x_cdt_fault_length(val));
1228
1229 return 1;
1230}
1231
1232static int at803x_cable_test_get_status(struct phy_device *phydev,
1233 bool *finished)
1234{
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001235 unsigned long pair_mask;
Michael Walle6cb75762020-05-13 22:38:07 +02001236 int retries = 20;
1237 int pair, ret;
1238
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001239 if (phydev->phy_id == ATH9331_PHY_ID ||
1240 phydev->phy_id == ATH8032_PHY_ID)
1241 pair_mask = 0x3;
1242 else
1243 pair_mask = 0xf;
1244
Michael Walle6cb75762020-05-13 22:38:07 +02001245 *finished = false;
1246
1247 /* According to the datasheet the CDT can be performed when
1248 * there is no link partner or when the link partner is
1249 * auto-negotiating. Starting the test will restart the AN
1250 * automatically. It seems that doing this repeatedly we will
1251 * get a slot where our link partner won't disturb our
1252 * measurement.
1253 */
1254 while (pair_mask && retries--) {
1255 for_each_set_bit(pair, &pair_mask, 4) {
1256 ret = at803x_cable_test_one_pair(phydev, pair);
1257 if (ret < 0)
1258 return ret;
1259 if (ret)
1260 clear_bit(pair, &pair_mask);
1261 }
1262 if (pair_mask)
1263 msleep(250);
1264 }
1265
1266 *finished = true;
1267
1268 return 0;
1269}
1270
1271static int at803x_cable_test_start(struct phy_device *phydev)
1272{
1273 /* Enable auto-negotiation, but advertise no capabilities, no link
1274 * will be established. A restart of the auto-negotiation is not
1275 * required, because the cable test will automatically break the link.
1276 */
1277 phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
1278 phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA);
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001279 if (phydev->phy_id != ATH9331_PHY_ID &&
1280 phydev->phy_id != ATH8032_PHY_ID)
1281 phy_write(phydev, MII_CTRL1000, 0);
Michael Walle6cb75762020-05-13 22:38:07 +02001282
1283 /* we do all the (time consuming) work later */
1284 return 0;
1285}
1286
Ansuel Smith272833b2021-05-14 23:00:15 +02001287static int qca83xx_config_init(struct phy_device *phydev)
1288{
1289 u8 switch_revision;
1290
1291 switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
1292
1293 switch (switch_revision) {
1294 case 1:
1295 /* For 100M waveform */
1296 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_0, 0x02ea);
1297 /* Turn on Gigabit clock */
1298 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x68a0);
1299 break;
1300
1301 case 2:
1302 phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
1303 fallthrough;
1304 case 4:
1305 phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
1306 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x6860);
1307 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_5, 0x2c46);
1308 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
1309 break;
1310 }
1311
1312 return 0;
1313}
1314
Mugunthan V N317420a2013-06-03 20:10:04 +00001315static struct phy_driver at803x_driver[] = {
1316{
Michael Walle96c36712019-11-06 23:36:16 +01001317 /* Qualcomm Atheros AR8035 */
Michael Walle0465d8f2020-05-22 11:53:31 +02001318 PHY_ID_MATCH_EXACT(ATH8035_PHY_ID),
Michael Walle96c36712019-11-06 23:36:16 +01001319 .name = "Qualcomm Atheros AR8035",
Michael Walle6cb75762020-05-13 22:38:07 +02001320 .flags = PHY_POLL_CABLE_TEST,
Michael Walle2f664822019-11-06 23:36:14 +01001321 .probe = at803x_probe,
Michael Walle2318ca82020-01-30 18:54:02 +01001322 .remove = at803x_remove,
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001323 .config_aneg = at803x_config_aneg,
Daniel Mack13a56b42014-06-18 11:01:43 +02001324 .config_init = at803x_config_init,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001325 .soft_reset = genphy_soft_reset,
Daniel Mack13a56b42014-06-18 11:01:43 +02001326 .set_wol = at803x_set_wol,
1327 .get_wol = at803x_get_wol,
1328 .suspend = at803x_suspend,
1329 .resume = at803x_resume,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001330 /* PHY_GBIT_FEATURES */
Russell King06d5f342019-10-04 17:06:14 +01001331 .read_status = at803x_read_status,
Måns Rullgård0eae5982015-11-12 17:40:20 +00001332 .config_intr = at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001333 .handle_interrupt = at803x_handle_interrupt,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001334 .get_tunable = at803x_get_tunable,
1335 .set_tunable = at803x_set_tunable,
Michael Walle6cb75762020-05-13 22:38:07 +02001336 .cable_test_start = at803x_cable_test_start,
1337 .cable_test_get_status = at803x_cable_test_get_status,
Mugunthan V N317420a2013-06-03 20:10:04 +00001338}, {
Michael Walle96c36712019-11-06 23:36:16 +01001339 /* Qualcomm Atheros AR8030 */
Daniel Mack13a56b42014-06-18 11:01:43 +02001340 .phy_id = ATH8030_PHY_ID,
Michael Walle96c36712019-11-06 23:36:16 +01001341 .name = "Qualcomm Atheros AR8030",
Michael Walle0465d8f2020-05-22 11:53:31 +02001342 .phy_id_mask = AT8030_PHY_ID_MASK,
Michael Walle2f664822019-11-06 23:36:14 +01001343 .probe = at803x_probe,
Michael Walle2318ca82020-01-30 18:54:02 +01001344 .remove = at803x_remove,
Daniel Mack13a56b42014-06-18 11:01:43 +02001345 .config_init = at803x_config_init,
1346 .link_change_notify = at803x_link_change_notify,
1347 .set_wol = at803x_set_wol,
1348 .get_wol = at803x_get_wol,
1349 .suspend = at803x_suspend,
1350 .resume = at803x_resume,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001351 /* PHY_BASIC_FEATURES */
Måns Rullgård0eae5982015-11-12 17:40:20 +00001352 .config_intr = at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001353 .handle_interrupt = at803x_handle_interrupt,
Mugunthan V N05d7cce2013-06-03 20:10:07 +00001354}, {
Michael Walle96c36712019-11-06 23:36:16 +01001355 /* Qualcomm Atheros AR8031/AR8033 */
Michael Walle0465d8f2020-05-22 11:53:31 +02001356 PHY_ID_MATCH_EXACT(ATH8031_PHY_ID),
Michael Walle96c36712019-11-06 23:36:16 +01001357 .name = "Qualcomm Atheros AR8031/AR8033",
Michael Walle6cb75762020-05-13 22:38:07 +02001358 .flags = PHY_POLL_CABLE_TEST,
Michael Walle2f664822019-11-06 23:36:14 +01001359 .probe = at803x_probe,
Michael Walle2318ca82020-01-30 18:54:02 +01001360 .remove = at803x_remove,
Daniel Mack13a56b42014-06-18 11:01:43 +02001361 .config_init = at803x_config_init,
Michael Walle63477a52021-02-14 02:17:11 +01001362 .config_aneg = at803x_config_aneg,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001363 .soft_reset = genphy_soft_reset,
Daniel Mack13a56b42014-06-18 11:01:43 +02001364 .set_wol = at803x_set_wol,
1365 .get_wol = at803x_get_wol,
1366 .suspend = at803x_suspend,
1367 .resume = at803x_resume,
David Bauerc329e5a2021-04-15 03:26:50 +02001368 .read_page = at803x_read_page,
1369 .write_page = at803x_write_page,
David Bauerb8561502021-06-27 12:16:07 +02001370 .get_features = at803x_get_features,
Russell King06d5f342019-10-04 17:06:14 +01001371 .read_status = at803x_read_status,
Daniel Mack13a56b42014-06-18 11:01:43 +02001372 .config_intr = &at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001373 .handle_interrupt = at803x_handle_interrupt,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001374 .get_tunable = at803x_get_tunable,
1375 .set_tunable = at803x_set_tunable,
Michael Walle6cb75762020-05-13 22:38:07 +02001376 .cable_test_start = at803x_cable_test_start,
1377 .cable_test_get_status = at803x_cable_test_get_status,
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001378}, {
David Bauer58000912020-04-17 15:41:59 +02001379 /* Qualcomm Atheros AR8032 */
1380 PHY_ID_MATCH_EXACT(ATH8032_PHY_ID),
1381 .name = "Qualcomm Atheros AR8032",
1382 .probe = at803x_probe,
1383 .remove = at803x_remove,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001384 .flags = PHY_POLL_CABLE_TEST,
David Bauer58000912020-04-17 15:41:59 +02001385 .config_init = at803x_config_init,
1386 .link_change_notify = at803x_link_change_notify,
1387 .set_wol = at803x_set_wol,
1388 .get_wol = at803x_get_wol,
1389 .suspend = at803x_suspend,
1390 .resume = at803x_resume,
1391 /* PHY_BASIC_FEATURES */
David Bauer58000912020-04-17 15:41:59 +02001392 .config_intr = at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001393 .handle_interrupt = at803x_handle_interrupt,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001394 .cable_test_start = at803x_cable_test_start,
1395 .cable_test_get_status = at803x_cable_test_get_status,
David Bauer58000912020-04-17 15:41:59 +02001396}, {
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001397 /* ATHEROS AR9331 */
1398 PHY_ID_MATCH_EXACT(ATH9331_PHY_ID),
Michael Walle96c36712019-11-06 23:36:16 +01001399 .name = "Qualcomm Atheros AR9331 built-in PHY",
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001400 .suspend = at803x_suspend,
1401 .resume = at803x_resume,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001402 .flags = PHY_POLL_CABLE_TEST,
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001403 /* PHY_BASIC_FEATURES */
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001404 .config_intr = &at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001405 .handle_interrupt = at803x_handle_interrupt,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001406 .cable_test_start = at803x_cable_test_start,
1407 .cable_test_get_status = at803x_cable_test_get_status,
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001408 .read_status = at803x_read_status,
1409 .soft_reset = genphy_soft_reset,
1410 .config_aneg = at803x_config_aneg,
Ansuel Smith272833b2021-05-14 23:00:15 +02001411}, {
1412 /* QCA8337 */
1413 .phy_id = QCA8337_PHY_ID,
1414 .phy_id_mask = QCA8K_PHY_ID_MASK,
1415 .name = "QCA PHY 8337",
1416 /* PHY_GBIT_FEATURES */
1417 .probe = at803x_probe,
1418 .flags = PHY_IS_INTERNAL,
1419 .config_init = qca83xx_config_init,
1420 .soft_reset = genphy_soft_reset,
1421 .get_sset_count = at803x_get_sset_count,
1422 .get_strings = at803x_get_strings,
1423 .get_stats = at803x_get_stats,
Ansuel Smith0ccf8512021-09-14 14:33:45 +02001424}, {
Ansuel Smithb4df02b2021-09-19 18:28:15 +02001425 /* QCA8327-A from switch QCA8327-AL1A */
1426 .phy_id = QCA8327_A_PHY_ID,
Ansuel Smith0ccf8512021-09-14 14:33:45 +02001427 .phy_id_mask = QCA8K_PHY_ID_MASK,
Ansuel Smithb4df02b2021-09-19 18:28:15 +02001428 .name = "QCA PHY 8327-A",
1429 /* PHY_GBIT_FEATURES */
1430 .probe = at803x_probe,
1431 .flags = PHY_IS_INTERNAL,
1432 .config_init = qca83xx_config_init,
1433 .soft_reset = genphy_soft_reset,
1434 .get_sset_count = at803x_get_sset_count,
1435 .get_strings = at803x_get_strings,
1436 .get_stats = at803x_get_stats,
1437}, {
1438 /* QCA8327-B from switch QCA8327-BL1A */
1439 .phy_id = QCA8327_B_PHY_ID,
1440 .phy_id_mask = QCA8K_PHY_ID_MASK,
1441 .name = "QCA PHY 8327-B",
Ansuel Smith0ccf8512021-09-14 14:33:45 +02001442 /* PHY_GBIT_FEATURES */
1443 .probe = at803x_probe,
1444 .flags = PHY_IS_INTERNAL,
1445 .config_init = qca83xx_config_init,
1446 .soft_reset = genphy_soft_reset,
1447 .get_sset_count = at803x_get_sset_count,
1448 .get_strings = at803x_get_strings,
1449 .get_stats = at803x_get_stats,
Ansuel Smith272833b2021-05-14 23:00:15 +02001450}, };
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00001451
Johan Hovold50fd7152014-11-11 19:45:59 +01001452module_phy_driver(at803x_driver);
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00001453
1454static struct mdio_device_id __maybe_unused atheros_tbl[] = {
Michael Walle0465d8f2020-05-22 11:53:31 +02001455 { ATH8030_PHY_ID, AT8030_PHY_ID_MASK },
1456 { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) },
David Bauer58000912020-04-17 15:41:59 +02001457 { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
Michael Walle0465d8f2020-05-22 11:53:31 +02001458 { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001459 { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
Ansuel Smith0ccf8512021-09-14 14:33:45 +02001460 { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
Ansuel Smithb4df02b2021-09-19 18:28:15 +02001461 { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
1462 { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00001463 { }
1464};
1465
1466MODULE_DEVICE_TABLE(mdio, atheros_tbl);