generic: 6.1: backport at803x split patches
[openwrt/staging/svanheule.git] / target / linux / generic / backport-6.1 / 713-v6.9-03-net-phy-qcom-deatch-qca83xx-PHY-driver-from-at803x.patch
1 From 2e45d404d99d43bb7127b74b5dea8818df64996c Mon Sep 17 00:00:00 2001
2 From: Christian Marangi <ansuelsmth@gmail.com>
3 Date: Mon, 29 Jan 2024 15:15:21 +0100
4 Subject: [PATCH 3/5] net: phy: qcom: deatch qca83xx PHY driver from at803x
5
6 Deatch qca83xx PHY driver from at803x.
7
8 The QCA83xx PHYs implement specific function and doesn't use generic
9 at803x so it can be detached from the driver and moved to a dedicated
10 one.
11
12 Probe function and priv struct is reimplemented to allocate and use
13 only the qca83xx specific data. Unused data from at803x PHY driver
14 are dropped from at803x priv struct.
15
16 This is to make slimmer PHY drivers instead of including lots of bloat
17 that would never be used in specific SoC.
18
19 A new Kconfig flag QCA83XX_PHY is introduced to compile the new
20 introduced PHY driver.
21
22 As the Kconfig name starts with Qualcomm the same order is kept.
23
24 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
25 Reviewed-by: Andrew Lunn <andrew@lunn.ch>
26 Link: https://lore.kernel.org/r/20240129141600.2592-4-ansuelsmth@gmail.com
27 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
28 ---
29 drivers/net/phy/qcom/Kconfig | 11 +-
30 drivers/net/phy/qcom/Makefile | 1 +
31 drivers/net/phy/qcom/at803x.c | 235 ----------------------------
32 drivers/net/phy/qcom/qca83xx.c | 275 +++++++++++++++++++++++++++++++++
33 4 files changed, 284 insertions(+), 238 deletions(-)
34 create mode 100644 drivers/net/phy/qcom/qca83xx.c
35
36 --- a/drivers/net/phy/qcom/Kconfig
37 +++ b/drivers/net/phy/qcom/Kconfig
38 @@ -3,9 +3,14 @@ config QCOM_NET_PHYLIB
39 tristate
40
41 config AT803X_PHY
42 - tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs"
43 + tristate "Qualcomm Atheros AR803X PHYs"
44 select QCOM_NET_PHYLIB
45 depends on REGULATOR
46 help
47 - Currently supports the AR8030, AR8031, AR8033, AR8035 and internal
48 - QCA8337(Internal qca8k PHY) model
49 + Currently supports the AR8030, AR8031, AR8033, AR8035 model
50 +
51 +config QCA83XX_PHY
52 + tristate "Qualcomm Atheros QCA833x PHYs"
53 + select QCOM_NET_PHYLIB
54 + help
55 + Currently supports the internal QCA8337(Internal qca8k PHY) model
56 --- a/drivers/net/phy/qcom/Makefile
57 +++ b/drivers/net/phy/qcom/Makefile
58 @@ -1,3 +1,4 @@
59 # SPDX-License-Identifier: GPL-2.0
60 obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-phy-lib.o
61 obj-$(CONFIG_AT803X_PHY) += at803x.o
62 +obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o
63 --- a/drivers/net/phy/qcom/at803x.c
64 +++ b/drivers/net/phy/qcom/at803x.c
65 @@ -102,17 +102,10 @@
66 #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
67 #define AT803X_PSSR_MR_AN_COMPLETE 0x0200
68
69 -#define AT803X_DEBUG_REG_3C 0x3C
70 -
71 -#define AT803X_DEBUG_REG_GREEN 0x3D
72 -#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
73 -
74 #define AT803X_DEBUG_REG_1F 0x1F
75 #define AT803X_DEBUG_PLL_ON BIT(2)
76 #define AT803X_DEBUG_RGMII_1V8 BIT(3)
77
78 -#define MDIO_AZ_DEBUG 0x800D
79 -
80 /* AT803x supports either the XTAL input pad, an internal PLL or the
81 * DSP as clock reference for the clock output pad. The XTAL reference
82 * is only used for 25 MHz output, all other frequencies need the PLL.
83 @@ -163,13 +156,7 @@
84
85 #define QCA8081_PHY_ID 0x004dd101
86
87 -#define QCA8327_A_PHY_ID 0x004dd033
88 -#define QCA8327_B_PHY_ID 0x004dd034
89 -#define QCA8337_PHY_ID 0x004dd036
90 #define QCA9561_PHY_ID 0x004dd042
91 -#define QCA8K_PHY_ID_MASK 0xffffffff
92 -
93 -#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
94
95 #define AT803X_PAGE_FIBER 0
96 #define AT803X_PAGE_COPPER 1
97 @@ -379,12 +366,6 @@ MODULE_DESCRIPTION("Qualcomm Atheros AR8
98 MODULE_AUTHOR("Matus Ujhelyi");
99 MODULE_LICENSE("GPL");
100
101 -static struct at803x_hw_stat qca83xx_hw_stats[] = {
102 - { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
103 - { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
104 - { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
105 -};
106 -
107 struct at803x_ss_mask {
108 u16 speed_mask;
109 u8 speed_shift;
110 @@ -400,7 +381,6 @@ struct at803x_priv {
111 bool is_1000basex;
112 struct regulator_dev *vddio_rdev;
113 struct regulator_dev *vddh_rdev;
114 - u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
115 int led_polarity_mode;
116 };
117
118 @@ -564,53 +544,6 @@ static void at803x_get_wol(struct phy_de
119 wol->wolopts |= WAKE_MAGIC;
120 }
121
122 -static int qca83xx_get_sset_count(struct phy_device *phydev)
123 -{
124 - return ARRAY_SIZE(qca83xx_hw_stats);
125 -}
126 -
127 -static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
128 -{
129 - int i;
130 -
131 - for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
132 - strscpy(data + i * ETH_GSTRING_LEN,
133 - qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
134 - }
135 -}
136 -
137 -static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
138 -{
139 - struct at803x_hw_stat stat = qca83xx_hw_stats[i];
140 - struct at803x_priv *priv = phydev->priv;
141 - int val;
142 - u64 ret;
143 -
144 - if (stat.access_type == MMD)
145 - val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
146 - else
147 - val = phy_read(phydev, stat.reg);
148 -
149 - if (val < 0) {
150 - ret = U64_MAX;
151 - } else {
152 - val = val & stat.mask;
153 - priv->stats[i] += val;
154 - ret = priv->stats[i];
155 - }
156 -
157 - return ret;
158 -}
159 -
160 -static void qca83xx_get_stats(struct phy_device *phydev,
161 - struct ethtool_stats *stats, u64 *data)
162 -{
163 - int i;
164 -
165 - for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
166 - data[i] = qca83xx_get_stat(phydev, i);
167 -}
168 -
169 static int at803x_suspend(struct phy_device *phydev)
170 {
171 int value;
172 @@ -1707,124 +1640,6 @@ static int at8035_probe(struct phy_devic
173 return at8035_parse_dt(phydev);
174 }
175
176 -static int qca83xx_config_init(struct phy_device *phydev)
177 -{
178 - u8 switch_revision;
179 -
180 - switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
181 -
182 - switch (switch_revision) {
183 - case 1:
184 - /* For 100M waveform */
185 - at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
186 - /* Turn on Gigabit clock */
187 - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
188 - break;
189 -
190 - case 2:
191 - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
192 - fallthrough;
193 - case 4:
194 - phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
195 - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
196 - at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
197 - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
198 - break;
199 - }
200 -
201 - /* Following original QCA sourcecode set port to prefer master */
202 - phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
203 -
204 - return 0;
205 -}
206 -
207 -static int qca8327_config_init(struct phy_device *phydev)
208 -{
209 - /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
210 - * Disable on init and enable only with 100m speed following
211 - * qca original source code.
212 - */
213 - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
214 - QCA8327_DEBUG_MANU_CTRL_EN, 0);
215 -
216 - return qca83xx_config_init(phydev);
217 -}
218 -
219 -static void qca83xx_link_change_notify(struct phy_device *phydev)
220 -{
221 - /* Set DAC Amplitude adjustment to +6% for 100m on link running */
222 - if (phydev->state == PHY_RUNNING) {
223 - if (phydev->speed == SPEED_100)
224 - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
225 - QCA8327_DEBUG_MANU_CTRL_EN,
226 - QCA8327_DEBUG_MANU_CTRL_EN);
227 - } else {
228 - /* Reset DAC Amplitude adjustment */
229 - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
230 - QCA8327_DEBUG_MANU_CTRL_EN, 0);
231 - }
232 -}
233 -
234 -static int qca83xx_resume(struct phy_device *phydev)
235 -{
236 - int ret, val;
237 -
238 - /* Skip reset if not suspended */
239 - if (!phydev->suspended)
240 - return 0;
241 -
242 - /* Reinit the port, reset values set by suspend */
243 - qca83xx_config_init(phydev);
244 -
245 - /* Reset the port on port resume */
246 - phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
247 -
248 - /* On resume from suspend the switch execute a reset and
249 - * restart auto-negotiation. Wait for reset to complete.
250 - */
251 - ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
252 - 50000, 600000, true);
253 - if (ret)
254 - return ret;
255 -
256 - usleep_range(1000, 2000);
257 -
258 - return 0;
259 -}
260 -
261 -static int qca83xx_suspend(struct phy_device *phydev)
262 -{
263 - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
264 - AT803X_DEBUG_GATE_CLK_IN1000, 0);
265 -
266 - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
267 - AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
268 - AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
269 -
270 - return 0;
271 -}
272 -
273 -static int qca8337_suspend(struct phy_device *phydev)
274 -{
275 - /* Only QCA8337 support actual suspend. */
276 - genphy_suspend(phydev);
277 -
278 - return qca83xx_suspend(phydev);
279 -}
280 -
281 -static int qca8327_suspend(struct phy_device *phydev)
282 -{
283 - u16 mask = 0;
284 -
285 - /* QCA8327 cause port unreliability when phy suspend
286 - * is set.
287 - */
288 - mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
289 - phy_modify(phydev, MII_BMCR, mask, 0);
290 -
291 - return qca83xx_suspend(phydev);
292 -}
293 -
294 static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
295 {
296 int ret;
297 @@ -2599,53 +2414,6 @@ static struct phy_driver at803x_driver[]
298 .soft_reset = genphy_soft_reset,
299 .config_aneg = at803x_config_aneg,
300 }, {
301 - /* QCA8337 */
302 - .phy_id = QCA8337_PHY_ID,
303 - .phy_id_mask = QCA8K_PHY_ID_MASK,
304 - .name = "Qualcomm Atheros 8337 internal PHY",
305 - /* PHY_GBIT_FEATURES */
306 - .probe = at803x_probe,
307 - .flags = PHY_IS_INTERNAL,
308 - .config_init = qca83xx_config_init,
309 - .soft_reset = genphy_soft_reset,
310 - .get_sset_count = qca83xx_get_sset_count,
311 - .get_strings = qca83xx_get_strings,
312 - .get_stats = qca83xx_get_stats,
313 - .suspend = qca8337_suspend,
314 - .resume = qca83xx_resume,
315 -}, {
316 - /* QCA8327-A from switch QCA8327-AL1A */
317 - .phy_id = QCA8327_A_PHY_ID,
318 - .phy_id_mask = QCA8K_PHY_ID_MASK,
319 - .name = "Qualcomm Atheros 8327-A internal PHY",
320 - /* PHY_GBIT_FEATURES */
321 - .link_change_notify = qca83xx_link_change_notify,
322 - .probe = at803x_probe,
323 - .flags = PHY_IS_INTERNAL,
324 - .config_init = qca8327_config_init,
325 - .soft_reset = genphy_soft_reset,
326 - .get_sset_count = qca83xx_get_sset_count,
327 - .get_strings = qca83xx_get_strings,
328 - .get_stats = qca83xx_get_stats,
329 - .suspend = qca8327_suspend,
330 - .resume = qca83xx_resume,
331 -}, {
332 - /* QCA8327-B from switch QCA8327-BL1A */
333 - .phy_id = QCA8327_B_PHY_ID,
334 - .phy_id_mask = QCA8K_PHY_ID_MASK,
335 - .name = "Qualcomm Atheros 8327-B internal PHY",
336 - /* PHY_GBIT_FEATURES */
337 - .link_change_notify = qca83xx_link_change_notify,
338 - .probe = at803x_probe,
339 - .flags = PHY_IS_INTERNAL,
340 - .config_init = qca8327_config_init,
341 - .soft_reset = genphy_soft_reset,
342 - .get_sset_count = qca83xx_get_sset_count,
343 - .get_strings = qca83xx_get_strings,
344 - .get_stats = qca83xx_get_stats,
345 - .suspend = qca8327_suspend,
346 - .resume = qca83xx_resume,
347 -}, {
348 /* Qualcomm QCA8081 */
349 PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),
350 .name = "Qualcomm QCA8081",
351 @@ -2683,9 +2451,6 @@ static struct mdio_device_id __maybe_unu
352 { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
353 { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
354 { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
355 - { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
356 - { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
357 - { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
358 { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) },
359 { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
360 { }
361 --- /dev/null
362 +++ b/drivers/net/phy/qcom/qca83xx.c
363 @@ -0,0 +1,275 @@
364 +// SPDX-License-Identifier: GPL-2.0+
365 +
366 +#include <linux/phy.h>
367 +#include <linux/module.h>
368 +
369 +#include "qcom.h"
370 +
371 +#define AT803X_DEBUG_REG_3C 0x3C
372 +
373 +#define AT803X_DEBUG_REG_GREEN 0x3D
374 +#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
375 +
376 +#define MDIO_AZ_DEBUG 0x800D
377 +
378 +#define QCA8327_A_PHY_ID 0x004dd033
379 +#define QCA8327_B_PHY_ID 0x004dd034
380 +#define QCA8337_PHY_ID 0x004dd036
381 +#define QCA8K_PHY_ID_MASK 0xffffffff
382 +
383 +#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
384 +
385 +static struct at803x_hw_stat qca83xx_hw_stats[] = {
386 + { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
387 + { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
388 + { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
389 +};
390 +
391 +struct qca83xx_priv {
392 + u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
393 +};
394 +
395 +MODULE_DESCRIPTION("Qualcomm Atheros QCA83XX PHY driver");
396 +MODULE_AUTHOR("Matus Ujhelyi");
397 +MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
398 +MODULE_LICENSE("GPL");
399 +
400 +static int qca83xx_get_sset_count(struct phy_device *phydev)
401 +{
402 + return ARRAY_SIZE(qca83xx_hw_stats);
403 +}
404 +
405 +static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
406 +{
407 + int i;
408 +
409 + for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
410 + strscpy(data + i * ETH_GSTRING_LEN,
411 + qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
412 + }
413 +}
414 +
415 +static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
416 +{
417 + struct at803x_hw_stat stat = qca83xx_hw_stats[i];
418 + struct qca83xx_priv *priv = phydev->priv;
419 + int val;
420 + u64 ret;
421 +
422 + if (stat.access_type == MMD)
423 + val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
424 + else
425 + val = phy_read(phydev, stat.reg);
426 +
427 + if (val < 0) {
428 + ret = U64_MAX;
429 + } else {
430 + val = val & stat.mask;
431 + priv->stats[i] += val;
432 + ret = priv->stats[i];
433 + }
434 +
435 + return ret;
436 +}
437 +
438 +static void qca83xx_get_stats(struct phy_device *phydev,
439 + struct ethtool_stats *stats, u64 *data)
440 +{
441 + int i;
442 +
443 + for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
444 + data[i] = qca83xx_get_stat(phydev, i);
445 +}
446 +
447 +static int qca83xx_probe(struct phy_device *phydev)
448 +{
449 + struct device *dev = &phydev->mdio.dev;
450 + struct qca83xx_priv *priv;
451 +
452 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
453 + if (!priv)
454 + return -ENOMEM;
455 +
456 + phydev->priv = priv;
457 +
458 + return 0;
459 +}
460 +
461 +static int qca83xx_config_init(struct phy_device *phydev)
462 +{
463 + u8 switch_revision;
464 +
465 + switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
466 +
467 + switch (switch_revision) {
468 + case 1:
469 + /* For 100M waveform */
470 + at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
471 + /* Turn on Gigabit clock */
472 + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
473 + break;
474 +
475 + case 2:
476 + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
477 + fallthrough;
478 + case 4:
479 + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
480 + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
481 + at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
482 + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
483 + break;
484 + }
485 +
486 + /* Following original QCA sourcecode set port to prefer master */
487 + phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
488 +
489 + return 0;
490 +}
491 +
492 +static int qca8327_config_init(struct phy_device *phydev)
493 +{
494 + /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
495 + * Disable on init and enable only with 100m speed following
496 + * qca original source code.
497 + */
498 + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
499 + QCA8327_DEBUG_MANU_CTRL_EN, 0);
500 +
501 + return qca83xx_config_init(phydev);
502 +}
503 +
504 +static void qca83xx_link_change_notify(struct phy_device *phydev)
505 +{
506 + /* Set DAC Amplitude adjustment to +6% for 100m on link running */
507 + if (phydev->state == PHY_RUNNING) {
508 + if (phydev->speed == SPEED_100)
509 + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
510 + QCA8327_DEBUG_MANU_CTRL_EN,
511 + QCA8327_DEBUG_MANU_CTRL_EN);
512 + } else {
513 + /* Reset DAC Amplitude adjustment */
514 + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
515 + QCA8327_DEBUG_MANU_CTRL_EN, 0);
516 + }
517 +}
518 +
519 +static int qca83xx_resume(struct phy_device *phydev)
520 +{
521 + int ret, val;
522 +
523 + /* Skip reset if not suspended */
524 + if (!phydev->suspended)
525 + return 0;
526 +
527 + /* Reinit the port, reset values set by suspend */
528 + qca83xx_config_init(phydev);
529 +
530 + /* Reset the port on port resume */
531 + phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
532 +
533 + /* On resume from suspend the switch execute a reset and
534 + * restart auto-negotiation. Wait for reset to complete.
535 + */
536 + ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
537 + 50000, 600000, true);
538 + if (ret)
539 + return ret;
540 +
541 + usleep_range(1000, 2000);
542 +
543 + return 0;
544 +}
545 +
546 +static int qca83xx_suspend(struct phy_device *phydev)
547 +{
548 + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
549 + AT803X_DEBUG_GATE_CLK_IN1000, 0);
550 +
551 + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
552 + AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
553 + AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
554 +
555 + return 0;
556 +}
557 +
558 +static int qca8337_suspend(struct phy_device *phydev)
559 +{
560 + /* Only QCA8337 support actual suspend. */
561 + genphy_suspend(phydev);
562 +
563 + return qca83xx_suspend(phydev);
564 +}
565 +
566 +static int qca8327_suspend(struct phy_device *phydev)
567 +{
568 + u16 mask = 0;
569 +
570 + /* QCA8327 cause port unreliability when phy suspend
571 + * is set.
572 + */
573 + mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
574 + phy_modify(phydev, MII_BMCR, mask, 0);
575 +
576 + return qca83xx_suspend(phydev);
577 +}
578 +
579 +static struct phy_driver qca83xx_driver[] = {
580 +{
581 + /* QCA8337 */
582 + .phy_id = QCA8337_PHY_ID,
583 + .phy_id_mask = QCA8K_PHY_ID_MASK,
584 + .name = "Qualcomm Atheros 8337 internal PHY",
585 + /* PHY_GBIT_FEATURES */
586 + .probe = qca83xx_probe,
587 + .flags = PHY_IS_INTERNAL,
588 + .config_init = qca83xx_config_init,
589 + .soft_reset = genphy_soft_reset,
590 + .get_sset_count = qca83xx_get_sset_count,
591 + .get_strings = qca83xx_get_strings,
592 + .get_stats = qca83xx_get_stats,
593 + .suspend = qca8337_suspend,
594 + .resume = qca83xx_resume,
595 +}, {
596 + /* QCA8327-A from switch QCA8327-AL1A */
597 + .phy_id = QCA8327_A_PHY_ID,
598 + .phy_id_mask = QCA8K_PHY_ID_MASK,
599 + .name = "Qualcomm Atheros 8327-A internal PHY",
600 + /* PHY_GBIT_FEATURES */
601 + .link_change_notify = qca83xx_link_change_notify,
602 + .probe = qca83xx_probe,
603 + .flags = PHY_IS_INTERNAL,
604 + .config_init = qca8327_config_init,
605 + .soft_reset = genphy_soft_reset,
606 + .get_sset_count = qca83xx_get_sset_count,
607 + .get_strings = qca83xx_get_strings,
608 + .get_stats = qca83xx_get_stats,
609 + .suspend = qca8327_suspend,
610 + .resume = qca83xx_resume,
611 +}, {
612 + /* QCA8327-B from switch QCA8327-BL1A */
613 + .phy_id = QCA8327_B_PHY_ID,
614 + .phy_id_mask = QCA8K_PHY_ID_MASK,
615 + .name = "Qualcomm Atheros 8327-B internal PHY",
616 + /* PHY_GBIT_FEATURES */
617 + .link_change_notify = qca83xx_link_change_notify,
618 + .probe = qca83xx_probe,
619 + .flags = PHY_IS_INTERNAL,
620 + .config_init = qca8327_config_init,
621 + .soft_reset = genphy_soft_reset,
622 + .get_sset_count = qca83xx_get_sset_count,
623 + .get_strings = qca83xx_get_strings,
624 + .get_stats = qca83xx_get_stats,
625 + .suspend = qca8327_suspend,
626 + .resume = qca83xx_resume,
627 +}, };
628 +
629 +module_phy_driver(qca83xx_driver);
630 +
631 +static struct mdio_device_id __maybe_unused qca83xx_tbl[] = {
632 + { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
633 + { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
634 + { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
635 + { }
636 +};
637 +
638 +MODULE_DEVICE_TABLE(mdio, qca83xx_tbl);