xref: /linux/drivers/net/phy/mediatek/mtk-phy-lib.c (revision fcc79e1714e8c2b8e216dc3149812edd37884eef)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/phy.h>
3 #include <linux/module.h>
4 
5 #include <linux/netdevice.h>
6 
7 #include "mtk.h"
8 
9 int mtk_phy_read_page(struct phy_device *phydev)
10 {
11 	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
12 }
13 EXPORT_SYMBOL_GPL(mtk_phy_read_page);
14 
15 int mtk_phy_write_page(struct phy_device *phydev, int page)
16 {
17 	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
18 }
19 EXPORT_SYMBOL_GPL(mtk_phy_write_page);
20 
21 int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
22 				unsigned long rules,
23 				unsigned long supported_triggers)
24 {
25 	if (index > 1)
26 		return -EINVAL;
27 
28 	/* All combinations of the supported triggers are allowed */
29 	if (rules & ~supported_triggers)
30 		return -EOPNOTSUPP;
31 
32 	return 0;
33 }
34 EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported);
35 
36 int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
37 			    unsigned long *rules, u16 on_set,
38 			    u16 rx_blink_set, u16 tx_blink_set)
39 {
40 	unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
41 				 (index ? 16 : 0);
42 	unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
43 	unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
44 	struct mtk_socphy_priv *priv = phydev->priv;
45 	int on, blink;
46 
47 	if (index > 1)
48 		return -EINVAL;
49 
50 	on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
51 			  index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
52 
53 	if (on < 0)
54 		return -EIO;
55 
56 	blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
57 			     index ? MTK_PHY_LED1_BLINK_CTRL :
58 				     MTK_PHY_LED0_BLINK_CTRL);
59 	if (blink < 0)
60 		return -EIO;
61 
62 	if ((on & (on_set | MTK_PHY_LED_ON_FDX |
63 		   MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
64 	    (blink & (rx_blink_set | tx_blink_set)))
65 		set_bit(bit_netdev, &priv->led_state);
66 	else
67 		clear_bit(bit_netdev, &priv->led_state);
68 
69 	if (on & MTK_PHY_LED_ON_FORCE_ON)
70 		set_bit(bit_on, &priv->led_state);
71 	else
72 		clear_bit(bit_on, &priv->led_state);
73 
74 	if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
75 		set_bit(bit_blink, &priv->led_state);
76 	else
77 		clear_bit(bit_blink, &priv->led_state);
78 
79 	if (!rules)
80 		return 0;
81 
82 	if (on & on_set)
83 		*rules |= BIT(TRIGGER_NETDEV_LINK);
84 
85 	if (on & MTK_PHY_LED_ON_LINK10)
86 		*rules |= BIT(TRIGGER_NETDEV_LINK_10);
87 
88 	if (on & MTK_PHY_LED_ON_LINK100)
89 		*rules |= BIT(TRIGGER_NETDEV_LINK_100);
90 
91 	if (on & MTK_PHY_LED_ON_LINK1000)
92 		*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
93 
94 	if (on & MTK_PHY_LED_ON_LINK2500)
95 		*rules |= BIT(TRIGGER_NETDEV_LINK_2500);
96 
97 	if (on & MTK_PHY_LED_ON_FDX)
98 		*rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
99 
100 	if (on & MTK_PHY_LED_ON_HDX)
101 		*rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
102 
103 	if (blink & rx_blink_set)
104 		*rules |= BIT(TRIGGER_NETDEV_RX);
105 
106 	if (blink & tx_blink_set)
107 		*rules |= BIT(TRIGGER_NETDEV_TX);
108 
109 	return 0;
110 }
111 EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get);
112 
113 int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
114 			    unsigned long rules, u16 on_set,
115 			    u16 rx_blink_set, u16 tx_blink_set)
116 {
117 	unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
118 	struct mtk_socphy_priv *priv = phydev->priv;
119 	u16 on = 0, blink = 0;
120 	int ret;
121 
122 	if (index > 1)
123 		return -EINVAL;
124 
125 	if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
126 		on |= MTK_PHY_LED_ON_FDX;
127 
128 	if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
129 		on |= MTK_PHY_LED_ON_HDX;
130 
131 	if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
132 		on |= MTK_PHY_LED_ON_LINK10;
133 
134 	if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
135 		on |= MTK_PHY_LED_ON_LINK100;
136 
137 	if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
138 		on |= MTK_PHY_LED_ON_LINK1000;
139 
140 	if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
141 		on |= MTK_PHY_LED_ON_LINK2500;
142 
143 	if (rules & BIT(TRIGGER_NETDEV_RX)) {
144 		if (on & on_set) {
145 			if (on & MTK_PHY_LED_ON_LINK10)
146 				blink |= MTK_PHY_LED_BLINK_10RX;
147 			if (on & MTK_PHY_LED_ON_LINK100)
148 				blink |= MTK_PHY_LED_BLINK_100RX;
149 			if (on & MTK_PHY_LED_ON_LINK1000)
150 				blink |= MTK_PHY_LED_BLINK_1000RX;
151 			if (on & MTK_PHY_LED_ON_LINK2500)
152 				blink |= MTK_PHY_LED_BLINK_2500RX;
153 		} else {
154 			blink |= rx_blink_set;
155 		}
156 	}
157 
158 	if (rules & BIT(TRIGGER_NETDEV_TX)) {
159 		if (on & on_set) {
160 			if (on & MTK_PHY_LED_ON_LINK10)
161 				blink |= MTK_PHY_LED_BLINK_10TX;
162 			if (on & MTK_PHY_LED_ON_LINK100)
163 				blink |= MTK_PHY_LED_BLINK_100TX;
164 			if (on & MTK_PHY_LED_ON_LINK1000)
165 				blink |= MTK_PHY_LED_BLINK_1000TX;
166 			if (on & MTK_PHY_LED_ON_LINK2500)
167 				blink |= MTK_PHY_LED_BLINK_2500TX;
168 		} else {
169 			blink |= tx_blink_set;
170 		}
171 	}
172 
173 	if (blink || on)
174 		set_bit(bit_netdev, &priv->led_state);
175 	else
176 		clear_bit(bit_netdev, &priv->led_state);
177 
178 	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
179 			     MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
180 			     MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set,
181 			     on);
182 
183 	if (ret)
184 		return ret;
185 
186 	return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
187 			     MTK_PHY_LED1_BLINK_CTRL :
188 			     MTK_PHY_LED0_BLINK_CTRL, blink);
189 }
190 EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set);
191 
192 int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
193 			    unsigned long *delay_off, bool *blinking)
194 {
195 	if (index > 1)
196 		return -EINVAL;
197 
198 	if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
199 		*blinking = true;
200 		*delay_on = 50;
201 		*delay_off = 50;
202 	}
203 
204 	return 0;
205 }
206 EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg);
207 
208 int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
209 			  u16 led_on_mask, bool on)
210 {
211 	unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
212 	struct mtk_socphy_priv *priv = phydev->priv;
213 	bool changed;
214 
215 	if (on)
216 		changed = !test_and_set_bit(bit_on, &priv->led_state);
217 	else
218 		changed = !!test_and_clear_bit(bit_on, &priv->led_state);
219 
220 	changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
221 					(index ? 16 : 0), &priv->led_state);
222 	if (changed)
223 		return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
224 				      MTK_PHY_LED1_ON_CTRL :
225 				      MTK_PHY_LED0_ON_CTRL,
226 				      led_on_mask,
227 				      on ? MTK_PHY_LED_ON_FORCE_ON : 0);
228 	else
229 		return 0;
230 }
231 EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set);
232 
233 int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking)
234 {
235 	unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
236 				 (index ? 16 : 0);
237 	struct mtk_socphy_priv *priv = phydev->priv;
238 	bool changed;
239 
240 	if (blinking)
241 		changed = !test_and_set_bit(bit_blink, &priv->led_state);
242 	else
243 		changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
244 
245 	changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
246 			      (index ? 16 : 0), &priv->led_state);
247 	if (changed)
248 		return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
249 				     MTK_PHY_LED1_BLINK_CTRL :
250 				     MTK_PHY_LED0_BLINK_CTRL,
251 				     blinking ?
252 				     MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
253 	else
254 		return 0;
255 }
256 EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set);
257 
258 void mtk_phy_leds_state_init(struct phy_device *phydev)
259 {
260 	int i;
261 
262 	for (i = 0; i < 2; ++i)
263 		phydev->drv->led_hw_control_get(phydev, i, NULL);
264 }
265 EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
266 
267 MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
268 MODULE_AUTHOR("Sky Huang <SkyLake.Huang@mediatek.com>");
269 MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
270 MODULE_LICENSE("GPL");
271