xref: /linux/drivers/net/phy/air_an8801.c (revision 00599d4841790d05401820a96cf7edb193888b00)
1fdb9bf7fSAngeloGioacchino Del Regno // SPDX-License-Identifier: GPL-2.0+
2fdb9bf7fSAngeloGioacchino Del Regno /*
3fdb9bf7fSAngeloGioacchino Del Regno  * Driver for the Airoha AN8801 Gigabit PHY.
4fdb9bf7fSAngeloGioacchino Del Regno  *
5fdb9bf7fSAngeloGioacchino Del Regno  * Copyright (C) 2025 Airoha Technology Corp.
6fdb9bf7fSAngeloGioacchino Del Regno  * Copyright (C) 2025 Collabora Ltd.
7fdb9bf7fSAngeloGioacchino Del Regno  *                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
8fdb9bf7fSAngeloGioacchino Del Regno  */
9fdb9bf7fSAngeloGioacchino Del Regno 
10fdb9bf7fSAngeloGioacchino Del Regno #include <linux/bitfield.h>
11fdb9bf7fSAngeloGioacchino Del Regno #include <linux/bitops.h>
12fdb9bf7fSAngeloGioacchino Del Regno #include <linux/delay.h>
13fdb9bf7fSAngeloGioacchino Del Regno #include <linux/errno.h>
14fdb9bf7fSAngeloGioacchino Del Regno #include <linux/etherdevice.h>
15fdb9bf7fSAngeloGioacchino Del Regno #include <linux/init.h>
16fdb9bf7fSAngeloGioacchino Del Regno #include <linux/minmax.h>
17fdb9bf7fSAngeloGioacchino Del Regno #include <linux/netdevice.h>
18fdb9bf7fSAngeloGioacchino Del Regno #include <linux/of.h>
19fdb9bf7fSAngeloGioacchino Del Regno #include <linux/phy.h>
20fdb9bf7fSAngeloGioacchino Del Regno #include <linux/pm_wakeirq.h>
21fdb9bf7fSAngeloGioacchino Del Regno 
22fdb9bf7fSAngeloGioacchino Del Regno #include "air_phy_lib.h"
23fdb9bf7fSAngeloGioacchino Del Regno 
24fdb9bf7fSAngeloGioacchino Del Regno #define AN8801R_PHY_ID			0xc0ff0421
25fdb9bf7fSAngeloGioacchino Del Regno 
26fdb9bf7fSAngeloGioacchino Del Regno /* MII Registers */
27fdb9bf7fSAngeloGioacchino Del Regno 
28fdb9bf7fSAngeloGioacchino Del Regno /* MII Registers - Airoha Page 1 */
29fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EXT_REG_PHY		0x14
30fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EXT_PHY_STATUS0	GENMASK(1, 0)
31fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EXT_PHY_DOWNSHIFT_CTL	GENMASK(3, 2) /* 2 to 5 1G auto-neg attempts (0..3) */
32fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EXT_PHY_DOWNSHIFT_EN	BIT(4)
33fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EXT_PHY_CTRL0		BIT(5)
34fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EXT_PHY_STATUS1	GENMASK(8, 6)
35fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EXT_PHY_CTRL1		GENMASK(14, 9)
36fdb9bf7fSAngeloGioacchino Del Regno 
37fdb9bf7fSAngeloGioacchino Del Regno /* MII Registers - Airoha Page 4 */
38fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PBUS_ACCESS		BIT(28)
39fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PBUS_EPHY_ACCESS		BIT(24)
40fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PBUS_CL22_ACCESS		BIT(23)
41fdb9bf7fSAngeloGioacchino Del Regno 
42fdb9bf7fSAngeloGioacchino Del Regno /* BPBUS Registers */
43fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_LED_GPIO	0x54
44fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_LED_ID_SEL	0x58
45fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ID_GPIO_SEL(led, gpio)	((led) << ((gpio) * 3))
46fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ID_GPIO_SEL_MASK(gpio)	(0x7 << ((gpio) * 3))
47fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_GPIO_MODE	0x70
48fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_PHY_IRQ_GPIO	0x7c
49fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_IRQ_GPIO_NUM_MASK	GENMASK(19, 16)
50fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_IRQ_GPIO_NUM	1
51fdb9bf7fSAngeloGioacchino Del Regno 
52fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_CKO		0x1a4
53fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_CKO_OUTPUT_MODE_AUTO	3
54fdb9bf7fSAngeloGioacchino Del Regno 
55fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_LINK_MODE	0x5054
56fdb9bf7fSAngeloGioacchino Del Regno #define  AN8801_BPBUS_LINK_MODE_1000	BIT(0)
57fdb9bf7fSAngeloGioacchino Del Regno 
58fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_BYPASS_PTP	0x21c004
59fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_BYP_PTP_SGMII_TO_GPHY	BIT(8)
60fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_BYP_PTP_RGMII_TO_GPHY	BIT(0)
61fdb9bf7fSAngeloGioacchino Del Regno 
62fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_TXDLY_STEP	0x21c024
63fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_DELAY_STEP_MASK		GENMASK(2, 0)
64fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_DELAY_NO_STEP		0
65fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_DELAY_STEP_1		1
66fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_DELAY_STEP_2		2
67fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_DELAY_STEP_3		3
68fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_DELAY_STEP_4		4
69fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_DELAY_STEP_5		5
70fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_DELAY_STEP_6		6
71fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_DELAY_STEP_7		7
72fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_TXDELAY_FORCE_MODE	BIT(24)
73fdb9bf7fSAngeloGioacchino Del Regno 
74fdb9bf7fSAngeloGioacchino Del Regno /* Default RGMII TX delay setting, corresponding to a 1.883ns delay */
75fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_RGMII_TXDELAY_DEFAULT	RGMII_DELAY_STEP_4
76fdb9bf7fSAngeloGioacchino Del Regno 
77fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_RXDLY_STEP	0x21c02c
78fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_RXDELAY_ALIGN		BIT(4)
79fdb9bf7fSAngeloGioacchino Del Regno #define   RGMII_RXDELAY_FORCE_MODE	BIT(24)
80fdb9bf7fSAngeloGioacchino Del Regno 
81fdb9bf7fSAngeloGioacchino Del Regno /* Default RGMII RX delay setting, corresponding to a 1.992ns delay,
82fdb9bf7fSAngeloGioacchino Del Regno  * when align bit is set or -0.008ns otherwise.
83fdb9bf7fSAngeloGioacchino Del Regno  */
84fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_RGMII_RXDELAY_DEFAULT	RGMII_DELAY_NO_STEP
85fdb9bf7fSAngeloGioacchino Del Regno 
86fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_EFIFO_CTL(x)	(0x270004 + (0x100 * (x))) /* 0..2 */
87fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EFIFO_ALL_EN		GENMASK(7, 0)
88fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EFIFO_RX_EN		BIT(0)
89fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EFIFO_TX_EN		BIT(1)
90fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EFIFO_RX_CLK_EN	BIT(2)
91fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EFIFO_TX_CLK_EN	BIT(3)
92fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EFIFO_RX_EEE_EN	BIT(4)
93fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EFIFO_TX_EEE_EN	BIT(5)
94fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EFIFO_RX_ODD_NIBBLE_EN	BIT(6)
95fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_EFIFO_TX_ODD_NIBBLE_EN	BIT(7)
96fdb9bf7fSAngeloGioacchino Del Regno 
97fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WOL_MAC_16_47	0x285114
98fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WOL_MAC_0_15	0x285118
99fdb9bf7fSAngeloGioacchino Del Regno 
100fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WAKEUP_CTL1	0x285400
101fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_WOL_WAKE_MAGIC_EN	GENMASK(3, 1)
102fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_WOL_WAKE_LNKCHG_EN	BIT(4)
103fdb9bf7fSAngeloGioacchino Del Regno 
104fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WAKEUP_CTL2	0x285404
105fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_WAKE_OUT_TYPE_PULSE	BIT(0) /* Set/Unset: Pulse/Static */
106fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_WAKE_OUT_POLARITY_NEG	BIT(1) /* Set/Unset: Negative/Positive */
107fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_WAKE_OUT_WIDTH		GENMASK(3, 2)
108fdb9bf7fSAngeloGioacchino Del Regno #define    AN8801_WAKE_OUT_84MS		0
109fdb9bf7fSAngeloGioacchino Del Regno #define    AN8801_WAKE_OUT_168MS	1
110fdb9bf7fSAngeloGioacchino Del Regno #define    AN8801_WAKE_OUT_336MS	2
111fdb9bf7fSAngeloGioacchino Del Regno #define    AN8801_WAKE_OUT_672MS	3
112fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_WAKE_OUT_EN		BIT(4)
113fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PME_WAKEUP_CLR		BIT(8)
114fdb9bf7fSAngeloGioacchino Del Regno 
115fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WAKE_IRQ_EN	0x285700
116fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WAKE_IRQ_STS	0x285704
117fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_IRQ_WAKE_LNKCHG	BIT(0) /* Wake on link change */
118fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_IRQ_WAKE_UNIPKT	BIT(1) /* Wake on unicast packet */
119fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_IRQ_WAKE_MULPKT	BIT(2) /* Wake on multicast packet */
120fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_IRQ_WAKE_BCPKT		BIT(3) /* Wake on broadcast packet */
121fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_IRQ_WAKE_MAGICPKT	BIT(4) /* Wake on magic packet */
122fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_IRQ_WAKE_ALL		GENMASK(4, 0)
123fdb9bf7fSAngeloGioacchino Del Regno 
124fdb9bf7fSAngeloGioacchino Del Regno /* MDIO_MMD_VEND1 Registers */
125fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_TX_PAIR_DLY_SEL_GBE	0x13
126fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_PAIR_DLY_SEL_A_GBE	GENMASK(14, 12)
127fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_PAIR_DLY_SEL_B_GBE	GENMASK(10, 8)
128fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_PAIR_DLY_SEL_C_GBE	GENMASK(6, 4)
129fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_PAIR_DLY_SEL_D_GBE	GENMASK(2, 0)
130fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_CTRL		0xd8
131fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_RXADC_SAMP_PHSEL_A	BIT(12)
132fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_RXADC_SAMP_PHSEL_B	BIT(8)
133fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_RXADC_SAMP_PHSEL_C	BIT(4)
134fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_RXADC_SAMP_PHSEL_D	BIT(0)
135fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_REV_0		0xd9
136fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_RXADC_REV_MASK_A	GENMASK(15, 8)
137fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_RXADC_REV_MASK_B	GENMASK(7, 0)
138fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_REV_1		0xda
139fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_RXADC_REV_MASK_C	GENMASK(15, 8)
140fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_RXADC_REV_MASK_D	GENMASK(7, 0)
141fdb9bf7fSAngeloGioacchino Del Regno 
142fdb9bf7fSAngeloGioacchino Del Regno /* MDIO_MMD_VEND2 Registers */
143fdb9bf7fSAngeloGioacchino Del Regno #define LED_BCR				0x21
144fdb9bf7fSAngeloGioacchino Del Regno #define   LED_BCR_MODE_MASK		GENMASK(1, 0)
145fdb9bf7fSAngeloGioacchino Del Regno #define   LED_BCR_TIME_TEST		BIT(2)
146fdb9bf7fSAngeloGioacchino Del Regno #define   LED_BCR_CLK_EN		BIT(3)
147fdb9bf7fSAngeloGioacchino Del Regno #define   LED_BCR_EVT_ALL		BIT(4)
148fdb9bf7fSAngeloGioacchino Del Regno #define   LED_BCR_EXT_CTRL		BIT(15)
149fdb9bf7fSAngeloGioacchino Del Regno #define   LED_BCR_MODE_DISABLE		0
150fdb9bf7fSAngeloGioacchino Del Regno #define   LED_BCR_MODE_2LED		1
151fdb9bf7fSAngeloGioacchino Del Regno #define   LED_BCR_MODE_3LED_1		2
152fdb9bf7fSAngeloGioacchino Del Regno #define   LED_BCR_MODE_3LED_2		3
153fdb9bf7fSAngeloGioacchino Del Regno 
154fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_DUR			0x22
155fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ON_DUR_MASK		GENMASK(15, 0)
156fdb9bf7fSAngeloGioacchino Del Regno 
157fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_DUR			0x23
158fdb9bf7fSAngeloGioacchino Del Regno #define   LED_BLINK_DUR_MASK		GENMASK(15, 0)
159fdb9bf7fSAngeloGioacchino Del Regno 
160fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_CTRL(i)			(0x24 + ((i) * 2))
161fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ON_EVT_MASK		GENMASK(6, 0)
162fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ON_EVT_LINK_1000M		BIT(0)
163fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ON_EVT_LINK_100M		BIT(1)
164fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ON_EVT_LINK_10M		BIT(2)
165fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ON_EVT_LINK_DN		BIT(3)
166fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ON_EVT_FDX		BIT(4)
167fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ON_EVT_HDX		BIT(5)
168fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ON_EVT_FORCE		BIT(6)
169fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ON_POL			BIT(14)
170fdb9bf7fSAngeloGioacchino Del Regno #define   LED_ON_EN			BIT(15)
171fdb9bf7fSAngeloGioacchino Del Regno 
172fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_CTRL(i)		(0x25 + ((i) * 2))
173fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_MASK		GENMASK(9, 0)
174fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_1000M_TX		BIT(0)
175fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_1000M_RX		BIT(1)
176fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_100M_TX		BIT(2)
177fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_100M_RX		BIT(3)
178fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_10M_TX		BIT(4)
179fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_10M_RX		BIT(5)
180fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_COLLISION		BIT(6)
181fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_RX_CRC_ERR	BIT(7)
182fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_RX_IDLE_ERR	BIT(8)
183fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_FORCE		BIT(9)
184fdb9bf7fSAngeloGioacchino Del Regno 
185fdb9bf7fSAngeloGioacchino Del Regno #define AN8801R_NUM_LEDS		3
186fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PERIOD_SHIFT		15
187fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PERIOD_UNIT		32768 /* (1 << AN8801_PERIOD_SHIFT) */
188fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_MAX_PERIOD_MS		2147
189fdb9bf7fSAngeloGioacchino Del Regno 
190fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_REG_PHY_INTERNAL0	0x600
191fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_REG_PHY_INTERNAL1	0x601
192fdb9bf7fSAngeloGioacchino Del Regno #define   AN8801_PHY_INTFUNC_MASK	GENMASK(15, 0) /* PHY internal functions */
193fdb9bf7fSAngeloGioacchino Del Regno 
194fdb9bf7fSAngeloGioacchino Del Regno enum an8801r_led_fn {
195fdb9bf7fSAngeloGioacchino Del Regno 	AN8801R_LED_FN_NONE,
196fdb9bf7fSAngeloGioacchino Del Regno 	AN8801R_LED_FN_LINK,
197fdb9bf7fSAngeloGioacchino Del Regno 	AN8801R_LED_FN_ACTIVITY,
198fdb9bf7fSAngeloGioacchino Del Regno 	AN8801R_LED_FN_MAX,
199fdb9bf7fSAngeloGioacchino Del Regno };
200fdb9bf7fSAngeloGioacchino Del Regno 
201fdb9bf7fSAngeloGioacchino Del Regno struct an8801r_priv {
202fdb9bf7fSAngeloGioacchino Del Regno 	bool wake_magic_enabled;
203fdb9bf7fSAngeloGioacchino Del Regno 	bool wake_lnkchg_enabled;
204fdb9bf7fSAngeloGioacchino Del Regno };
205fdb9bf7fSAngeloGioacchino Del Regno 
206fdb9bf7fSAngeloGioacchino Del Regno static const unsigned long an8801r_led_trig = BIT(TRIGGER_NETDEV_LINK) |
207fdb9bf7fSAngeloGioacchino Del Regno 					      BIT(TRIGGER_NETDEV_LINK_10) |
208fdb9bf7fSAngeloGioacchino Del Regno 					      BIT(TRIGGER_NETDEV_LINK_100) |
209fdb9bf7fSAngeloGioacchino Del Regno 					      BIT(TRIGGER_NETDEV_LINK_1000) |
210fdb9bf7fSAngeloGioacchino Del Regno 					      BIT(TRIGGER_NETDEV_RX) |
211fdb9bf7fSAngeloGioacchino Del Regno 					      BIT(TRIGGER_NETDEV_RX_ERR) |
212fdb9bf7fSAngeloGioacchino Del Regno 					      BIT(TRIGGER_NETDEV_TX);
213fdb9bf7fSAngeloGioacchino Del Regno 
214fdb9bf7fSAngeloGioacchino Del Regno static int an8801_buckpbus_reg_rmw(struct phy_device *phydev,
215fdb9bf7fSAngeloGioacchino Del Regno 				   u32 addr, u32 mask, u32 set)
216fdb9bf7fSAngeloGioacchino Del Regno {
217fdb9bf7fSAngeloGioacchino Del Regno 	return air_phy_buckpbus_reg_modify(phydev,
218fdb9bf7fSAngeloGioacchino Del Regno 					   addr | AN8801_PBUS_ACCESS,
219fdb9bf7fSAngeloGioacchino Del Regno 					   mask, set);
220fdb9bf7fSAngeloGioacchino Del Regno }
221fdb9bf7fSAngeloGioacchino Del Regno 
222fdb9bf7fSAngeloGioacchino Del Regno static int an8801_buckpbus_reg_set_bits(struct phy_device *phydev,
223fdb9bf7fSAngeloGioacchino Del Regno 					u32 addr, u32 mask)
224fdb9bf7fSAngeloGioacchino Del Regno {
225fdb9bf7fSAngeloGioacchino Del Regno 	return air_phy_buckpbus_reg_modify(phydev,
226fdb9bf7fSAngeloGioacchino Del Regno 					   addr | AN8801_PBUS_ACCESS,
227fdb9bf7fSAngeloGioacchino Del Regno 					   mask, mask);
228fdb9bf7fSAngeloGioacchino Del Regno }
229fdb9bf7fSAngeloGioacchino Del Regno 
230fdb9bf7fSAngeloGioacchino Del Regno static int an8801_buckpbus_reg_clear_bits(struct phy_device *phydev,
231fdb9bf7fSAngeloGioacchino Del Regno 					  u32 addr, u32 mask)
232fdb9bf7fSAngeloGioacchino Del Regno {
233fdb9bf7fSAngeloGioacchino Del Regno 	return air_phy_buckpbus_reg_modify(phydev,
234fdb9bf7fSAngeloGioacchino Del Regno 					   addr | AN8801_PBUS_ACCESS,
235fdb9bf7fSAngeloGioacchino Del Regno 					   mask, 0);
236fdb9bf7fSAngeloGioacchino Del Regno }
237fdb9bf7fSAngeloGioacchino Del Regno 
238fdb9bf7fSAngeloGioacchino Del Regno static int an8801_buckpbus_reg_write(struct phy_device *phydev, u32 addr,
239fdb9bf7fSAngeloGioacchino Del Regno 				     u32 data)
240fdb9bf7fSAngeloGioacchino Del Regno {
241fdb9bf7fSAngeloGioacchino Del Regno 	return air_phy_buckpbus_reg_write(phydev,
242fdb9bf7fSAngeloGioacchino Del Regno 					  addr | AN8801_PBUS_ACCESS,
243fdb9bf7fSAngeloGioacchino Del Regno 					  data);
244fdb9bf7fSAngeloGioacchino Del Regno }
245fdb9bf7fSAngeloGioacchino Del Regno 
246fdb9bf7fSAngeloGioacchino Del Regno static int an8801_buckpbus_reg_read(struct phy_device *phydev, u32 addr,
247fdb9bf7fSAngeloGioacchino Del Regno 				    u32 *data)
248fdb9bf7fSAngeloGioacchino Del Regno {
249fdb9bf7fSAngeloGioacchino Del Regno 	return air_phy_buckpbus_reg_read(phydev,
250fdb9bf7fSAngeloGioacchino Del Regno 					 addr | AN8801_PBUS_ACCESS,
251fdb9bf7fSAngeloGioacchino Del Regno 					 data);
252fdb9bf7fSAngeloGioacchino Del Regno }
253fdb9bf7fSAngeloGioacchino Del Regno 
254fdb9bf7fSAngeloGioacchino Del Regno static u32 an8801r_led_blink_ms_to_hw(unsigned long req_ms)
255fdb9bf7fSAngeloGioacchino Del Regno {
256fdb9bf7fSAngeloGioacchino Del Regno 	u32 req_ns, regval;
257fdb9bf7fSAngeloGioacchino Del Regno 
258fdb9bf7fSAngeloGioacchino Del Regno 	if (req_ms > AN8801_MAX_PERIOD_MS)
259fdb9bf7fSAngeloGioacchino Del Regno 		req_ms = AN8801_MAX_PERIOD_MS;
260fdb9bf7fSAngeloGioacchino Del Regno 
261fdb9bf7fSAngeloGioacchino Del Regno 	req_ns = req_ms * NSEC_PER_MSEC;
262fdb9bf7fSAngeloGioacchino Del Regno 
263fdb9bf7fSAngeloGioacchino Del Regno 	/* Round to the nearest period unit... */
264fdb9bf7fSAngeloGioacchino Del Regno 	regval = req_ns + (AN8801_PERIOD_UNIT / 2);
265fdb9bf7fSAngeloGioacchino Del Regno 
266fdb9bf7fSAngeloGioacchino Del Regno 	/* ...and now divide by the full period */
267fdb9bf7fSAngeloGioacchino Del Regno 	regval >>= AN8801_PERIOD_SHIFT;
268fdb9bf7fSAngeloGioacchino Del Regno 
269fdb9bf7fSAngeloGioacchino Del Regno 	return regval;
270fdb9bf7fSAngeloGioacchino Del Regno }
271fdb9bf7fSAngeloGioacchino Del Regno 
272fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_blink_set(struct phy_device *phydev, u8 index,
273fdb9bf7fSAngeloGioacchino Del Regno 				 unsigned long *delay_on,
274fdb9bf7fSAngeloGioacchino Del Regno 				 unsigned long *delay_off)
275fdb9bf7fSAngeloGioacchino Del Regno {
276fdb9bf7fSAngeloGioacchino Del Regno 	u32 hw_delay_on, hw_delay_off;
277fdb9bf7fSAngeloGioacchino Del Regno 	u16 blink_dur;
278fdb9bf7fSAngeloGioacchino Del Regno 	bool blink;
279fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
280fdb9bf7fSAngeloGioacchino Del Regno 
281fdb9bf7fSAngeloGioacchino Del Regno 	if (index >= AN8801R_NUM_LEDS)
282fdb9bf7fSAngeloGioacchino Del Regno 		return -EINVAL;
283fdb9bf7fSAngeloGioacchino Del Regno 
284fdb9bf7fSAngeloGioacchino Del Regno 	if (delay_on && delay_off) {
285fdb9bf7fSAngeloGioacchino Del Regno 		blink = true;
286fdb9bf7fSAngeloGioacchino Del Regno 
287fdb9bf7fSAngeloGioacchino Del Regno 		if (*delay_on == 0 || *delay_off == 0) {
288fdb9bf7fSAngeloGioacchino Del Regno 			*delay_on = 64;
289fdb9bf7fSAngeloGioacchino Del Regno 			*delay_off = 64;
290fdb9bf7fSAngeloGioacchino Del Regno 		}
291fdb9bf7fSAngeloGioacchino Del Regno 
292fdb9bf7fSAngeloGioacchino Del Regno 		hw_delay_on = an8801r_led_blink_ms_to_hw(*delay_on);
293fdb9bf7fSAngeloGioacchino Del Regno 		hw_delay_off = an8801r_led_blink_ms_to_hw(*delay_off);
294fdb9bf7fSAngeloGioacchino Del Regno 	} else {
295fdb9bf7fSAngeloGioacchino Del Regno 		blink = false;
296fdb9bf7fSAngeloGioacchino Del Regno 	}
297fdb9bf7fSAngeloGioacchino Del Regno 
298fdb9bf7fSAngeloGioacchino Del Regno 	if (blink) {
299fdb9bf7fSAngeloGioacchino Del Regno 		blink_dur = (u16)min(hw_delay_on + hw_delay_off,
300fdb9bf7fSAngeloGioacchino Del Regno 				     LED_BLINK_DUR_MASK);
301fdb9bf7fSAngeloGioacchino Del Regno 		ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_DUR,
302fdb9bf7fSAngeloGioacchino Del Regno 				    blink_dur);
303fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
304fdb9bf7fSAngeloGioacchino Del Regno 			goto error;
305fdb9bf7fSAngeloGioacchino Del Regno 
306fdb9bf7fSAngeloGioacchino Del Regno 		ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_ON_DUR,
307fdb9bf7fSAngeloGioacchino Del Regno 				    hw_delay_on);
308fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
309fdb9bf7fSAngeloGioacchino Del Regno 			goto error;
310fdb9bf7fSAngeloGioacchino Del Regno 	}
311fdb9bf7fSAngeloGioacchino Del Regno 
312fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index),
313fdb9bf7fSAngeloGioacchino Del Regno 			     LED_BLINK_EVT_MASK,
314fdb9bf7fSAngeloGioacchino Del Regno 			     blink ? LED_BLINK_EVT_FORCE : 0);
315fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
316fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
317fdb9bf7fSAngeloGioacchino Del Regno 
318fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
319fdb9bf7fSAngeloGioacchino Del Regno 			     LED_ON_EVT_MASK,
320fdb9bf7fSAngeloGioacchino Del Regno 			     0);
321fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
322fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
323fdb9bf7fSAngeloGioacchino Del Regno 
324fdb9bf7fSAngeloGioacchino Del Regno 	return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
325fdb9bf7fSAngeloGioacchino Del Regno 			      LED_ON_EN, blink ? LED_ON_EN : 0);
326fdb9bf7fSAngeloGioacchino Del Regno 
327fdb9bf7fSAngeloGioacchino Del Regno error:
328fdb9bf7fSAngeloGioacchino Del Regno 	phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
329fdb9bf7fSAngeloGioacchino Del Regno 		       LED_ON_EN, 0);
330fdb9bf7fSAngeloGioacchino Del Regno 	return ret;
331fdb9bf7fSAngeloGioacchino Del Regno }
332fdb9bf7fSAngeloGioacchino Del Regno 
333fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_brightness_set(struct phy_device *phydev, u8 index,
334fdb9bf7fSAngeloGioacchino Del Regno 				      enum led_brightness value)
335fdb9bf7fSAngeloGioacchino Del Regno {
336fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
337fdb9bf7fSAngeloGioacchino Del Regno 
338fdb9bf7fSAngeloGioacchino Del Regno 	if (index >= AN8801R_NUM_LEDS)
339fdb9bf7fSAngeloGioacchino Del Regno 		return -EINVAL;
340fdb9bf7fSAngeloGioacchino Del Regno 
341fdb9bf7fSAngeloGioacchino Del Regno 	/* Disable blink first if previously enabled */
342fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index),
343fdb9bf7fSAngeloGioacchino Del Regno 			     LED_BLINK_EVT_MASK, 0);
344fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
345fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
346fdb9bf7fSAngeloGioacchino Del Regno 
347fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
348fdb9bf7fSAngeloGioacchino Del Regno 			     LED_ON_EVT_MASK,
349fdb9bf7fSAngeloGioacchino Del Regno 			     (value == LED_OFF) ? 0 : LED_ON_EVT_FORCE);
350fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
351fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
352fdb9bf7fSAngeloGioacchino Del Regno 
353fdb9bf7fSAngeloGioacchino Del Regno 	return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
354fdb9bf7fSAngeloGioacchino Del Regno 			      LED_ON_EN, (value == LED_OFF) ? 0 : LED_ON_EN);
355fdb9bf7fSAngeloGioacchino Del Regno }
356fdb9bf7fSAngeloGioacchino Del Regno 
357fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_hw_control_get(struct phy_device *phydev, u8 index,
358fdb9bf7fSAngeloGioacchino Del Regno 				      unsigned long *rules)
359fdb9bf7fSAngeloGioacchino Del Regno {
360fdb9bf7fSAngeloGioacchino Del Regno 	int on, blink;
361fdb9bf7fSAngeloGioacchino Del Regno 
362fdb9bf7fSAngeloGioacchino Del Regno 	if (index >= AN8801R_NUM_LEDS)
363fdb9bf7fSAngeloGioacchino Del Regno 		return -EINVAL;
364fdb9bf7fSAngeloGioacchino Del Regno 
365fdb9bf7fSAngeloGioacchino Del Regno 	on = phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index));
366fdb9bf7fSAngeloGioacchino Del Regno 	if (on < 0)
367fdb9bf7fSAngeloGioacchino Del Regno 		return on;
368fdb9bf7fSAngeloGioacchino Del Regno 
369fdb9bf7fSAngeloGioacchino Del Regno 	blink = phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index));
370fdb9bf7fSAngeloGioacchino Del Regno 	if (blink < 0)
371fdb9bf7fSAngeloGioacchino Del Regno 		return blink;
372fdb9bf7fSAngeloGioacchino Del Regno 
373fdb9bf7fSAngeloGioacchino Del Regno 	if (FIELD_GET(LED_ON_EVT_LINK_10M, on))
374fdb9bf7fSAngeloGioacchino Del Regno 		__set_bit(TRIGGER_NETDEV_LINK_10, rules);
375fdb9bf7fSAngeloGioacchino Del Regno 
376fdb9bf7fSAngeloGioacchino Del Regno 	if (FIELD_GET(LED_ON_EVT_LINK_100M, on))
377fdb9bf7fSAngeloGioacchino Del Regno 		__set_bit(TRIGGER_NETDEV_LINK_100, rules);
378fdb9bf7fSAngeloGioacchino Del Regno 
379fdb9bf7fSAngeloGioacchino Del Regno 	if (FIELD_GET(LED_ON_EVT_LINK_1000M, on))
380fdb9bf7fSAngeloGioacchino Del Regno 		__set_bit(TRIGGER_NETDEV_LINK_1000, rules);
381fdb9bf7fSAngeloGioacchino Del Regno 
382fdb9bf7fSAngeloGioacchino Del Regno 	if (FIELD_GET(LED_ON_EVT_LINK_10M, on) &&
383fdb9bf7fSAngeloGioacchino Del Regno 	    FIELD_GET(LED_ON_EVT_LINK_100M, on) &&
384fdb9bf7fSAngeloGioacchino Del Regno 	    FIELD_GET(LED_ON_EVT_LINK_1000M, on))
385fdb9bf7fSAngeloGioacchino Del Regno 		__set_bit(TRIGGER_NETDEV_LINK, rules);
386fdb9bf7fSAngeloGioacchino Del Regno 
387fdb9bf7fSAngeloGioacchino Del Regno 	if (FIELD_GET(LED_BLINK_EVT_10M_RX, blink) ||
388fdb9bf7fSAngeloGioacchino Del Regno 	    FIELD_GET(LED_BLINK_EVT_100M_RX, blink) ||
389fdb9bf7fSAngeloGioacchino Del Regno 	    FIELD_GET(LED_BLINK_EVT_1000M_RX, blink))
390fdb9bf7fSAngeloGioacchino Del Regno 		__set_bit(TRIGGER_NETDEV_RX, rules);
391fdb9bf7fSAngeloGioacchino Del Regno 
392fdb9bf7fSAngeloGioacchino Del Regno 	if (FIELD_GET(LED_BLINK_EVT_10M_TX, blink) ||
393fdb9bf7fSAngeloGioacchino Del Regno 	    FIELD_GET(LED_BLINK_EVT_100M_TX, blink) ||
394fdb9bf7fSAngeloGioacchino Del Regno 	    FIELD_GET(LED_BLINK_EVT_1000M_TX, blink))
395fdb9bf7fSAngeloGioacchino Del Regno 		__set_bit(TRIGGER_NETDEV_TX, rules);
396fdb9bf7fSAngeloGioacchino Del Regno 
397fdb9bf7fSAngeloGioacchino Del Regno 	if (FIELD_GET(LED_BLINK_EVT_RX_CRC_ERR, blink))
398fdb9bf7fSAngeloGioacchino Del Regno 		__set_bit(TRIGGER_NETDEV_RX_ERR, rules);
399fdb9bf7fSAngeloGioacchino Del Regno 
400fdb9bf7fSAngeloGioacchino Del Regno 	return 0;
401fdb9bf7fSAngeloGioacchino Del Regno }
402fdb9bf7fSAngeloGioacchino Del Regno 
403fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_trig_to_hw(unsigned long rules, u16 *on, u16 *blink)
404fdb9bf7fSAngeloGioacchino Del Regno {
405fdb9bf7fSAngeloGioacchino Del Regno 	/* All combinations of the supported triggers are allowed */
406fdb9bf7fSAngeloGioacchino Del Regno 	if (rules & ~an8801r_led_trig)
407fdb9bf7fSAngeloGioacchino Del Regno 		return -EOPNOTSUPP;
408fdb9bf7fSAngeloGioacchino Del Regno 
409fdb9bf7fSAngeloGioacchino Del Regno 	if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
410fdb9bf7fSAngeloGioacchino Del Regno 		*on |= LED_ON_EVT_LINK_10M;
411fdb9bf7fSAngeloGioacchino Del Regno 
412fdb9bf7fSAngeloGioacchino Del Regno 	if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
413fdb9bf7fSAngeloGioacchino Del Regno 		*on |= LED_ON_EVT_LINK_100M;
414fdb9bf7fSAngeloGioacchino Del Regno 
415fdb9bf7fSAngeloGioacchino Del Regno 	if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
416fdb9bf7fSAngeloGioacchino Del Regno 		*on |= LED_ON_EVT_LINK_1000M;
417fdb9bf7fSAngeloGioacchino Del Regno 
418fdb9bf7fSAngeloGioacchino Del Regno 	if (test_bit(TRIGGER_NETDEV_LINK, &rules)) {
419fdb9bf7fSAngeloGioacchino Del Regno 		*on |= LED_ON_EVT_LINK_10M;
420fdb9bf7fSAngeloGioacchino Del Regno 		*on |= LED_ON_EVT_LINK_100M;
421fdb9bf7fSAngeloGioacchino Del Regno 		*on |= LED_ON_EVT_LINK_1000M;
422fdb9bf7fSAngeloGioacchino Del Regno 	}
423fdb9bf7fSAngeloGioacchino Del Regno 
424fdb9bf7fSAngeloGioacchino Del Regno 	if (test_bit(TRIGGER_NETDEV_RX, &rules)) {
425fdb9bf7fSAngeloGioacchino Del Regno 		*blink |= LED_BLINK_EVT_10M_RX;
426fdb9bf7fSAngeloGioacchino Del Regno 		*blink |= LED_BLINK_EVT_100M_RX;
427fdb9bf7fSAngeloGioacchino Del Regno 		*blink |= LED_BLINK_EVT_1000M_RX;
428fdb9bf7fSAngeloGioacchino Del Regno 	}
429fdb9bf7fSAngeloGioacchino Del Regno 
430fdb9bf7fSAngeloGioacchino Del Regno 	if (test_bit(TRIGGER_NETDEV_TX, &rules)) {
431fdb9bf7fSAngeloGioacchino Del Regno 		*blink |= LED_BLINK_EVT_10M_TX;
432fdb9bf7fSAngeloGioacchino Del Regno 		*blink |= LED_BLINK_EVT_100M_TX;
433fdb9bf7fSAngeloGioacchino Del Regno 		*blink |= LED_BLINK_EVT_1000M_TX;
434fdb9bf7fSAngeloGioacchino Del Regno 	}
435fdb9bf7fSAngeloGioacchino Del Regno 
436fdb9bf7fSAngeloGioacchino Del Regno 	if (test_bit(TRIGGER_NETDEV_RX_ERR, &rules))
437fdb9bf7fSAngeloGioacchino Del Regno 		*blink |= LED_BLINK_EVT_RX_CRC_ERR;
438fdb9bf7fSAngeloGioacchino Del Regno 
439fdb9bf7fSAngeloGioacchino Del Regno 	return 0;
440fdb9bf7fSAngeloGioacchino Del Regno }
441fdb9bf7fSAngeloGioacchino Del Regno 
442fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_hw_is_supported(struct phy_device *phydev, u8 index,
443fdb9bf7fSAngeloGioacchino Del Regno 				       unsigned long rules)
444fdb9bf7fSAngeloGioacchino Del Regno {
445fdb9bf7fSAngeloGioacchino Del Regno 	u16 on = 0, blink = 0;
446fdb9bf7fSAngeloGioacchino Del Regno 
447fdb9bf7fSAngeloGioacchino Del Regno 	if (index >= AN8801R_NUM_LEDS)
448fdb9bf7fSAngeloGioacchino Del Regno 		return -EINVAL;
449fdb9bf7fSAngeloGioacchino Del Regno 
450fdb9bf7fSAngeloGioacchino Del Regno 	return an8801r_led_trig_to_hw(rules, &on, &blink);
451fdb9bf7fSAngeloGioacchino Del Regno }
452fdb9bf7fSAngeloGioacchino Del Regno 
453fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_hw_control_set(struct phy_device *phydev, u8 index,
454fdb9bf7fSAngeloGioacchino Del Regno 				      unsigned long rules)
455fdb9bf7fSAngeloGioacchino Del Regno {
456fdb9bf7fSAngeloGioacchino Del Regno 	u16 on = 0, blink = 0;
457fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
458fdb9bf7fSAngeloGioacchino Del Regno 
459fdb9bf7fSAngeloGioacchino Del Regno 	if (index >= AN8801R_NUM_LEDS)
460fdb9bf7fSAngeloGioacchino Del Regno 		return -EINVAL;
461fdb9bf7fSAngeloGioacchino Del Regno 
462fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801r_led_trig_to_hw(rules, &on, &blink);
463fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
464fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
465fdb9bf7fSAngeloGioacchino Del Regno 
466fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
467fdb9bf7fSAngeloGioacchino Del Regno 			     LED_ON_EVT_MASK, on);
468fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
469fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
470fdb9bf7fSAngeloGioacchino Del Regno 
471fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index),
472fdb9bf7fSAngeloGioacchino Del Regno 			     LED_BLINK_EVT_MASK, blink);
473fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
474fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
475fdb9bf7fSAngeloGioacchino Del Regno 
476fdb9bf7fSAngeloGioacchino Del Regno 	return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
477fdb9bf7fSAngeloGioacchino Del Regno 			      LED_ON_EN, (on | blink) ? LED_ON_EN : 0);
478fdb9bf7fSAngeloGioacchino Del Regno }
479fdb9bf7fSAngeloGioacchino Del Regno 
480fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_polarity_set(struct phy_device *phydev, int index,
481fdb9bf7fSAngeloGioacchino Del Regno 				    unsigned long modes)
482fdb9bf7fSAngeloGioacchino Del Regno {
483fdb9bf7fSAngeloGioacchino Del Regno 	bool active_high = true;
484fdb9bf7fSAngeloGioacchino Del Regno 	unsigned long mode;
485fdb9bf7fSAngeloGioacchino Del Regno 
486fdb9bf7fSAngeloGioacchino Del Regno 	if (index >= AN8801R_NUM_LEDS)
487fdb9bf7fSAngeloGioacchino Del Regno 		return -EINVAL;
488fdb9bf7fSAngeloGioacchino Del Regno 
489fdb9bf7fSAngeloGioacchino Del Regno 	for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
490fdb9bf7fSAngeloGioacchino Del Regno 		switch (mode) {
491fdb9bf7fSAngeloGioacchino Del Regno 		case PHY_LED_ACTIVE_HIGH:
492fdb9bf7fSAngeloGioacchino Del Regno 			break;
493fdb9bf7fSAngeloGioacchino Del Regno 		case PHY_LED_ACTIVE_LOW:
494fdb9bf7fSAngeloGioacchino Del Regno 			active_high = false;
495fdb9bf7fSAngeloGioacchino Del Regno 			break;
496fdb9bf7fSAngeloGioacchino Del Regno 		default:
497fdb9bf7fSAngeloGioacchino Del Regno 			return -EINVAL;
498fdb9bf7fSAngeloGioacchino Del Regno 		}
499fdb9bf7fSAngeloGioacchino Del Regno 	}
500fdb9bf7fSAngeloGioacchino Del Regno 
501fdb9bf7fSAngeloGioacchino Del Regno 	return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
502fdb9bf7fSAngeloGioacchino Del Regno 			      LED_ON_POL, active_high ? LED_ON_POL : 0);
503fdb9bf7fSAngeloGioacchino Del Regno }
504fdb9bf7fSAngeloGioacchino Del Regno 
505fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_init(struct phy_device *phydev, u8 *led_cfg)
506fdb9bf7fSAngeloGioacchino Del Regno {
507fdb9bf7fSAngeloGioacchino Del Regno 	int led_id, ret;
508fdb9bf7fSAngeloGioacchino Del Regno 
509fdb9bf7fSAngeloGioacchino Del Regno 	/* Set LED BCR Enable */
510fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, LED_BCR,
511fdb9bf7fSAngeloGioacchino Del Regno 			       LED_BCR_EXT_CTRL | LED_BCR_CLK_EN);
512fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
513fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
514fdb9bf7fSAngeloGioacchino Del Regno 
515fdb9bf7fSAngeloGioacchino Del Regno 	for (led_id = 0; led_id < AN8801R_NUM_LEDS; led_id++) {
516fdb9bf7fSAngeloGioacchino Del Regno 		unsigned long led_trigger = 0;
517fdb9bf7fSAngeloGioacchino Del Regno 		u32 led_gpio = led_id + 1;
518fdb9bf7fSAngeloGioacchino Del Regno 
519fdb9bf7fSAngeloGioacchino Del Regno 		switch (led_cfg[led_id]) {
520fdb9bf7fSAngeloGioacchino Del Regno 		case AN8801R_LED_FN_LINK:
521fdb9bf7fSAngeloGioacchino Del Regno 			led_trigger = BIT(TRIGGER_NETDEV_LINK);
522fdb9bf7fSAngeloGioacchino Del Regno 			break;
523fdb9bf7fSAngeloGioacchino Del Regno 		case AN8801R_LED_FN_ACTIVITY:
524fdb9bf7fSAngeloGioacchino Del Regno 			led_trigger = BIT(TRIGGER_NETDEV_RX) |
525fdb9bf7fSAngeloGioacchino Del Regno 				    BIT(TRIGGER_NETDEV_TX);
526fdb9bf7fSAngeloGioacchino Del Regno 			break;
527fdb9bf7fSAngeloGioacchino Del Regno 		default:
528fdb9bf7fSAngeloGioacchino Del Regno 			led_trigger = 0;
529fdb9bf7fSAngeloGioacchino Del Regno 			break;
530fdb9bf7fSAngeloGioacchino Del Regno 		}
531fdb9bf7fSAngeloGioacchino Del Regno 
532fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_set_bits(phydev,
533fdb9bf7fSAngeloGioacchino Del Regno 						   AN8801_BPBUS_REG_LED_GPIO,
534fdb9bf7fSAngeloGioacchino Del Regno 						   BIT(led_gpio));
535fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
536fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
537fdb9bf7fSAngeloGioacchino Del Regno 
538fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_rmw(phydev,
539fdb9bf7fSAngeloGioacchino Del Regno 					      AN8801_BPBUS_REG_LED_ID_SEL,
540fdb9bf7fSAngeloGioacchino Del Regno 					      LED_ID_GPIO_SEL_MASK(led_gpio),
541fdb9bf7fSAngeloGioacchino Del Regno 					      LED_ID_GPIO_SEL(led_id,
542fdb9bf7fSAngeloGioacchino Del Regno 							      led_gpio));
543fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
544fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
545fdb9bf7fSAngeloGioacchino Del Regno 
546fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_clear_bits(phydev,
547fdb9bf7fSAngeloGioacchino Del Regno 						     AN8801_BPBUS_REG_GPIO_MODE,
548fdb9bf7fSAngeloGioacchino Del Regno 						     BIT(led_gpio));
549fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
550fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
551fdb9bf7fSAngeloGioacchino Del Regno 
552fdb9bf7fSAngeloGioacchino Del Regno 		if (!led_trigger)
553fdb9bf7fSAngeloGioacchino Del Regno 			continue;
554fdb9bf7fSAngeloGioacchino Del Regno 
555fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801r_led_hw_control_set(phydev, led_id, led_trigger);
556fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
557fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
558fdb9bf7fSAngeloGioacchino Del Regno 	}
559fdb9bf7fSAngeloGioacchino Del Regno 
560fdb9bf7fSAngeloGioacchino Del Regno 	return ret;
561fdb9bf7fSAngeloGioacchino Del Regno }
562fdb9bf7fSAngeloGioacchino Del Regno 
563fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_reset_wake(struct phy_device *phydev)
564fdb9bf7fSAngeloGioacchino Del Regno {
565fdb9bf7fSAngeloGioacchino Del Regno 	struct an8801r_priv *priv = phydev->priv;
566fdb9bf7fSAngeloGioacchino Del Regno 	u32 reg_val = 0;
567fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
568fdb9bf7fSAngeloGioacchino Del Regno 
569fdb9bf7fSAngeloGioacchino Del Regno 	/* Enable wakeup clear and disable wake up output */
570fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL2,
571fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_PME_WAKEUP_CLR |
572fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_WAKE_OUT_POLARITY_NEG);
573fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
574fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
575fdb9bf7fSAngeloGioacchino Del Regno 
576fdb9bf7fSAngeloGioacchino Del Regno 	/* Clear WAKEUP_CTL1 register before enabling the wakeup events
577fdb9bf7fSAngeloGioacchino Del Regno 	 * again
578fdb9bf7fSAngeloGioacchino Del Regno 	 */
579fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1,
580fdb9bf7fSAngeloGioacchino Del Regno 					0);
581fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
582fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
583fdb9bf7fSAngeloGioacchino Del Regno 
584fdb9bf7fSAngeloGioacchino Del Regno 	if (priv->wake_magic_enabled)
585fdb9bf7fSAngeloGioacchino Del Regno 		reg_val |= AN8801_WOL_WAKE_MAGIC_EN;
586fdb9bf7fSAngeloGioacchino Del Regno 
587fdb9bf7fSAngeloGioacchino Del Regno 	if (priv->wake_lnkchg_enabled)
588fdb9bf7fSAngeloGioacchino Del Regno 		reg_val |= AN8801_WOL_WAKE_LNKCHG_EN;
589fdb9bf7fSAngeloGioacchino Del Regno 
590fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1,
591fdb9bf7fSAngeloGioacchino Del Regno 					reg_val);
592fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
593fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
594fdb9bf7fSAngeloGioacchino Del Regno 
595fdb9bf7fSAngeloGioacchino Del Regno 	/* Disable wake up clear and re-enable wake up output */
596fdb9bf7fSAngeloGioacchino Del Regno 	return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL2,
597fdb9bf7fSAngeloGioacchino Del Regno 					 AN8801_WAKE_OUT_POLARITY_NEG |
598fdb9bf7fSAngeloGioacchino Del Regno 					 AN8801_WAKE_OUT_EN);
599fdb9bf7fSAngeloGioacchino Del Regno }
600fdb9bf7fSAngeloGioacchino Del Regno 
601fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_ack_interrupt(struct phy_device *phydev)
602fdb9bf7fSAngeloGioacchino Del Regno {
603fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
604fdb9bf7fSAngeloGioacchino Del Regno 
605fdb9bf7fSAngeloGioacchino Del Regno 	/* Reset wake status */
606fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801r_reset_wake(phydev);
607fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
608fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
609fdb9bf7fSAngeloGioacchino Del Regno 
610fdb9bf7fSAngeloGioacchino Del Regno 	/* Clear the interrupts by writing the reg */
611fdb9bf7fSAngeloGioacchino Del Regno 	return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKE_IRQ_STS,
612fdb9bf7fSAngeloGioacchino Del Regno 					 AN8801_IRQ_WAKE_ALL);
613fdb9bf7fSAngeloGioacchino Del Regno }
614fdb9bf7fSAngeloGioacchino Del Regno 
615fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_config_intr(struct phy_device *phydev)
616fdb9bf7fSAngeloGioacchino Del Regno {
617fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
618fdb9bf7fSAngeloGioacchino Del Regno 
619fdb9bf7fSAngeloGioacchino Del Regno 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
620fdb9bf7fSAngeloGioacchino Del Regno 		u32 val = FIELD_PREP(AN8801_PHY_IRQ_GPIO_NUM_MASK,
621fdb9bf7fSAngeloGioacchino Del Regno 				     AN8801_PHY_IRQ_GPIO_NUM);
622fdb9bf7fSAngeloGioacchino Del Regno 
623fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_write(phydev,
624fdb9bf7fSAngeloGioacchino Del Regno 						AN8801_BPBUS_REG_PHY_IRQ_GPIO,
625fdb9bf7fSAngeloGioacchino Del Regno 						val);
626fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
627fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
628fdb9bf7fSAngeloGioacchino Del Regno 
629fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_set_bits(phydev,
630fdb9bf7fSAngeloGioacchino Del Regno 						   AN8801_BPBUS_REG_WAKE_IRQ_EN,
631fdb9bf7fSAngeloGioacchino Del Regno 						   AN8801_IRQ_WAKE_LNKCHG);
632fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
633fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
634fdb9bf7fSAngeloGioacchino Del Regno 
635fdb9bf7fSAngeloGioacchino Del Regno 	} else {
636fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_write(phydev,
637fdb9bf7fSAngeloGioacchino Del Regno 						AN8801_BPBUS_REG_PHY_IRQ_GPIO,
638fdb9bf7fSAngeloGioacchino Del Regno 						0);
639fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
640fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
641fdb9bf7fSAngeloGioacchino Del Regno 
642fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_clear_bits(phydev,
643fdb9bf7fSAngeloGioacchino Del Regno 						     AN8801_BPBUS_REG_WAKE_IRQ_EN,
644fdb9bf7fSAngeloGioacchino Del Regno 						     AN8801_IRQ_WAKE_LNKCHG);
645fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
646fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
647fdb9bf7fSAngeloGioacchino Del Regno 	}
648fdb9bf7fSAngeloGioacchino Del Regno 
649fdb9bf7fSAngeloGioacchino Del Regno 	return an8801r_ack_interrupt(phydev);
650fdb9bf7fSAngeloGioacchino Del Regno }
651fdb9bf7fSAngeloGioacchino Del Regno 
652fdb9bf7fSAngeloGioacchino Del Regno static irqreturn_t an8801r_handle_interrupt(struct phy_device *phydev)
653fdb9bf7fSAngeloGioacchino Del Regno {
654fdb9bf7fSAngeloGioacchino Del Regno 	u32 irq_status = 0;
655fdb9bf7fSAngeloGioacchino Del Regno 	bool irq_handled = false;
656fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
657fdb9bf7fSAngeloGioacchino Del Regno 
658fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801_buckpbus_reg_read(phydev, AN8801_BPBUS_REG_WAKE_IRQ_STS,
659fdb9bf7fSAngeloGioacchino Del Regno 				       &irq_status);
660fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
661fdb9bf7fSAngeloGioacchino Del Regno 		return IRQ_NONE;
662fdb9bf7fSAngeloGioacchino Del Regno 
663fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801r_ack_interrupt(phydev);
664fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
665fdb9bf7fSAngeloGioacchino Del Regno 		return IRQ_NONE;
666fdb9bf7fSAngeloGioacchino Del Regno 
667fdb9bf7fSAngeloGioacchino Del Regno 	if (irq_status & AN8801_IRQ_WAKE_MAGICPKT) {
668fdb9bf7fSAngeloGioacchino Del Regno 		pm_wakeup_event(&phydev->mdio.dev, 0);
669fdb9bf7fSAngeloGioacchino Del Regno 		irq_handled = true;
670fdb9bf7fSAngeloGioacchino Del Regno 	}
671fdb9bf7fSAngeloGioacchino Del Regno 
672fdb9bf7fSAngeloGioacchino Del Regno 	if (irq_status & AN8801_IRQ_WAKE_LNKCHG) {
673fdb9bf7fSAngeloGioacchino Del Regno 		phy_trigger_machine(phydev);
674fdb9bf7fSAngeloGioacchino Del Regno 		irq_handled = true;
675fdb9bf7fSAngeloGioacchino Del Regno 	}
676fdb9bf7fSAngeloGioacchino Del Regno 
677fdb9bf7fSAngeloGioacchino Del Regno 	return irq_handled ? IRQ_HANDLED : IRQ_NONE;
678fdb9bf7fSAngeloGioacchino Del Regno }
679fdb9bf7fSAngeloGioacchino Del Regno 
680fdb9bf7fSAngeloGioacchino Del Regno static void an8801r_get_wol(struct phy_device *phydev,
681fdb9bf7fSAngeloGioacchino Del Regno 			    struct ethtool_wolinfo *wol)
682fdb9bf7fSAngeloGioacchino Del Regno {
683fdb9bf7fSAngeloGioacchino Del Regno 	u32 reg_val;
684fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
685fdb9bf7fSAngeloGioacchino Del Regno 
686fdb9bf7fSAngeloGioacchino Del Regno 	/* If the PHY is not capable of waking the system, then WoL can not
687fdb9bf7fSAngeloGioacchino Del Regno 	 * be supported.
688fdb9bf7fSAngeloGioacchino Del Regno 	 */
689fdb9bf7fSAngeloGioacchino Del Regno 	if (!device_can_wakeup(&phydev->mdio.dev)) {
690fdb9bf7fSAngeloGioacchino Del Regno 		wol->supported = 0;
691fdb9bf7fSAngeloGioacchino Del Regno 		return;
692fdb9bf7fSAngeloGioacchino Del Regno 	}
693fdb9bf7fSAngeloGioacchino Del Regno 
694fdb9bf7fSAngeloGioacchino Del Regno 	wol->supported = WAKE_MAGIC;
695fdb9bf7fSAngeloGioacchino Del Regno 	wol->wolopts = 0;
696fdb9bf7fSAngeloGioacchino Del Regno 
697fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801_buckpbus_reg_read(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1,
698fdb9bf7fSAngeloGioacchino Del Regno 				       &reg_val);
699fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
700fdb9bf7fSAngeloGioacchino Del Regno 		return;
701fdb9bf7fSAngeloGioacchino Del Regno 
702fdb9bf7fSAngeloGioacchino Del Regno 	if (reg_val & AN8801_WOL_WAKE_MAGIC_EN)
703fdb9bf7fSAngeloGioacchino Del Regno 		wol->wolopts |= WAKE_MAGIC;
704fdb9bf7fSAngeloGioacchino Del Regno 	else
705fdb9bf7fSAngeloGioacchino Del Regno 		wol->wolopts &= ~WAKE_MAGIC;
706fdb9bf7fSAngeloGioacchino Del Regno }
707fdb9bf7fSAngeloGioacchino Del Regno 
708fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_set_wol(struct phy_device *phydev,
709fdb9bf7fSAngeloGioacchino Del Regno 			   struct ethtool_wolinfo *wol)
710fdb9bf7fSAngeloGioacchino Del Regno {
711fdb9bf7fSAngeloGioacchino Del Regno 	struct an8801r_priv *priv = phydev->priv;
712fdb9bf7fSAngeloGioacchino Del Regno 	struct net_device *attach_dev;
713fdb9bf7fSAngeloGioacchino Del Regno 	const u8 *macaddr;
714fdb9bf7fSAngeloGioacchino Del Regno 	u32 reg_val;
715fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
716fdb9bf7fSAngeloGioacchino Del Regno 
717fdb9bf7fSAngeloGioacchino Del Regno 	if (!device_can_wakeup(&phydev->mdio.dev))
718fdb9bf7fSAngeloGioacchino Del Regno 		return -EOPNOTSUPP;
719fdb9bf7fSAngeloGioacchino Del Regno 
720fdb9bf7fSAngeloGioacchino Del Regno 	if (wol->wolopts & ~WAKE_MAGIC)
721fdb9bf7fSAngeloGioacchino Del Regno 		return -EINVAL;
722fdb9bf7fSAngeloGioacchino Del Regno 
723fdb9bf7fSAngeloGioacchino Del Regno 	if (wol->wolopts & WAKE_MAGIC) {
724fdb9bf7fSAngeloGioacchino Del Regno 		attach_dev = phydev->attached_dev;
725fdb9bf7fSAngeloGioacchino Del Regno 		if (!attach_dev)
726fdb9bf7fSAngeloGioacchino Del Regno 			return -ENODEV;
727fdb9bf7fSAngeloGioacchino Del Regno 
728fdb9bf7fSAngeloGioacchino Del Regno 		macaddr = (const u8 *)attach_dev->dev_addr;
729fdb9bf7fSAngeloGioacchino Del Regno 		if (!is_valid_ether_addr(macaddr))
730fdb9bf7fSAngeloGioacchino Del Regno 			return -EINVAL;
731fdb9bf7fSAngeloGioacchino Del Regno 
732fdb9bf7fSAngeloGioacchino Del Regno 		/* MAC bits 16..47 */
733fdb9bf7fSAngeloGioacchino Del Regno 		reg_val = (macaddr[2] << 24) | (macaddr[3] << 16);
734fdb9bf7fSAngeloGioacchino Del Regno 		reg_val |= (macaddr[4] << 8) | (macaddr[5]);
735fdb9bf7fSAngeloGioacchino Del Regno 
736fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_write(phydev,
737fdb9bf7fSAngeloGioacchino Del Regno 						AN8801_BPBUS_REG_WOL_MAC_16_47,
738fdb9bf7fSAngeloGioacchino Del Regno 						reg_val);
739fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
740fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
741fdb9bf7fSAngeloGioacchino Del Regno 
742fdb9bf7fSAngeloGioacchino Del Regno 		/* MAC bits 0..15 */
743fdb9bf7fSAngeloGioacchino Del Regno 		reg_val = (macaddr[0] << 8) | (macaddr[1]);
744fdb9bf7fSAngeloGioacchino Del Regno 
745fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_write(phydev,
746fdb9bf7fSAngeloGioacchino Del Regno 						AN8801_BPBUS_REG_WOL_MAC_0_15,
747fdb9bf7fSAngeloGioacchino Del Regno 						reg_val);
748fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
749fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
750fdb9bf7fSAngeloGioacchino Del Regno 
751fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_set_bits(phydev,
752fdb9bf7fSAngeloGioacchino Del Regno 						   AN8801_BPBUS_REG_WAKEUP_CTL1,
753fdb9bf7fSAngeloGioacchino Del Regno 						   AN8801_WOL_WAKE_MAGIC_EN);
754fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
755fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
756fdb9bf7fSAngeloGioacchino Del Regno 
757fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_set_bits(phydev,
758fdb9bf7fSAngeloGioacchino Del Regno 						   AN8801_BPBUS_REG_WAKE_IRQ_EN,
759fdb9bf7fSAngeloGioacchino Del Regno 						   AN8801_IRQ_WAKE_MAGICPKT);
760fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
761fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
762fdb9bf7fSAngeloGioacchino Del Regno 
763fdb9bf7fSAngeloGioacchino Del Regno 	} else {
764fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_clear_bits(phydev,
765fdb9bf7fSAngeloGioacchino Del Regno 						     AN8801_BPBUS_REG_WAKEUP_CTL1,
766fdb9bf7fSAngeloGioacchino Del Regno 						     AN8801_WOL_WAKE_MAGIC_EN);
767fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
768fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
769fdb9bf7fSAngeloGioacchino Del Regno 
770fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_clear_bits(phydev,
771fdb9bf7fSAngeloGioacchino Del Regno 						     AN8801_BPBUS_REG_WAKE_IRQ_EN,
772fdb9bf7fSAngeloGioacchino Del Regno 						     AN8801_IRQ_WAKE_MAGICPKT);
773fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
774fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
775fdb9bf7fSAngeloGioacchino Del Regno 	}
776fdb9bf7fSAngeloGioacchino Del Regno 
777fdb9bf7fSAngeloGioacchino Del Regno 	priv->wake_magic_enabled = !!(wol->wolopts & WAKE_MAGIC);
778fdb9bf7fSAngeloGioacchino Del Regno 
779fdb9bf7fSAngeloGioacchino Del Regno 	return device_set_wakeup_enable(&phydev->mdio.dev,
780fdb9bf7fSAngeloGioacchino Del Regno 					priv->wake_magic_enabled);
781fdb9bf7fSAngeloGioacchino Del Regno }
782fdb9bf7fSAngeloGioacchino Del Regno 
783fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_of_init_leds(struct phy_device *phydev, u8 *led_cfg)
784fdb9bf7fSAngeloGioacchino Del Regno {
785fdb9bf7fSAngeloGioacchino Del Regno 	struct device *dev = &phydev->mdio.dev;
786fdb9bf7fSAngeloGioacchino Del Regno 	struct device_node *np = dev->of_node;
787fdb9bf7fSAngeloGioacchino Del Regno 	struct device_node *leds;
788fdb9bf7fSAngeloGioacchino Del Regno 	u32 function_enum_idx;
789fdb9bf7fSAngeloGioacchino Del Regno 	int ret = 0;
790fdb9bf7fSAngeloGioacchino Del Regno 
791fdb9bf7fSAngeloGioacchino Del Regno 	if (!np)
792fdb9bf7fSAngeloGioacchino Del Regno 		return 0;
793fdb9bf7fSAngeloGioacchino Del Regno 
794fdb9bf7fSAngeloGioacchino Del Regno 	/* If devicetree is present, leds configuration is required */
795fdb9bf7fSAngeloGioacchino Del Regno 	leds = of_get_child_by_name(np, "leds");
796fdb9bf7fSAngeloGioacchino Del Regno 	if (!leds)
797fdb9bf7fSAngeloGioacchino Del Regno 		return 0;
798fdb9bf7fSAngeloGioacchino Del Regno 
799fdb9bf7fSAngeloGioacchino Del Regno 	for_each_available_child_of_node_scoped(leds, led) {
800fdb9bf7fSAngeloGioacchino Del Regno 		u32 led_idx;
801fdb9bf7fSAngeloGioacchino Del Regno 
802fdb9bf7fSAngeloGioacchino Del Regno 		ret = of_property_read_u32(led, "reg", &led_idx);
803fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
804fdb9bf7fSAngeloGioacchino Del Regno 			goto out;
805fdb9bf7fSAngeloGioacchino Del Regno 
806fdb9bf7fSAngeloGioacchino Del Regno 		if (led_idx >= AN8801R_NUM_LEDS) {
807fdb9bf7fSAngeloGioacchino Del Regno 			ret = -EINVAL;
808fdb9bf7fSAngeloGioacchino Del Regno 			goto out;
809fdb9bf7fSAngeloGioacchino Del Regno 		}
810fdb9bf7fSAngeloGioacchino Del Regno 
811fdb9bf7fSAngeloGioacchino Del Regno 		ret = of_property_read_u32(led, "function-enumerator",
812fdb9bf7fSAngeloGioacchino Del Regno 					   &function_enum_idx);
813fdb9bf7fSAngeloGioacchino Del Regno 		if (ret) {
814fdb9bf7fSAngeloGioacchino Del Regno 			function_enum_idx = AN8801R_LED_FN_NONE;
815fdb9bf7fSAngeloGioacchino Del Regno 			ret = 0;
816fdb9bf7fSAngeloGioacchino Del Regno 		}
817fdb9bf7fSAngeloGioacchino Del Regno 
818fdb9bf7fSAngeloGioacchino Del Regno 		if (function_enum_idx >= AN8801R_LED_FN_MAX) {
819fdb9bf7fSAngeloGioacchino Del Regno 			ret = -EINVAL;
820fdb9bf7fSAngeloGioacchino Del Regno 			goto out;
821fdb9bf7fSAngeloGioacchino Del Regno 		}
822fdb9bf7fSAngeloGioacchino Del Regno 
823fdb9bf7fSAngeloGioacchino Del Regno 		led_cfg[led_idx] = function_enum_idx;
824fdb9bf7fSAngeloGioacchino Del Regno 	}
825fdb9bf7fSAngeloGioacchino Del Regno out:
826fdb9bf7fSAngeloGioacchino Del Regno 	of_node_put(leds);
827fdb9bf7fSAngeloGioacchino Del Regno 	return ret;
828fdb9bf7fSAngeloGioacchino Del Regno }
829fdb9bf7fSAngeloGioacchino Del Regno 
830fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_rgmii_rxdelay(struct phy_device *phydev, bool enable,
831fdb9bf7fSAngeloGioacchino Del Regno 				 u16 delay_steps)
832fdb9bf7fSAngeloGioacchino Del Regno {
833fdb9bf7fSAngeloGioacchino Del Regno 	u32 reg_val;
834fdb9bf7fSAngeloGioacchino Del Regno 
835fdb9bf7fSAngeloGioacchino Del Regno 	if (delay_steps > RGMII_DELAY_STEP_MASK)
836fdb9bf7fSAngeloGioacchino Del Regno 		return -EINVAL;
837fdb9bf7fSAngeloGioacchino Del Regno 
838fdb9bf7fSAngeloGioacchino Del Regno 	if (enable) {
839fdb9bf7fSAngeloGioacchino Del Regno 		/* Set force mode bit to enable RX delay insertion */
840fdb9bf7fSAngeloGioacchino Del Regno 		reg_val = delay_steps | RGMII_RXDELAY_FORCE_MODE;
841fdb9bf7fSAngeloGioacchino Del Regno 
842fdb9bf7fSAngeloGioacchino Del Regno 		/* Set align bit to add extra offset for RX delay */
843fdb9bf7fSAngeloGioacchino Del Regno 		reg_val |= RGMII_RXDELAY_ALIGN;
844fdb9bf7fSAngeloGioacchino Del Regno 	} else {
845fdb9bf7fSAngeloGioacchino Del Regno 		reg_val = 0;
846fdb9bf7fSAngeloGioacchino Del Regno 	}
847fdb9bf7fSAngeloGioacchino Del Regno 
848fdb9bf7fSAngeloGioacchino Del Regno 	return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_RXDLY_STEP,
849fdb9bf7fSAngeloGioacchino Del Regno 					 reg_val);
850fdb9bf7fSAngeloGioacchino Del Regno }
851fdb9bf7fSAngeloGioacchino Del Regno 
852fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_rgmii_txdelay(struct phy_device *phydev, bool enable,
853fdb9bf7fSAngeloGioacchino Del Regno 				 u16 delay_steps)
854fdb9bf7fSAngeloGioacchino Del Regno {
855fdb9bf7fSAngeloGioacchino Del Regno 	u32 reg_val;
856fdb9bf7fSAngeloGioacchino Del Regno 
857fdb9bf7fSAngeloGioacchino Del Regno 	if (delay_steps > RGMII_DELAY_STEP_MASK)
858fdb9bf7fSAngeloGioacchino Del Regno 		return -EINVAL;
859fdb9bf7fSAngeloGioacchino Del Regno 
860fdb9bf7fSAngeloGioacchino Del Regno 	if (enable) {
861fdb9bf7fSAngeloGioacchino Del Regno 		/* Set force mode bit to enable TX delay insertion */
862fdb9bf7fSAngeloGioacchino Del Regno 		reg_val = delay_steps | RGMII_TXDELAY_FORCE_MODE;
863fdb9bf7fSAngeloGioacchino Del Regno 	} else {
864fdb9bf7fSAngeloGioacchino Del Regno 		reg_val = 0;
865fdb9bf7fSAngeloGioacchino Del Regno 	}
866fdb9bf7fSAngeloGioacchino Del Regno 
867fdb9bf7fSAngeloGioacchino Del Regno 	return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_TXDLY_STEP,
868fdb9bf7fSAngeloGioacchino Del Regno 					 reg_val);
869fdb9bf7fSAngeloGioacchino Del Regno }
870fdb9bf7fSAngeloGioacchino Del Regno 
871fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_rgmii_delay_config(struct phy_device *phydev)
872fdb9bf7fSAngeloGioacchino Del Regno {
873fdb9bf7fSAngeloGioacchino Del Regno 	bool enable_delay;
874fdb9bf7fSAngeloGioacchino Del Regno 	u16 delay_step;
875fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
876fdb9bf7fSAngeloGioacchino Del Regno 
877fdb9bf7fSAngeloGioacchino Del Regno 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
878fdb9bf7fSAngeloGioacchino Del Regno 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
879fdb9bf7fSAngeloGioacchino Del Regno 		enable_delay = true;
880fdb9bf7fSAngeloGioacchino Del Regno 		delay_step = AN8801_RGMII_TXDELAY_DEFAULT;
881fdb9bf7fSAngeloGioacchino Del Regno 	} else {
882fdb9bf7fSAngeloGioacchino Del Regno 		enable_delay = false;
883fdb9bf7fSAngeloGioacchino Del Regno 		delay_step = RGMII_DELAY_NO_STEP;
884fdb9bf7fSAngeloGioacchino Del Regno 	}
885fdb9bf7fSAngeloGioacchino Del Regno 
886fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801r_rgmii_txdelay(phydev, enable_delay, delay_step);
887fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
888fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
889fdb9bf7fSAngeloGioacchino Del Regno 
890fdb9bf7fSAngeloGioacchino Del Regno 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
891fdb9bf7fSAngeloGioacchino Del Regno 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
892fdb9bf7fSAngeloGioacchino Del Regno 		enable_delay = true;
893fdb9bf7fSAngeloGioacchino Del Regno 		delay_step = AN8801_RGMII_RXDELAY_DEFAULT;
894fdb9bf7fSAngeloGioacchino Del Regno 	} else {
895fdb9bf7fSAngeloGioacchino Del Regno 		enable_delay = false;
896fdb9bf7fSAngeloGioacchino Del Regno 		delay_step = RGMII_DELAY_NO_STEP;
897fdb9bf7fSAngeloGioacchino Del Regno 	}
898fdb9bf7fSAngeloGioacchino Del Regno 
899fdb9bf7fSAngeloGioacchino Del Regno 	return an8801r_rgmii_rxdelay(phydev, enable_delay, delay_step);
900fdb9bf7fSAngeloGioacchino Del Regno }
901fdb9bf7fSAngeloGioacchino Del Regno 
902fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_config_init(struct phy_device *phydev)
903fdb9bf7fSAngeloGioacchino Del Regno {
904fdb9bf7fSAngeloGioacchino Del Regno 	u8 led_default_function[AN8801R_NUM_LEDS] = { 0 };
905fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
906fdb9bf7fSAngeloGioacchino Del Regno 
907fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801r_of_init_leds(phydev, led_default_function);
908fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
909fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
910fdb9bf7fSAngeloGioacchino Del Regno 
911fdb9bf7fSAngeloGioacchino Del Regno 	/* Disable Low Power Mode (LPM) */
912fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL0,
913fdb9bf7fSAngeloGioacchino Del Regno 			    FIELD_PREP(AN8801_PHY_INTFUNC_MASK, 0x1e));
914fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
915fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
916fdb9bf7fSAngeloGioacchino Del Regno 
917fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL1,
918fdb9bf7fSAngeloGioacchino Del Regno 			    FIELD_PREP(AN8801_PHY_INTFUNC_MASK, 0x2));
919fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
920fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
921fdb9bf7fSAngeloGioacchino Del Regno 
922fdb9bf7fSAngeloGioacchino Del Regno 	/* Set the PHY to perform auto-downshift after 3 auto-negotiation
923fdb9bf7fSAngeloGioacchino Del Regno 	 * attempts
924fdb9bf7fSAngeloGioacchino Del Regno 	 */
925fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_write_paged(phydev, AIR_PHY_PAGE_EXTENDED_1,
926fdb9bf7fSAngeloGioacchino Del Regno 			      AN8801_EXT_REG_PHY,
927fdb9bf7fSAngeloGioacchino Del Regno 			      FIELD_PREP(AN8801_EXT_PHY_CTRL1, 0x1d) |
928fdb9bf7fSAngeloGioacchino Del Regno 			      FIELD_PREP(AN8801_EXT_PHY_DOWNSHIFT_CTL, 1) |
929fdb9bf7fSAngeloGioacchino Del Regno 			      AN8801_EXT_PHY_DOWNSHIFT_EN);
930fdb9bf7fSAngeloGioacchino Del Regno 	if (ret < 0)
931fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
932fdb9bf7fSAngeloGioacchino Del Regno 
933fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_BYPASS_PTP,
934fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_BYP_PTP_RGMII_TO_GPHY);
935fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
936fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
937fdb9bf7fSAngeloGioacchino Del Regno 
938fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(0),
939fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_EFIFO_RX_EN |
940fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_EFIFO_TX_EN |
941fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_EFIFO_RX_CLK_EN |
942fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_EFIFO_TX_CLK_EN |
943fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_EFIFO_RX_EEE_EN |
944fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_EFIFO_TX_EEE_EN);
945fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
946fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
947fdb9bf7fSAngeloGioacchino Del Regno 
948fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(1),
949fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_EFIFO_ALL_EN);
950fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
951fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
952fdb9bf7fSAngeloGioacchino Del Regno 
953fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(2),
954fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_EFIFO_ALL_EN);
955fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
956fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
957fdb9bf7fSAngeloGioacchino Del Regno 
958fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
959fdb9bf7fSAngeloGioacchino Del Regno 			    AN8801_PHY_TX_PAIR_DLY_SEL_GBE,
960fdb9bf7fSAngeloGioacchino Del Regno 			    FIELD_PREP(AN8801_PHY_PAIR_DLY_SEL_A_GBE, 4) |
961fdb9bf7fSAngeloGioacchino Del Regno 			    FIELD_PREP(AN8801_PHY_PAIR_DLY_SEL_C_GBE, 4));
962fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
963fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
964fdb9bf7fSAngeloGioacchino Del Regno 
965fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_CTRL,
966fdb9bf7fSAngeloGioacchino Del Regno 			    AN8801_PHY_RXADC_SAMP_PHSEL_A |
967fdb9bf7fSAngeloGioacchino Del Regno 			    AN8801_PHY_RXADC_SAMP_PHSEL_C);
968fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
969fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
970fdb9bf7fSAngeloGioacchino Del Regno 
971fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_REV_0,
972fdb9bf7fSAngeloGioacchino Del Regno 			    FIELD_PREP(AN8801_PHY_RXADC_REV_MASK_A, 1));
973fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
974fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
975fdb9bf7fSAngeloGioacchino Del Regno 
976fdb9bf7fSAngeloGioacchino Del Regno 	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_REV_1,
977fdb9bf7fSAngeloGioacchino Del Regno 			    FIELD_PREP(AN8801_PHY_RXADC_REV_MASK_C, 1));
978fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
979fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
980fdb9bf7fSAngeloGioacchino Del Regno 
981fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801r_rgmii_delay_config(phydev);
982fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
983fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
984fdb9bf7fSAngeloGioacchino Del Regno 
985fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_CKO,
986fdb9bf7fSAngeloGioacchino Del Regno 					AN8801_CKO_OUTPUT_MODE_AUTO);
987fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
988fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
989fdb9bf7fSAngeloGioacchino Del Regno 
990fdb9bf7fSAngeloGioacchino Del Regno 	ret = an8801r_led_init(phydev, led_default_function);
991fdb9bf7fSAngeloGioacchino Del Regno 	if (ret) {
992fdb9bf7fSAngeloGioacchino Del Regno 		phydev_err(phydev, "Cannot initialize LEDs: %d\n", ret);
993fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
994fdb9bf7fSAngeloGioacchino Del Regno 	}
995fdb9bf7fSAngeloGioacchino Del Regno 
996fdb9bf7fSAngeloGioacchino Del Regno 	return 0;
997fdb9bf7fSAngeloGioacchino Del Regno }
998fdb9bf7fSAngeloGioacchino Del Regno 
999*f6465e36SLouis-Alexis Eyraud static int an8801r_read_status(struct phy_device *phydev)
1000*f6465e36SLouis-Alexis Eyraud {
1001*f6465e36SLouis-Alexis Eyraud 	int prev_speed, ret;
1002*f6465e36SLouis-Alexis Eyraud 	u32 val;
1003*f6465e36SLouis-Alexis Eyraud 
1004*f6465e36SLouis-Alexis Eyraud 	prev_speed = phydev->speed;
1005*f6465e36SLouis-Alexis Eyraud 
1006*f6465e36SLouis-Alexis Eyraud 	ret = genphy_read_status(phydev);
1007*f6465e36SLouis-Alexis Eyraud 	if (ret)
1008*f6465e36SLouis-Alexis Eyraud 		return ret;
1009*f6465e36SLouis-Alexis Eyraud 
1010*f6465e36SLouis-Alexis Eyraud 	if (!phydev->link) {
1011*f6465e36SLouis-Alexis Eyraud 		phydev->speed = SPEED_UNKNOWN;
1012*f6465e36SLouis-Alexis Eyraud 		return 0;
1013*f6465e36SLouis-Alexis Eyraud 	}
1014*f6465e36SLouis-Alexis Eyraud 
1015*f6465e36SLouis-Alexis Eyraud 	if (prev_speed != phydev->speed) {
1016*f6465e36SLouis-Alexis Eyraud 		/* Ensure that PHY switches to 1G speed when available,
1017*f6465e36SLouis-Alexis Eyraud 		 * by configuring the function mode for either 1G or 100M/10M
1018*f6465e36SLouis-Alexis Eyraud 		 * operation.
1019*f6465e36SLouis-Alexis Eyraud 		 * Therefore, set the link mode register, after read_status
1020*f6465e36SLouis-Alexis Eyraud 		 * determines the link speed.
1021*f6465e36SLouis-Alexis Eyraud 		 */
1022*f6465e36SLouis-Alexis Eyraud 		val = phydev->speed == SPEED_1000 ?
1023*f6465e36SLouis-Alexis Eyraud 		      AN8801_BPBUS_LINK_MODE_1000 : 0;
1024*f6465e36SLouis-Alexis Eyraud 
1025*f6465e36SLouis-Alexis Eyraud 		return an8801_buckpbus_reg_rmw(phydev,
1026*f6465e36SLouis-Alexis Eyraud 					       AN8801_BPBUS_REG_LINK_MODE,
1027*f6465e36SLouis-Alexis Eyraud 					       AN8801_BPBUS_LINK_MODE_1000,
1028*f6465e36SLouis-Alexis Eyraud 					       val);
1029*f6465e36SLouis-Alexis Eyraud 	}
1030*f6465e36SLouis-Alexis Eyraud 
1031*f6465e36SLouis-Alexis Eyraud 	return 0;
1032*f6465e36SLouis-Alexis Eyraud }
1033*f6465e36SLouis-Alexis Eyraud 
1034fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_probe(struct phy_device *phydev)
1035fdb9bf7fSAngeloGioacchino Del Regno {
1036fdb9bf7fSAngeloGioacchino Del Regno 	struct device *dev = &phydev->mdio.dev;
1037fdb9bf7fSAngeloGioacchino Del Regno 	struct an8801r_priv *priv;
1038fdb9bf7fSAngeloGioacchino Del Regno 
1039fdb9bf7fSAngeloGioacchino Del Regno 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1040fdb9bf7fSAngeloGioacchino Del Regno 	if (!priv)
1041fdb9bf7fSAngeloGioacchino Del Regno 		return -ENOMEM;
1042fdb9bf7fSAngeloGioacchino Del Regno 
1043fdb9bf7fSAngeloGioacchino Del Regno 	priv->wake_lnkchg_enabled = true;
1044fdb9bf7fSAngeloGioacchino Del Regno 
1045fdb9bf7fSAngeloGioacchino Del Regno 	phydev->priv = priv;
1046fdb9bf7fSAngeloGioacchino Del Regno 
1047fdb9bf7fSAngeloGioacchino Del Regno 	/* Mark this PHY as wakeup capable and register the interrupt as a
1048fdb9bf7fSAngeloGioacchino Del Regno 	 * wakeup IRQ if the PHY is marked as a wakeup source in devicetree,
1049fdb9bf7fSAngeloGioacchino Del Regno 	 * and the interrupt is valid.
1050fdb9bf7fSAngeloGioacchino Del Regno 	 */
1051fdb9bf7fSAngeloGioacchino Del Regno 	if (of_property_read_bool(dev->of_node, "wakeup-source") &&
1052fdb9bf7fSAngeloGioacchino Del Regno 	    phy_interrupt_is_valid(phydev)) {
1053fdb9bf7fSAngeloGioacchino Del Regno 		device_set_wakeup_capable(dev, true);
1054fdb9bf7fSAngeloGioacchino Del Regno 		devm_pm_set_wake_irq(dev, phydev->irq);
1055fdb9bf7fSAngeloGioacchino Del Regno 	}
1056fdb9bf7fSAngeloGioacchino Del Regno 
1057fdb9bf7fSAngeloGioacchino Del Regno 	return 0;
1058fdb9bf7fSAngeloGioacchino Del Regno }
1059fdb9bf7fSAngeloGioacchino Del Regno 
1060fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_suspend(struct phy_device *phydev)
1061fdb9bf7fSAngeloGioacchino Del Regno {
1062fdb9bf7fSAngeloGioacchino Del Regno 	struct an8801r_priv *priv = phydev->priv;
1063fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
1064fdb9bf7fSAngeloGioacchino Del Regno 
1065fdb9bf7fSAngeloGioacchino Del Regno 	/* If the PHY may wake up by a Wake-on-LAN (WOL) event, disable the link
1066fdb9bf7fSAngeloGioacchino Del Regno 	 * interrupt to only keep the WOL magic interrupt enabled
1067fdb9bf7fSAngeloGioacchino Del Regno 	 */
1068fdb9bf7fSAngeloGioacchino Del Regno 	if (device_may_wakeup(&phydev->mdio.dev)) {
1069fdb9bf7fSAngeloGioacchino Del Regno 		priv->wake_lnkchg_enabled = false;
1070fdb9bf7fSAngeloGioacchino Del Regno 
1071fdb9bf7fSAngeloGioacchino Del Regno 		if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
1072fdb9bf7fSAngeloGioacchino Del Regno 			ret = an8801_buckpbus_reg_clear_bits(phydev,
1073fdb9bf7fSAngeloGioacchino Del Regno 							     AN8801_BPBUS_REG_WAKE_IRQ_EN,
1074fdb9bf7fSAngeloGioacchino Del Regno 							     AN8801_IRQ_WAKE_LNKCHG);
1075fdb9bf7fSAngeloGioacchino Del Regno 			if (ret)
1076fdb9bf7fSAngeloGioacchino Del Regno 				return ret;
1077fdb9bf7fSAngeloGioacchino Del Regno 		}
1078fdb9bf7fSAngeloGioacchino Del Regno 
1079fdb9bf7fSAngeloGioacchino Del Regno 		/* Reset WOL status */
1080fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801r_reset_wake(phydev);
1081fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
1082fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
1083fdb9bf7fSAngeloGioacchino Del Regno 	}
1084fdb9bf7fSAngeloGioacchino Del Regno 
1085fdb9bf7fSAngeloGioacchino Del Regno 	if (!phydev->wol_enabled)
1086fdb9bf7fSAngeloGioacchino Del Regno 		return genphy_suspend(phydev);
1087fdb9bf7fSAngeloGioacchino Del Regno 
1088fdb9bf7fSAngeloGioacchino Del Regno 	return 0;
1089fdb9bf7fSAngeloGioacchino Del Regno }
1090fdb9bf7fSAngeloGioacchino Del Regno 
1091fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_resume(struct phy_device *phydev)
1092fdb9bf7fSAngeloGioacchino Del Regno {
1093fdb9bf7fSAngeloGioacchino Del Regno 	struct an8801r_priv *priv = phydev->priv;
1094fdb9bf7fSAngeloGioacchino Del Regno 	int ret;
1095fdb9bf7fSAngeloGioacchino Del Regno 
1096fdb9bf7fSAngeloGioacchino Del Regno 	ret = genphy_resume(phydev);
1097fdb9bf7fSAngeloGioacchino Del Regno 	if (ret)
1098fdb9bf7fSAngeloGioacchino Del Regno 		return ret;
1099fdb9bf7fSAngeloGioacchino Del Regno 
1100fdb9bf7fSAngeloGioacchino Del Regno 	/* Restore the interrupt enable so phylib can receive link
1101fdb9bf7fSAngeloGioacchino Del Regno 	 * state interrupts.
1102fdb9bf7fSAngeloGioacchino Del Regno 	 */
1103fdb9bf7fSAngeloGioacchino Del Regno 	if (device_may_wakeup(&phydev->mdio.dev)) {
1104fdb9bf7fSAngeloGioacchino Del Regno 		priv->wake_lnkchg_enabled = true;
1105fdb9bf7fSAngeloGioacchino Del Regno 
1106fdb9bf7fSAngeloGioacchino Del Regno 		ret = an8801_buckpbus_reg_set_bits(phydev,
1107fdb9bf7fSAngeloGioacchino Del Regno 						   AN8801_BPBUS_REG_WAKEUP_CTL1,
1108fdb9bf7fSAngeloGioacchino Del Regno 						   AN8801_WOL_WAKE_LNKCHG_EN);
1109fdb9bf7fSAngeloGioacchino Del Regno 		if (ret)
1110fdb9bf7fSAngeloGioacchino Del Regno 			return ret;
1111fdb9bf7fSAngeloGioacchino Del Regno 
1112fdb9bf7fSAngeloGioacchino Del Regno 		if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
1113fdb9bf7fSAngeloGioacchino Del Regno 			ret = an8801_buckpbus_reg_set_bits(phydev,
1114fdb9bf7fSAngeloGioacchino Del Regno 							   AN8801_BPBUS_REG_WAKE_IRQ_EN,
1115fdb9bf7fSAngeloGioacchino Del Regno 							   AN8801_IRQ_WAKE_LNKCHG);
1116fdb9bf7fSAngeloGioacchino Del Regno 		}
1117fdb9bf7fSAngeloGioacchino Del Regno 	}
1118fdb9bf7fSAngeloGioacchino Del Regno 
1119fdb9bf7fSAngeloGioacchino Del Regno 	return ret;
1120fdb9bf7fSAngeloGioacchino Del Regno }
1121fdb9bf7fSAngeloGioacchino Del Regno 
1122fdb9bf7fSAngeloGioacchino Del Regno static struct phy_driver airoha_driver[] = {
1123fdb9bf7fSAngeloGioacchino Del Regno {
1124fdb9bf7fSAngeloGioacchino Del Regno 	PHY_ID_MATCH_MODEL(AN8801R_PHY_ID),
1125fdb9bf7fSAngeloGioacchino Del Regno 	.name			= "Airoha AN8801R",
1126fdb9bf7fSAngeloGioacchino Del Regno 	.probe			= an8801r_probe,
1127fdb9bf7fSAngeloGioacchino Del Regno 	.config_init		= an8801r_config_init,
1128fdb9bf7fSAngeloGioacchino Del Regno 	.suspend		= an8801r_suspend,
1129fdb9bf7fSAngeloGioacchino Del Regno 	.resume			= an8801r_resume,
1130fdb9bf7fSAngeloGioacchino Del Regno 	.config_aneg		= genphy_config_aneg,
1131*f6465e36SLouis-Alexis Eyraud 	.read_status		= an8801r_read_status,
1132fdb9bf7fSAngeloGioacchino Del Regno 	.config_intr		= an8801r_config_intr,
1133fdb9bf7fSAngeloGioacchino Del Regno 	.handle_interrupt	= an8801r_handle_interrupt,
1134fdb9bf7fSAngeloGioacchino Del Regno 	.set_wol		= an8801r_set_wol,
1135fdb9bf7fSAngeloGioacchino Del Regno 	.get_wol		= an8801r_get_wol,
1136fdb9bf7fSAngeloGioacchino Del Regno 	.read_page		= air_phy_read_page,
1137fdb9bf7fSAngeloGioacchino Del Regno 	.write_page		= air_phy_write_page,
1138fdb9bf7fSAngeloGioacchino Del Regno 	.flags			= PHY_ALWAYS_CALL_SUSPEND,
1139fdb9bf7fSAngeloGioacchino Del Regno 	.led_brightness_set	= an8801r_led_brightness_set,
1140fdb9bf7fSAngeloGioacchino Del Regno 	.led_blink_set		= an8801r_led_blink_set,
1141fdb9bf7fSAngeloGioacchino Del Regno 	.led_hw_is_supported	= an8801r_led_hw_is_supported,
1142fdb9bf7fSAngeloGioacchino Del Regno 	.led_hw_control_set	= an8801r_led_hw_control_set,
1143fdb9bf7fSAngeloGioacchino Del Regno 	.led_hw_control_get	= an8801r_led_hw_control_get,
1144fdb9bf7fSAngeloGioacchino Del Regno 	.led_polarity_set	= an8801r_led_polarity_set,
1145fdb9bf7fSAngeloGioacchino Del Regno } };
1146fdb9bf7fSAngeloGioacchino Del Regno module_phy_driver(airoha_driver);
1147fdb9bf7fSAngeloGioacchino Del Regno 
1148fdb9bf7fSAngeloGioacchino Del Regno static struct mdio_device_id __maybe_unused an8801_tbl[] = {
1149fdb9bf7fSAngeloGioacchino Del Regno 	{ PHY_ID_MATCH_MODEL(AN8801R_PHY_ID) },
1150fdb9bf7fSAngeloGioacchino Del Regno 	{ }
1151fdb9bf7fSAngeloGioacchino Del Regno };
1152fdb9bf7fSAngeloGioacchino Del Regno MODULE_DEVICE_TABLE(mdio, an8801_tbl);
1153fdb9bf7fSAngeloGioacchino Del Regno 
1154fdb9bf7fSAngeloGioacchino Del Regno MODULE_DESCRIPTION("Airoha AN8801 PHY driver");
1155fdb9bf7fSAngeloGioacchino Del Regno MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
1156fdb9bf7fSAngeloGioacchino Del Regno MODULE_LICENSE("GPL");
1157