xref: /linux/drivers/net/ethernet/adi/adin1140.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1*20e69e67SCiprian Regus // SPDX-License-Identifier: GPL-2.0+
2*20e69e67SCiprian Regus /*
3*20e69e67SCiprian Regus  * Driver for Analog Devices, Inc. ADIN1140 10BASE-T1S MAC-PHY
4*20e69e67SCiprian Regus  *
5*20e69e67SCiprian Regus  * Copyright 2026 Analog Devices Inc.
6*20e69e67SCiprian Regus  */
7*20e69e67SCiprian Regus 
8*20e69e67SCiprian Regus #include <linux/cleanup.h>
9*20e69e67SCiprian Regus #include <linux/etherdevice.h>
10*20e69e67SCiprian Regus #include <linux/kernel.h>
11*20e69e67SCiprian Regus #include <linux/mdio.h>
12*20e69e67SCiprian Regus #include <linux/module.h>
13*20e69e67SCiprian Regus #include <linux/oa_tc6.h>
14*20e69e67SCiprian Regus #include <linux/phy.h>
15*20e69e67SCiprian Regus 
16*20e69e67SCiprian Regus #define ADIN1140_MAC_CONFIG2_STAT_CLR_RD	BIT(6)
17*20e69e67SCiprian Regus #define ADIN1140_MAC_CONFIG2_FWD_UNK2HOST	BIT(2)
18*20e69e67SCiprian Regus 
19*20e69e67SCiprian Regus #define ADIN1140_MAC_P1_LOOP_ADDR_REG	0xC4
20*20e69e67SCiprian Regus 
21*20e69e67SCiprian Regus #define ADIN1140_MAC_ADDR_FILT_UPR_REG		0x50
22*20e69e67SCiprian Regus #define ADIN1140_MAC_ADDR_FILT_APPLY2PORT1	BIT(30)
23*20e69e67SCiprian Regus #define ADIN1140_MAC_ADDR_FILT_TO_HOST		BIT(16)
24*20e69e67SCiprian Regus 
25*20e69e67SCiprian Regus #define ADIN1140_MAC_ADDR_FILT_LWR_REG		0x51
26*20e69e67SCiprian Regus 
27*20e69e67SCiprian Regus #define ADIN1140_MAC_ADDR_MASK_UPR_REG	0x70
28*20e69e67SCiprian Regus #define ADIN1140_MAC_ADDR_MASK_LWR_REG	0x71
29*20e69e67SCiprian Regus 
30*20e69e67SCiprian Regus #define ADIN1140_MAC_FILT_MC_SLOT	0U
31*20e69e67SCiprian Regus #define ADIN1140_MAC_FILT_BC_SLOT	1U
32*20e69e67SCiprian Regus #define ADIN1140_MAC_FILT_UC_SLOT	2U
33*20e69e67SCiprian Regus #define ADIN1140_MAC_FILT_MAX_SLOT	16U
34*20e69e67SCiprian Regus #define ADIN1140_MAC_FILT_MASK_LIMIT	2U
35*20e69e67SCiprian Regus 
36*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_FRAME_CNT		0xA1
37*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_BC_FRAME_CNT		0xA2
38*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_MC_FRAME_CNT		0xA3
39*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_CRC_ERR_CNT		0xA5
40*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_ALIGN_ERR_CNT		0xA6
41*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_PREAMBLE_ERR_CNT	0xA7
42*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_SHORT_ERR_CNT		0xA8
43*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_LONG_ERR_CNT		0xA9
44*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_PHY_ERR_CNT		0xAA
45*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_DRP_FULL_CNT		0xAB
46*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_DRP_FILTER_CNT		0xAD
47*20e69e67SCiprian Regus #define ADIN1140_MAC_RX_IFG_ERR_CNT		0xAE
48*20e69e67SCiprian Regus #define ADIN1140_MAC_TX_FRAME_CNT		0xB1
49*20e69e67SCiprian Regus #define ADIN1140_MAC_TX_BC_FRAME_CNT		0xB2
50*20e69e67SCiprian Regus #define ADIN1140_MAC_TX_MC_FRAME_CNT		0xB3
51*20e69e67SCiprian Regus #define ADIN1140_MAC_TX_SINGLE_COL_CNT		0xB5
52*20e69e67SCiprian Regus #define ADIN1140_MAC_TX_MULTI_COL_CNT		0xB6
53*20e69e67SCiprian Regus #define ADIN1140_MAC_TX_DEFERRED_CNT		0xB7
54*20e69e67SCiprian Regus #define ADIN1140_MAC_TX_LATE_COL_CNT		0xB8
55*20e69e67SCiprian Regus #define ADIN1140_MAC_TX_EXCESS_COL_CNT		0xB9
56*20e69e67SCiprian Regus #define ADIN1140_MAC_TX_UNDERRUN_CNT		0xBA
57*20e69e67SCiprian Regus 
58*20e69e67SCiprian Regus /* ADIN1140_MAC_FILT_MAX_SLOT - 3 (multicast, broadcast and unicast
59*20e69e67SCiprian Regus  * reserved slots)
60*20e69e67SCiprian Regus  */
61*20e69e67SCiprian Regus #define ADIN1140_MAC_FILT_AVAIL	13U
62*20e69e67SCiprian Regus 
63*20e69e67SCiprian Regus #define ADIN1140_PHY_CTRL_DEFAULT	0x1000
64*20e69e67SCiprian Regus #define ADIN1140_PHY_STATUS_DEFAULT	0x082D
65*20e69e67SCiprian Regus #define ADIN1140_PHY_ID1		0x0283
66*20e69e67SCiprian Regus #define ADIN1140_PHY_ID2		0xBE00
67*20e69e67SCiprian Regus 
68*20e69e67SCiprian Regus #define ADIN1140_STATS_CHECK_DELAY	(3 * HZ)
69*20e69e67SCiprian Regus 
70*20e69e67SCiprian Regus enum adin1140_statistics_entry {
71*20e69e67SCiprian Regus 	rx_frames,
72*20e69e67SCiprian Regus 	rx_bc_frames,
73*20e69e67SCiprian Regus 	rx_mc_frames,
74*20e69e67SCiprian Regus 	rx_crc_errors,
75*20e69e67SCiprian Regus 	rx_align_errors,
76*20e69e67SCiprian Regus 	rx_preamble_errors,
77*20e69e67SCiprian Regus 	rx_short_frame_errors,
78*20e69e67SCiprian Regus 	rx_long_frame_errors,
79*20e69e67SCiprian Regus 	rx_phy_errors,
80*20e69e67SCiprian Regus 	rx_fifo_full_dropped,
81*20e69e67SCiprian Regus 	rx_addr_filter_dropped,
82*20e69e67SCiprian Regus 	rx_ifg_errors,
83*20e69e67SCiprian Regus 	tx_frames,
84*20e69e67SCiprian Regus 	tx_bc_frames,
85*20e69e67SCiprian Regus 	tx_mc_frames,
86*20e69e67SCiprian Regus 	tx_single_collision,
87*20e69e67SCiprian Regus 	tx_multi_collision,
88*20e69e67SCiprian Regus 	tx_deferred,
89*20e69e67SCiprian Regus 	tx_late_collision,
90*20e69e67SCiprian Regus 	tx_excess_collision,
91*20e69e67SCiprian Regus 	tx_underrun,
92*20e69e67SCiprian Regus 	ADIN1140_STATS_CNT,
93*20e69e67SCiprian Regus };
94*20e69e67SCiprian Regus 
95*20e69e67SCiprian Regus struct adin1140_statistics_reg {
96*20e69e67SCiprian Regus 	const char *name;
97*20e69e67SCiprian Regus 	enum adin1140_statistics_entry idx;
98*20e69e67SCiprian Regus };
99*20e69e67SCiprian Regus 
100*20e69e67SCiprian Regus struct adin1140_priv {
101*20e69e67SCiprian Regus 	struct net_device *netdev;
102*20e69e67SCiprian Regus 	struct oa_tc6 *tc6;
103*20e69e67SCiprian Regus 	struct mii_bus *mdiobus;
104*20e69e67SCiprian Regus 	struct phy_device *phydev;
105*20e69e67SCiprian Regus 	struct delayed_work stats_work;
106*20e69e67SCiprian Regus 
107*20e69e67SCiprian Regus 	/* Protects stats[] from concurrent updates in adin1140_stats_work
108*20e69e67SCiprian Regus 	 * and reads in the get_stats functions
109*20e69e67SCiprian Regus 	 */
110*20e69e67SCiprian Regus 	spinlock_t stat_lock;
111*20e69e67SCiprian Regus 	u64 stats[ADIN1140_STATS_CNT];
112*20e69e67SCiprian Regus };
113*20e69e67SCiprian Regus 
114*20e69e67SCiprian Regus static const u32 adin1140_stat_regs[] = {
115*20e69e67SCiprian Regus 	[rx_frames] = ADIN1140_MAC_RX_FRAME_CNT,
116*20e69e67SCiprian Regus 	[rx_bc_frames] = ADIN1140_MAC_RX_BC_FRAME_CNT,
117*20e69e67SCiprian Regus 	[rx_mc_frames] = ADIN1140_MAC_RX_MC_FRAME_CNT,
118*20e69e67SCiprian Regus 	[rx_crc_errors] = ADIN1140_MAC_RX_CRC_ERR_CNT,
119*20e69e67SCiprian Regus 	[rx_align_errors] = ADIN1140_MAC_RX_ALIGN_ERR_CNT,
120*20e69e67SCiprian Regus 	[rx_preamble_errors] = ADIN1140_MAC_RX_PREAMBLE_ERR_CNT,
121*20e69e67SCiprian Regus 	[rx_short_frame_errors]	= ADIN1140_MAC_RX_SHORT_ERR_CNT,
122*20e69e67SCiprian Regus 	[rx_long_frame_errors] = ADIN1140_MAC_RX_LONG_ERR_CNT,
123*20e69e67SCiprian Regus 	[rx_phy_errors] = ADIN1140_MAC_RX_PHY_ERR_CNT,
124*20e69e67SCiprian Regus 	[rx_fifo_full_dropped] = ADIN1140_MAC_RX_DRP_FULL_CNT,
125*20e69e67SCiprian Regus 	[rx_addr_filter_dropped] = ADIN1140_MAC_RX_DRP_FILTER_CNT,
126*20e69e67SCiprian Regus 	[rx_ifg_errors] = ADIN1140_MAC_RX_IFG_ERR_CNT,
127*20e69e67SCiprian Regus 	[tx_frames] = ADIN1140_MAC_TX_FRAME_CNT,
128*20e69e67SCiprian Regus 	[tx_bc_frames] = ADIN1140_MAC_TX_BC_FRAME_CNT,
129*20e69e67SCiprian Regus 	[tx_mc_frames] = ADIN1140_MAC_TX_MC_FRAME_CNT,
130*20e69e67SCiprian Regus 	[tx_single_collision] = ADIN1140_MAC_TX_SINGLE_COL_CNT,
131*20e69e67SCiprian Regus 	[tx_multi_collision] = ADIN1140_MAC_TX_MULTI_COL_CNT,
132*20e69e67SCiprian Regus 	[tx_deferred] = ADIN1140_MAC_TX_DEFERRED_CNT,
133*20e69e67SCiprian Regus 	[tx_late_collision] = ADIN1140_MAC_TX_LATE_COL_CNT,
134*20e69e67SCiprian Regus 	[tx_excess_collision] = ADIN1140_MAC_TX_EXCESS_COL_CNT,
135*20e69e67SCiprian Regus 	[tx_underrun] = ADIN1140_MAC_TX_UNDERRUN_CNT,
136*20e69e67SCiprian Regus };
137*20e69e67SCiprian Regus 
138*20e69e67SCiprian Regus static const struct adin1140_statistics_reg adin1140_stats[] = {
139*20e69e67SCiprian Regus 	{.name = "rx_preamble_errors", .idx = rx_preamble_errors},
140*20e69e67SCiprian Regus 	{.name = "rx_ifg_errors", .idx = rx_ifg_errors},
141*20e69e67SCiprian Regus };
142*20e69e67SCiprian Regus 
adin1140_mac_filter_set(struct adin1140_priv * priv,const u8 * addr,const u8 * mask,u8 slot)143*20e69e67SCiprian Regus static int adin1140_mac_filter_set(struct adin1140_priv *priv,
144*20e69e67SCiprian Regus 				   const u8 *addr, const u8 *mask,
145*20e69e67SCiprian Regus 				   u8 slot)
146*20e69e67SCiprian Regus {
147*20e69e67SCiprian Regus 	u32 reg_address;
148*20e69e67SCiprian Regus 	u32 val;
149*20e69e67SCiprian Regus 	int ret;
150*20e69e67SCiprian Regus 
151*20e69e67SCiprian Regus 	if (slot >= ADIN1140_MAC_FILT_MAX_SLOT)
152*20e69e67SCiprian Regus 		return -ENOSPC;
153*20e69e67SCiprian Regus 
154*20e69e67SCiprian Regus 	reg_address = ADIN1140_MAC_ADDR_FILT_UPR_REG + 2 * slot;
155*20e69e67SCiprian Regus 
156*20e69e67SCiprian Regus 	ret = oa_tc6_write_register_mms(priv->tc6, OA_TC6_MAC_MMS1,
157*20e69e67SCiprian Regus 					reg_address,
158*20e69e67SCiprian Regus 					get_unaligned_be16(&addr[0]) |
159*20e69e67SCiprian Regus 					ADIN1140_MAC_ADDR_FILT_APPLY2PORT1 |
160*20e69e67SCiprian Regus 					ADIN1140_MAC_ADDR_FILT_TO_HOST);
161*20e69e67SCiprian Regus 	if (ret)
162*20e69e67SCiprian Regus 		return ret;
163*20e69e67SCiprian Regus 
164*20e69e67SCiprian Regus 	reg_address = ADIN1140_MAC_ADDR_FILT_LWR_REG + 2 * slot;
165*20e69e67SCiprian Regus 	ret = oa_tc6_write_register_mms(priv->tc6, OA_TC6_MAC_MMS1,
166*20e69e67SCiprian Regus 					reg_address,
167*20e69e67SCiprian Regus 					get_unaligned_be32(&addr[2]));
168*20e69e67SCiprian Regus 	if (ret)
169*20e69e67SCiprian Regus 		return ret;
170*20e69e67SCiprian Regus 
171*20e69e67SCiprian Regus 	/* Only the first 2 destination MAC filter slots support masking.
172*20e69e67SCiprian Regus 	 * For the other entries, the destination address in the received
173*20e69e67SCiprian Regus 	 * frame must match exactly.
174*20e69e67SCiprian Regus 	 */
175*20e69e67SCiprian Regus 	if (slot >= ADIN1140_MAC_FILT_MASK_LIMIT)
176*20e69e67SCiprian Regus 		return 0;
177*20e69e67SCiprian Regus 
178*20e69e67SCiprian Regus 	val = get_unaligned_be16(&mask[0]);
179*20e69e67SCiprian Regus 	reg_address = ADIN1140_MAC_ADDR_MASK_UPR_REG + (2 * slot);
180*20e69e67SCiprian Regus 
181*20e69e67SCiprian Regus 	ret = oa_tc6_write_register_mms(priv->tc6, OA_TC6_MAC_MMS1,
182*20e69e67SCiprian Regus 					reg_address, val);
183*20e69e67SCiprian Regus 	if (ret)
184*20e69e67SCiprian Regus 		return ret;
185*20e69e67SCiprian Regus 
186*20e69e67SCiprian Regus 	val = get_unaligned_be32(&mask[2]);
187*20e69e67SCiprian Regus 	reg_address = ADIN1140_MAC_ADDR_MASK_LWR_REG + (2 * slot);
188*20e69e67SCiprian Regus 
189*20e69e67SCiprian Regus 	return oa_tc6_write_register_mms(priv->tc6, OA_TC6_MAC_MMS1,
190*20e69e67SCiprian Regus 					 reg_address, val);
191*20e69e67SCiprian Regus }
192*20e69e67SCiprian Regus 
adin1140_mac_filter_clear(struct adin1140_priv * priv,u8 slot)193*20e69e67SCiprian Regus static int adin1140_mac_filter_clear(struct adin1140_priv *priv, u8 slot)
194*20e69e67SCiprian Regus {
195*20e69e67SCiprian Regus 	u8 mask[ETH_ALEN];
196*20e69e67SCiprian Regus 	u8 addr[ETH_ALEN];
197*20e69e67SCiprian Regus 
198*20e69e67SCiprian Regus 	memset(mask, 0xFF, ETH_ALEN);
199*20e69e67SCiprian Regus 	memset(addr, 0x0, ETH_ALEN);
200*20e69e67SCiprian Regus 
201*20e69e67SCiprian Regus 	return adin1140_mac_filter_set(priv, addr, mask, slot);
202*20e69e67SCiprian Regus }
203*20e69e67SCiprian Regus 
adin1140_filter_unicast(struct adin1140_priv * priv)204*20e69e67SCiprian Regus static int adin1140_filter_unicast(struct adin1140_priv *priv)
205*20e69e67SCiprian Regus {
206*20e69e67SCiprian Regus 	/* Only the first 2 filter slots support masking, so no unicast
207*20e69e67SCiprian Regus 	 * address will ever need a mask. The first slots are used for the
208*20e69e67SCiprian Regus 	 * all multicast and broadcast filter.
209*20e69e67SCiprian Regus 	 */
210*20e69e67SCiprian Regus 	return adin1140_mac_filter_set(priv, priv->netdev->dev_addr, NULL,
211*20e69e67SCiprian Regus 				       ADIN1140_MAC_FILT_UC_SLOT);
212*20e69e67SCiprian Regus }
213*20e69e67SCiprian Regus 
adin1140_filter_all_multicast(struct adin1140_priv * priv,bool en)214*20e69e67SCiprian Regus static int adin1140_filter_all_multicast(struct adin1140_priv *priv, bool en)
215*20e69e67SCiprian Regus {
216*20e69e67SCiprian Regus 	u8 multicast_addr[ETH_ALEN] = {1, 0, 0, 0, 0, 0};
217*20e69e67SCiprian Regus 
218*20e69e67SCiprian Regus 	if (en)
219*20e69e67SCiprian Regus 		return adin1140_mac_filter_set(priv, multicast_addr,
220*20e69e67SCiprian Regus 					       multicast_addr,
221*20e69e67SCiprian Regus 					       ADIN1140_MAC_FILT_MC_SLOT);
222*20e69e67SCiprian Regus 
223*20e69e67SCiprian Regus 	return adin1140_mac_filter_clear(priv, ADIN1140_MAC_FILT_MC_SLOT);
224*20e69e67SCiprian Regus }
225*20e69e67SCiprian Regus 
adin1140_filter_broadcast(struct adin1140_priv * priv,bool enabled)226*20e69e67SCiprian Regus static int adin1140_filter_broadcast(struct adin1140_priv *priv, bool enabled)
227*20e69e67SCiprian Regus {
228*20e69e67SCiprian Regus 	u8 mask[ETH_ALEN];
229*20e69e67SCiprian Regus 
230*20e69e67SCiprian Regus 	if (enabled) {
231*20e69e67SCiprian Regus 		memset(mask, 0xFF, ETH_ALEN);
232*20e69e67SCiprian Regus 		return adin1140_mac_filter_set(priv, mask, mask,
233*20e69e67SCiprian Regus 					       ADIN1140_MAC_FILT_BC_SLOT);
234*20e69e67SCiprian Regus 	}
235*20e69e67SCiprian Regus 
236*20e69e67SCiprian Regus 	return adin1140_mac_filter_clear(priv, ADIN1140_MAC_FILT_BC_SLOT);
237*20e69e67SCiprian Regus }
238*20e69e67SCiprian Regus 
adin1140_default_filter_config(struct adin1140_priv * priv)239*20e69e67SCiprian Regus static int adin1140_default_filter_config(struct adin1140_priv *priv)
240*20e69e67SCiprian Regus {
241*20e69e67SCiprian Regus 	int ret;
242*20e69e67SCiprian Regus 
243*20e69e67SCiprian Regus 	ret = adin1140_filter_broadcast(priv, true);
244*20e69e67SCiprian Regus 	if (ret)
245*20e69e67SCiprian Regus 		return ret;
246*20e69e67SCiprian Regus 
247*20e69e67SCiprian Regus 	return adin1140_filter_unicast(priv);
248*20e69e67SCiprian Regus }
249*20e69e67SCiprian Regus 
adin1140_promiscuous_mode(struct adin1140_priv * priv,bool enabled)250*20e69e67SCiprian Regus static int adin1140_promiscuous_mode(struct adin1140_priv *priv, bool enabled)
251*20e69e67SCiprian Regus {
252*20e69e67SCiprian Regus 	int ret;
253*20e69e67SCiprian Regus 	u32 val;
254*20e69e67SCiprian Regus 
255*20e69e67SCiprian Regus 	ret = oa_tc6_read_register(priv->tc6, OA_TC6_REG_CONFIG2, &val);
256*20e69e67SCiprian Regus 	if (ret)
257*20e69e67SCiprian Regus 		return ret;
258*20e69e67SCiprian Regus 
259*20e69e67SCiprian Regus 	if (enabled)
260*20e69e67SCiprian Regus 		val |= ADIN1140_MAC_CONFIG2_FWD_UNK2HOST;
261*20e69e67SCiprian Regus 	else
262*20e69e67SCiprian Regus 		val &= ~ADIN1140_MAC_CONFIG2_FWD_UNK2HOST;
263*20e69e67SCiprian Regus 
264*20e69e67SCiprian Regus 	return oa_tc6_write_register(priv->tc6, OA_TC6_REG_CONFIG2, val);
265*20e69e67SCiprian Regus }
266*20e69e67SCiprian Regus 
adin1140_rx_mode(struct net_device * dev,struct netdev_hw_addr_list * uc,struct netdev_hw_addr_list * mc)267*20e69e67SCiprian Regus static int adin1140_rx_mode(struct net_device *dev,
268*20e69e67SCiprian Regus 			    struct netdev_hw_addr_list *uc,
269*20e69e67SCiprian Regus 			    struct netdev_hw_addr_list *mc)
270*20e69e67SCiprian Regus {
271*20e69e67SCiprian Regus 	struct adin1140_priv *priv = netdev_priv(dev);
272*20e69e67SCiprian Regus 	struct netdev_hw_addr *ha;
273*20e69e67SCiprian Regus 	bool all_multi, promisc;
274*20e69e67SCiprian Regus 	u32 mac_addrs;
275*20e69e67SCiprian Regus 	u8 slot, i;
276*20e69e67SCiprian Regus 	int ret;
277*20e69e67SCiprian Regus 
278*20e69e67SCiprian Regus 	/* The ADIN1140 has 16 dest MAC address filter slots:
279*20e69e67SCiprian Regus 	 * 0 - reserved for all multicast filter.
280*20e69e67SCiprian Regus 	 * 1 - reserved for broadcast filter.
281*20e69e67SCiprian Regus 	 * 2 - reserved for the device's own unicast MAC.
282*20e69e67SCiprian Regus 	 * 3 -> 15 - available for other unicast/multicast filters.
283*20e69e67SCiprian Regus 	 */
284*20e69e67SCiprian Regus 
285*20e69e67SCiprian Regus 	mac_addrs = netdev_hw_addr_list_count(uc);
286*20e69e67SCiprian Regus 	all_multi = false;
287*20e69e67SCiprian Regus 	promisc = false;
288*20e69e67SCiprian Regus 
289*20e69e67SCiprian Regus 	if (priv->netdev->flags & IFF_PROMISC)
290*20e69e67SCiprian Regus 		promisc = true;
291*20e69e67SCiprian Regus 	else if (priv->netdev->flags & IFF_ALLMULTI)
292*20e69e67SCiprian Regus 		all_multi = true;
293*20e69e67SCiprian Regus 	else
294*20e69e67SCiprian Regus 		mac_addrs += netdev_hw_addr_list_count(mc);
295*20e69e67SCiprian Regus 
296*20e69e67SCiprian Regus 	if (mac_addrs > ADIN1140_MAC_FILT_AVAIL) {
297*20e69e67SCiprian Regus 		/* The filter table is full. Enable promisc mode. */
298*20e69e67SCiprian Regus 		promisc = true;
299*20e69e67SCiprian Regus 	}
300*20e69e67SCiprian Regus 
301*20e69e67SCiprian Regus 	ret = adin1140_promiscuous_mode(priv, promisc);
302*20e69e67SCiprian Regus 	if (ret)
303*20e69e67SCiprian Regus 		return ret;
304*20e69e67SCiprian Regus 
305*20e69e67SCiprian Regus 	ret = adin1140_filter_all_multicast(priv, all_multi);
306*20e69e67SCiprian Regus 	if (ret)
307*20e69e67SCiprian Regus 		return ret;
308*20e69e67SCiprian Regus 
309*20e69e67SCiprian Regus 	slot = ADIN1140_MAC_FILT_UC_SLOT + 1;
310*20e69e67SCiprian Regus 	if (!promisc) {
311*20e69e67SCiprian Regus 		netdev_hw_addr_list_for_each(ha, uc) {
312*20e69e67SCiprian Regus 			ret = adin1140_mac_filter_set(priv, ha->addr, NULL,
313*20e69e67SCiprian Regus 						      slot);
314*20e69e67SCiprian Regus 			if (ret)
315*20e69e67SCiprian Regus 				return ret;
316*20e69e67SCiprian Regus 
317*20e69e67SCiprian Regus 			slot++;
318*20e69e67SCiprian Regus 		}
319*20e69e67SCiprian Regus 
320*20e69e67SCiprian Regus 		if (!all_multi) {
321*20e69e67SCiprian Regus 			netdev_hw_addr_list_for_each(ha, mc) {
322*20e69e67SCiprian Regus 				ret = adin1140_mac_filter_set(priv, ha->addr,
323*20e69e67SCiprian Regus 							      NULL, slot);
324*20e69e67SCiprian Regus 				if (ret)
325*20e69e67SCiprian Regus 					return ret;
326*20e69e67SCiprian Regus 
327*20e69e67SCiprian Regus 				slot++;
328*20e69e67SCiprian Regus 			}
329*20e69e67SCiprian Regus 		}
330*20e69e67SCiprian Regus 	}
331*20e69e67SCiprian Regus 
332*20e69e67SCiprian Regus 	for (i = slot; i < ADIN1140_MAC_FILT_MAX_SLOT; i++) {
333*20e69e67SCiprian Regus 		ret = adin1140_mac_filter_clear(priv, i);
334*20e69e67SCiprian Regus 		if (ret)
335*20e69e67SCiprian Regus 			return ret;
336*20e69e67SCiprian Regus 	}
337*20e69e67SCiprian Regus 
338*20e69e67SCiprian Regus 	return 0;
339*20e69e67SCiprian Regus }
340*20e69e67SCiprian Regus 
adin1140_stats_work(struct work_struct * work)341*20e69e67SCiprian Regus static void adin1140_stats_work(struct work_struct *work)
342*20e69e67SCiprian Regus {
343*20e69e67SCiprian Regus 	struct delayed_work *dwork = to_delayed_work(work);
344*20e69e67SCiprian Regus 	struct adin1140_priv *priv;
345*20e69e67SCiprian Regus 	u32 reg_val;
346*20e69e67SCiprian Regus 	int ret;
347*20e69e67SCiprian Regus 	u32 i;
348*20e69e67SCiprian Regus 
349*20e69e67SCiprian Regus 	priv = container_of(dwork, struct adin1140_priv, stats_work);
350*20e69e67SCiprian Regus 
351*20e69e67SCiprian Regus 	for (i = 0; i < ARRAY_SIZE(adin1140_stat_regs); i++) {
352*20e69e67SCiprian Regus 		ret = oa_tc6_read_register_mms(priv->tc6, OA_TC6_MAC_MMS1,
353*20e69e67SCiprian Regus 					       adin1140_stat_regs[i],
354*20e69e67SCiprian Regus 					       &reg_val);
355*20e69e67SCiprian Regus 		if (ret)
356*20e69e67SCiprian Regus 			goto out;
357*20e69e67SCiprian Regus 
358*20e69e67SCiprian Regus 		scoped_guard(spinlock, &priv->stat_lock)
359*20e69e67SCiprian Regus 			priv->stats[i] += reg_val;
360*20e69e67SCiprian Regus 	}
361*20e69e67SCiprian Regus 
362*20e69e67SCiprian Regus out:
363*20e69e67SCiprian Regus 	schedule_delayed_work(dwork, ADIN1140_STATS_CHECK_DELAY);
364*20e69e67SCiprian Regus }
365*20e69e67SCiprian Regus 
adin1140_configure(struct adin1140_priv * priv)366*20e69e67SCiprian Regus static int adin1140_configure(struct adin1140_priv *priv)
367*20e69e67SCiprian Regus {
368*20e69e67SCiprian Regus 	u32 reg_val;
369*20e69e67SCiprian Regus 	int ret;
370*20e69e67SCiprian Regus 
371*20e69e67SCiprian Regus 	ret = oa_tc6_zero_align_receive_frame_enable(priv->tc6);
372*20e69e67SCiprian Regus 	if (ret)
373*20e69e67SCiprian Regus 		return ret;
374*20e69e67SCiprian Regus 
375*20e69e67SCiprian Regus 	/* Disable MAC loopback */
376*20e69e67SCiprian Regus 	ret = oa_tc6_write_register_mms(priv->tc6, OA_TC6_MAC_MMS1,
377*20e69e67SCiprian Regus 					ADIN1140_MAC_P1_LOOP_ADDR_REG, 0x0);
378*20e69e67SCiprian Regus 	if (ret)
379*20e69e67SCiprian Regus 		return ret;
380*20e69e67SCiprian Regus 
381*20e69e67SCiprian Regus 	ret = oa_tc6_read_register(priv->tc6, OA_TC6_REG_CONFIG2, &reg_val);
382*20e69e67SCiprian Regus 	if (ret)
383*20e69e67SCiprian Regus 		return ret;
384*20e69e67SCiprian Regus 
385*20e69e67SCiprian Regus 	reg_val |= ADIN1140_MAC_CONFIG2_STAT_CLR_RD;
386*20e69e67SCiprian Regus 
387*20e69e67SCiprian Regus 	ret = oa_tc6_write_register(priv->tc6, OA_TC6_REG_CONFIG2, reg_val);
388*20e69e67SCiprian Regus 	if (ret)
389*20e69e67SCiprian Regus 		return ret;
390*20e69e67SCiprian Regus 
391*20e69e67SCiprian Regus 	return adin1140_default_filter_config(priv);
392*20e69e67SCiprian Regus }
393*20e69e67SCiprian Regus 
adin1140_open(struct net_device * netdev)394*20e69e67SCiprian Regus static int adin1140_open(struct net_device *netdev)
395*20e69e67SCiprian Regus {
396*20e69e67SCiprian Regus 	struct adin1140_priv *priv = netdev_priv(netdev);
397*20e69e67SCiprian Regus 
398*20e69e67SCiprian Regus 	schedule_delayed_work(&priv->stats_work, ADIN1140_STATS_CHECK_DELAY);
399*20e69e67SCiprian Regus 
400*20e69e67SCiprian Regus 	phy_start(netdev->phydev);
401*20e69e67SCiprian Regus 	netif_start_queue(netdev);
402*20e69e67SCiprian Regus 
403*20e69e67SCiprian Regus 	return 0;
404*20e69e67SCiprian Regus }
405*20e69e67SCiprian Regus 
adin1140_close(struct net_device * netdev)406*20e69e67SCiprian Regus static int adin1140_close(struct net_device *netdev)
407*20e69e67SCiprian Regus {
408*20e69e67SCiprian Regus 	struct adin1140_priv *priv = netdev_priv(netdev);
409*20e69e67SCiprian Regus 
410*20e69e67SCiprian Regus 	cancel_delayed_work_sync(&priv->stats_work);
411*20e69e67SCiprian Regus 
412*20e69e67SCiprian Regus 	netif_stop_queue(netdev);
413*20e69e67SCiprian Regus 	phy_stop(netdev->phydev);
414*20e69e67SCiprian Regus 
415*20e69e67SCiprian Regus 	return 0;
416*20e69e67SCiprian Regus }
417*20e69e67SCiprian Regus 
adin1140_start_xmit(struct sk_buff * skb,struct net_device * netdev)418*20e69e67SCiprian Regus static netdev_tx_t adin1140_start_xmit(struct sk_buff *skb,
419*20e69e67SCiprian Regus 				       struct net_device *netdev)
420*20e69e67SCiprian Regus {
421*20e69e67SCiprian Regus 	struct adin1140_priv *priv = netdev_priv(netdev);
422*20e69e67SCiprian Regus 
423*20e69e67SCiprian Regus 	/* The MAC doesn't automatically pad the frame to a 60 byte minimum
424*20e69e67SCiprian Regus 	 * size in case the host sends a shorter skb, so we have to do it in
425*20e69e67SCiprian Regus 	 * the driver. The FCS will be added by the MAC.
426*20e69e67SCiprian Regus 	 */
427*20e69e67SCiprian Regus 	if (skb_put_padto(skb, ETH_ZLEN))
428*20e69e67SCiprian Regus 		return NETDEV_TX_OK;
429*20e69e67SCiprian Regus 
430*20e69e67SCiprian Regus 	return oa_tc6_start_xmit(priv->tc6, skb);
431*20e69e67SCiprian Regus }
432*20e69e67SCiprian Regus 
adin1140_set_mac_address(struct net_device * netdev,void * addr)433*20e69e67SCiprian Regus static int adin1140_set_mac_address(struct net_device *netdev, void *addr)
434*20e69e67SCiprian Regus {
435*20e69e67SCiprian Regus 	struct adin1140_priv *priv = netdev_priv(netdev);
436*20e69e67SCiprian Regus 	struct sockaddr *address = addr;
437*20e69e67SCiprian Regus 	u8 mask[ETH_ALEN];
438*20e69e67SCiprian Regus 	int ret;
439*20e69e67SCiprian Regus 
440*20e69e67SCiprian Regus 	ret = eth_prepare_mac_addr_change(netdev, addr);
441*20e69e67SCiprian Regus 	if (ret < 0)
442*20e69e67SCiprian Regus 		return ret;
443*20e69e67SCiprian Regus 
444*20e69e67SCiprian Regus 	if (ether_addr_equal(address->sa_data, netdev->dev_addr))
445*20e69e67SCiprian Regus 		return 0;
446*20e69e67SCiprian Regus 
447*20e69e67SCiprian Regus 	memset(mask, 0xFF, ETH_ALEN);
448*20e69e67SCiprian Regus 	ret = adin1140_mac_filter_set(priv, address->sa_data, mask,
449*20e69e67SCiprian Regus 				      ADIN1140_MAC_FILT_UC_SLOT);
450*20e69e67SCiprian Regus 	if (ret)
451*20e69e67SCiprian Regus 		return ret;
452*20e69e67SCiprian Regus 
453*20e69e67SCiprian Regus 	eth_commit_mac_addr_change(netdev, addr);
454*20e69e67SCiprian Regus 
455*20e69e67SCiprian Regus 	return 0;
456*20e69e67SCiprian Regus }
457*20e69e67SCiprian Regus 
__adin1140_ndo_get_stats64(struct adin1140_priv * priv,struct rtnl_link_stats64 * storage)458*20e69e67SCiprian Regus static void __adin1140_ndo_get_stats64(struct adin1140_priv *priv,
459*20e69e67SCiprian Regus 				       struct rtnl_link_stats64 *storage)
460*20e69e67SCiprian Regus {
461*20e69e67SCiprian Regus 	storage->rx_errors = priv->stats[rx_crc_errors] +
462*20e69e67SCiprian Regus 			     priv->stats[rx_align_errors] +
463*20e69e67SCiprian Regus 			     priv->stats[rx_preamble_errors] +
464*20e69e67SCiprian Regus 			     priv->stats[rx_short_frame_errors] +
465*20e69e67SCiprian Regus 			     priv->stats[rx_long_frame_errors] +
466*20e69e67SCiprian Regus 			     priv->stats[rx_phy_errors] +
467*20e69e67SCiprian Regus 			     priv->stats[rx_ifg_errors];
468*20e69e67SCiprian Regus 
469*20e69e67SCiprian Regus 	storage->tx_errors = priv->stats[tx_excess_collision] +
470*20e69e67SCiprian Regus 			     priv->stats[tx_underrun];
471*20e69e67SCiprian Regus 
472*20e69e67SCiprian Regus 	storage->rx_dropped = priv->stats[rx_fifo_full_dropped] +
473*20e69e67SCiprian Regus 			      priv->stats[rx_addr_filter_dropped];
474*20e69e67SCiprian Regus 
475*20e69e67SCiprian Regus 	storage->multicast = priv->stats[rx_mc_frames];
476*20e69e67SCiprian Regus 
477*20e69e67SCiprian Regus 	storage->collisions = priv->stats[tx_single_collision] +
478*20e69e67SCiprian Regus 			      priv->stats[tx_multi_collision];
479*20e69e67SCiprian Regus 
480*20e69e67SCiprian Regus 	storage->rx_length_errors = priv->stats[rx_short_frame_errors] +
481*20e69e67SCiprian Regus 				    priv->stats[rx_long_frame_errors];
482*20e69e67SCiprian Regus 	storage->rx_over_errors = priv->stats[rx_fifo_full_dropped];
483*20e69e67SCiprian Regus 	storage->rx_crc_errors = priv->stats[rx_crc_errors];
484*20e69e67SCiprian Regus 	storage->rx_frame_errors = priv->stats[rx_align_errors];
485*20e69e67SCiprian Regus 	storage->rx_missed_errors = priv->stats[rx_fifo_full_dropped];
486*20e69e67SCiprian Regus 
487*20e69e67SCiprian Regus 	storage->tx_aborted_errors = priv->stats[tx_excess_collision];
488*20e69e67SCiprian Regus 	storage->tx_fifo_errors = priv->stats[tx_underrun];
489*20e69e67SCiprian Regus 	storage->tx_window_errors = priv->stats[tx_late_collision];
490*20e69e67SCiprian Regus }
491*20e69e67SCiprian Regus 
adin1140_ndo_get_stats64(struct net_device * dev,struct rtnl_link_stats64 * storage)492*20e69e67SCiprian Regus static void adin1140_ndo_get_stats64(struct net_device *dev,
493*20e69e67SCiprian Regus 				     struct rtnl_link_stats64 *storage)
494*20e69e67SCiprian Regus {
495*20e69e67SCiprian Regus 	struct adin1140_priv *priv = netdev_priv(dev);
496*20e69e67SCiprian Regus 
497*20e69e67SCiprian Regus 	storage->rx_packets = priv->netdev->stats.rx_packets;
498*20e69e67SCiprian Regus 	storage->tx_packets = priv->netdev->stats.tx_packets;
499*20e69e67SCiprian Regus 
500*20e69e67SCiprian Regus 	storage->rx_bytes = priv->netdev->stats.rx_bytes;
501*20e69e67SCiprian Regus 	storage->tx_bytes = priv->netdev->stats.tx_bytes;
502*20e69e67SCiprian Regus 
503*20e69e67SCiprian Regus 	scoped_guard(spinlock, &priv->stat_lock)
504*20e69e67SCiprian Regus 		__adin1140_ndo_get_stats64(priv, storage);
505*20e69e67SCiprian Regus }
506*20e69e67SCiprian Regus 
adin1140_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * info)507*20e69e67SCiprian Regus static void adin1140_get_drvinfo(struct net_device *netdev,
508*20e69e67SCiprian Regus 				 struct ethtool_drvinfo *info)
509*20e69e67SCiprian Regus {
510*20e69e67SCiprian Regus 	strscpy(info->driver, "ADIN1140", sizeof(info->driver));
511*20e69e67SCiprian Regus 	strscpy(info->bus_info, dev_name(netdev->dev.parent),
512*20e69e67SCiprian Regus 		sizeof(info->bus_info));
513*20e69e67SCiprian Regus }
514*20e69e67SCiprian Regus 
adin1140_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)515*20e69e67SCiprian Regus static void adin1140_get_ethtool_stats(struct net_device *netdev,
516*20e69e67SCiprian Regus 				       struct ethtool_stats *stats, u64 *data)
517*20e69e67SCiprian Regus {
518*20e69e67SCiprian Regus 	struct adin1140_priv *priv = netdev_priv(netdev);
519*20e69e67SCiprian Regus 	u32 i;
520*20e69e67SCiprian Regus 
521*20e69e67SCiprian Regus 	scoped_guard(spinlock, &priv->stat_lock) {
522*20e69e67SCiprian Regus 		for (i = 0; i < ARRAY_SIZE(adin1140_stats); i++)
523*20e69e67SCiprian Regus 			data[i] = priv->stats[adin1140_stats[i].idx];
524*20e69e67SCiprian Regus 	}
525*20e69e67SCiprian Regus }
526*20e69e67SCiprian Regus 
adin1140_get_ethtool_strings(struct net_device * netdev,u32 sset,u8 * p)527*20e69e67SCiprian Regus static void adin1140_get_ethtool_strings(struct net_device *netdev, u32 sset,
528*20e69e67SCiprian Regus 					 u8 *p)
529*20e69e67SCiprian Regus {
530*20e69e67SCiprian Regus 	u32 i;
531*20e69e67SCiprian Regus 
532*20e69e67SCiprian Regus 	switch (sset) {
533*20e69e67SCiprian Regus 	case ETH_SS_STATS:
534*20e69e67SCiprian Regus 		for (i = 0; i < ARRAY_SIZE(adin1140_stats); i++)
535*20e69e67SCiprian Regus 			ethtool_puts(&p, adin1140_stats[i].name);
536*20e69e67SCiprian Regus 
537*20e69e67SCiprian Regus 		break;
538*20e69e67SCiprian Regus 	}
539*20e69e67SCiprian Regus }
540*20e69e67SCiprian Regus 
adin1140_get_sset_count(struct net_device * netdev,int sset)541*20e69e67SCiprian Regus static int adin1140_get_sset_count(struct net_device *netdev, int sset)
542*20e69e67SCiprian Regus {
543*20e69e67SCiprian Regus 	switch (sset) {
544*20e69e67SCiprian Regus 	case ETH_SS_STATS:
545*20e69e67SCiprian Regus 		return ARRAY_SIZE(adin1140_stats);
546*20e69e67SCiprian Regus 	default:
547*20e69e67SCiprian Regus 		return -EOPNOTSUPP;
548*20e69e67SCiprian Regus 	}
549*20e69e67SCiprian Regus }
550*20e69e67SCiprian Regus 
__adin1140_eth_mac_stats(struct adin1140_priv * priv,struct ethtool_eth_mac_stats * mac_stats)551*20e69e67SCiprian Regus static void __adin1140_eth_mac_stats(struct adin1140_priv *priv,
552*20e69e67SCiprian Regus 				     struct ethtool_eth_mac_stats *mac_stats)
553*20e69e67SCiprian Regus {
554*20e69e67SCiprian Regus 	mac_stats->FramesReceivedOK = priv->stats[rx_frames];
555*20e69e67SCiprian Regus 	mac_stats->BroadcastFramesReceivedOK = priv->stats[rx_bc_frames];
556*20e69e67SCiprian Regus 	mac_stats->MulticastFramesReceivedOK = priv->stats[rx_mc_frames];
557*20e69e67SCiprian Regus 	mac_stats->FrameCheckSequenceErrors = priv->stats[rx_crc_errors];
558*20e69e67SCiprian Regus 	mac_stats->AlignmentErrors = priv->stats[rx_align_errors];
559*20e69e67SCiprian Regus 	mac_stats->FrameTooLongErrors = priv->stats[rx_long_frame_errors];
560*20e69e67SCiprian Regus 	mac_stats->FramesLostDueToIntMACRcvError =
561*20e69e67SCiprian Regus 					priv->stats[rx_fifo_full_dropped];
562*20e69e67SCiprian Regus 	mac_stats->FramesTransmittedOK = priv->stats[tx_frames];
563*20e69e67SCiprian Regus 	mac_stats->BroadcastFramesXmittedOK = priv->stats[tx_bc_frames];
564*20e69e67SCiprian Regus 	mac_stats->MulticastFramesXmittedOK = priv->stats[tx_mc_frames];
565*20e69e67SCiprian Regus 	mac_stats->SingleCollisionFrames = priv->stats[tx_single_collision];
566*20e69e67SCiprian Regus 	mac_stats->MultipleCollisionFrames = priv->stats[tx_multi_collision];
567*20e69e67SCiprian Regus 	mac_stats->FramesWithDeferredXmissions = priv->stats[tx_deferred];
568*20e69e67SCiprian Regus 	mac_stats->LateCollisions = priv->stats[tx_late_collision];
569*20e69e67SCiprian Regus 	mac_stats->FramesAbortedDueToXSColls =
570*20e69e67SCiprian Regus 					priv->stats[tx_excess_collision];
571*20e69e67SCiprian Regus 	mac_stats->FramesLostDueToIntMACXmitError = priv->stats[tx_underrun];
572*20e69e67SCiprian Regus }
573*20e69e67SCiprian Regus 
adin1140_get_eth_mac_stats(struct net_device * netdev,struct ethtool_eth_mac_stats * mac_stats)574*20e69e67SCiprian Regus static void adin1140_get_eth_mac_stats(struct net_device *netdev,
575*20e69e67SCiprian Regus 				       struct ethtool_eth_mac_stats *mac_stats)
576*20e69e67SCiprian Regus {
577*20e69e67SCiprian Regus 	struct adin1140_priv *priv = netdev_priv(netdev);
578*20e69e67SCiprian Regus 
579*20e69e67SCiprian Regus 	scoped_guard(spinlock, &priv->stat_lock)
580*20e69e67SCiprian Regus 		__adin1140_eth_mac_stats(priv, mac_stats);
581*20e69e67SCiprian Regus }
582*20e69e67SCiprian Regus 
adin1140_mdiobus_read(struct mii_bus * bus,int addr,int regnum)583*20e69e67SCiprian Regus static int adin1140_mdiobus_read(struct mii_bus *bus, int addr, int regnum)
584*20e69e67SCiprian Regus {
585*20e69e67SCiprian Regus 	/* The ADIN1140's standard PHY C22 register map (OA TC6 0xFF00 -
586*20e69e67SCiprian Regus 	 * 0xFF1F), of which only 0xFF00 - 0xFF03 are implemented) cannot be
587*20e69e67SCiprian Regus 	 * accessed while frames are being received by the PHY. In case this
588*20e69e67SCiprian Regus 	 * happens the CONFIG0 and CONFIG2 register values will get corrupted,
589*20e69e67SCiprian Regus 	 * getting a random value. Both reads and writes cause the same
590*20e69e67SCiprian Regus 	 * behavior. This is a workaround that avoids MDIO accesses all
591*20e69e67SCiprian Regus 	 * together. Since this is a 10BASE-T1S PHY, only the loopback and
592*20e69e67SCiprian Regus 	 * reset (AN) bits in the control register (0x0) can be written.
593*20e69e67SCiprian Regus 	 * These functionalities have custom implementations in the PHY
594*20e69e67SCiprian Regus 	 * driver. C45 accesses do not cause this issue.
595*20e69e67SCiprian Regus 	 */
596*20e69e67SCiprian Regus 
597*20e69e67SCiprian Regus 	switch (regnum) {
598*20e69e67SCiprian Regus 	case MII_BMCR:
599*20e69e67SCiprian Regus 		return ADIN1140_PHY_CTRL_DEFAULT;
600*20e69e67SCiprian Regus 	case MII_BMSR:
601*20e69e67SCiprian Regus 		return ADIN1140_PHY_STATUS_DEFAULT;
602*20e69e67SCiprian Regus 	case MII_PHYSID1:
603*20e69e67SCiprian Regus 		return ADIN1140_PHY_ID1;
604*20e69e67SCiprian Regus 	case MII_PHYSID2:
605*20e69e67SCiprian Regus 		return ADIN1140_PHY_ID2;
606*20e69e67SCiprian Regus 	default:
607*20e69e67SCiprian Regus 		return 0xFFFF;
608*20e69e67SCiprian Regus 	}
609*20e69e67SCiprian Regus }
610*20e69e67SCiprian Regus 
adin1140_mdiobus_write(struct mii_bus * bus,int addr,int regnum,u16 val)611*20e69e67SCiprian Regus static int adin1140_mdiobus_write(struct mii_bus *bus, int addr, int regnum,
612*20e69e67SCiprian Regus 				  u16 val)
613*20e69e67SCiprian Regus {
614*20e69e67SCiprian Regus 	return -EIO;
615*20e69e67SCiprian Regus }
616*20e69e67SCiprian Regus 
adin1140_mdio_register(struct adin1140_priv * priv,struct spi_device * spidev)617*20e69e67SCiprian Regus static int adin1140_mdio_register(struct adin1140_priv *priv,
618*20e69e67SCiprian Regus 				  struct spi_device *spidev)
619*20e69e67SCiprian Regus {
620*20e69e67SCiprian Regus 	priv->mdiobus = devm_mdiobus_alloc(&spidev->dev);
621*20e69e67SCiprian Regus 	if (!priv->mdiobus)
622*20e69e67SCiprian Regus 		return dev_err_probe(&spidev->dev, -ENOMEM,
623*20e69e67SCiprian Regus 				     "MDIO bus alloc failed\n");
624*20e69e67SCiprian Regus 
625*20e69e67SCiprian Regus 	priv->mdiobus->name = "adin1140-mdiobus";
626*20e69e67SCiprian Regus 	priv->mdiobus->priv = priv->tc6;
627*20e69e67SCiprian Regus 	priv->mdiobus->parent = &spidev->dev;
628*20e69e67SCiprian Regus 	priv->mdiobus->phy_mask = GENMASK(31, 1);
629*20e69e67SCiprian Regus 	priv->mdiobus->read = adin1140_mdiobus_read;
630*20e69e67SCiprian Regus 	priv->mdiobus->write = adin1140_mdiobus_write;
631*20e69e67SCiprian Regus 	priv->mdiobus->read_c45 = oa_tc6_mdiobus_read_c45;
632*20e69e67SCiprian Regus 	priv->mdiobus->write_c45 = oa_tc6_mdiobus_write_c45;
633*20e69e67SCiprian Regus 
634*20e69e67SCiprian Regus 	snprintf(priv->mdiobus->id, MII_BUS_ID_SIZE, "adin1140-%s.%u",
635*20e69e67SCiprian Regus 		 dev_name(&spidev->dev), spi_get_chipselect(spidev, 0));
636*20e69e67SCiprian Regus 
637*20e69e67SCiprian Regus 	return devm_mdiobus_register(&spidev->dev, priv->mdiobus);
638*20e69e67SCiprian Regus }
639*20e69e67SCiprian Regus 
adin1140_handle_link_change(struct net_device * netdev)640*20e69e67SCiprian Regus static void adin1140_handle_link_change(struct net_device *netdev)
641*20e69e67SCiprian Regus {
642*20e69e67SCiprian Regus 	phy_print_status(netdev->phydev);
643*20e69e67SCiprian Regus }
644*20e69e67SCiprian Regus 
adin1140_phy_remove(void * data)645*20e69e67SCiprian Regus static void adin1140_phy_remove(void *data)
646*20e69e67SCiprian Regus {
647*20e69e67SCiprian Regus 	phy_disconnect(data);
648*20e69e67SCiprian Regus }
649*20e69e67SCiprian Regus 
adin1140_phy_init(struct adin1140_priv * priv,struct spi_device * spidev)650*20e69e67SCiprian Regus static int adin1140_phy_init(struct adin1140_priv *priv,
651*20e69e67SCiprian Regus 			     struct spi_device *spidev)
652*20e69e67SCiprian Regus {
653*20e69e67SCiprian Regus 	int ret;
654*20e69e67SCiprian Regus 
655*20e69e67SCiprian Regus 	ret = adin1140_mdio_register(priv, spidev);
656*20e69e67SCiprian Regus 	if (ret)
657*20e69e67SCiprian Regus 		return ret;
658*20e69e67SCiprian Regus 
659*20e69e67SCiprian Regus 	priv->phydev = phy_find_first(priv->mdiobus);
660*20e69e67SCiprian Regus 	if (!priv->phydev)
661*20e69e67SCiprian Regus 		return dev_err_probe(&spidev->dev, -ENODEV, "No PHY found\n");
662*20e69e67SCiprian Regus 
663*20e69e67SCiprian Regus 	priv->phydev->is_internal = true;
664*20e69e67SCiprian Regus 	ret = phy_connect_direct(priv->netdev, priv->phydev,
665*20e69e67SCiprian Regus 				 &adin1140_handle_link_change,
666*20e69e67SCiprian Regus 				 PHY_INTERFACE_MODE_INTERNAL);
667*20e69e67SCiprian Regus 	if (ret)
668*20e69e67SCiprian Regus 		return dev_err_probe(&spidev->dev, ret,
669*20e69e67SCiprian Regus 				     "Can't attach PHY to %s\n",
670*20e69e67SCiprian Regus 				     priv->mdiobus->id);
671*20e69e67SCiprian Regus 
672*20e69e67SCiprian Regus 	ret = devm_add_action_or_reset(&spidev->dev, adin1140_phy_remove,
673*20e69e67SCiprian Regus 				       priv->phydev);
674*20e69e67SCiprian Regus 	if (ret)
675*20e69e67SCiprian Regus 		return ret;
676*20e69e67SCiprian Regus 
677*20e69e67SCiprian Regus 	phy_attached_info(priv->phydev);
678*20e69e67SCiprian Regus 
679*20e69e67SCiprian Regus 	return 0;
680*20e69e67SCiprian Regus }
681*20e69e67SCiprian Regus 
682*20e69e67SCiprian Regus static const struct ethtool_ops adin1140_ethtool_ops = {
683*20e69e67SCiprian Regus 	.get_drvinfo = adin1140_get_drvinfo,
684*20e69e67SCiprian Regus 	.get_link = ethtool_op_get_link,
685*20e69e67SCiprian Regus 	.get_ethtool_stats = adin1140_get_ethtool_stats,
686*20e69e67SCiprian Regus 	.get_sset_count = adin1140_get_sset_count,
687*20e69e67SCiprian Regus 	.get_strings = adin1140_get_ethtool_strings,
688*20e69e67SCiprian Regus 	.get_link_ksettings = phy_ethtool_get_link_ksettings,
689*20e69e67SCiprian Regus 	.set_link_ksettings = phy_ethtool_set_link_ksettings,
690*20e69e67SCiprian Regus 	.get_eth_mac_stats = adin1140_get_eth_mac_stats,
691*20e69e67SCiprian Regus };
692*20e69e67SCiprian Regus 
693*20e69e67SCiprian Regus static const struct net_device_ops adin1140_netdev_ops = {
694*20e69e67SCiprian Regus 	.ndo_open = adin1140_open,
695*20e69e67SCiprian Regus 	.ndo_stop = adin1140_close,
696*20e69e67SCiprian Regus 	.ndo_start_xmit	= adin1140_start_xmit,
697*20e69e67SCiprian Regus 	.ndo_set_mac_address = adin1140_set_mac_address,
698*20e69e67SCiprian Regus 	.ndo_validate_addr = eth_validate_addr,
699*20e69e67SCiprian Regus 	.ndo_set_rx_mode_async = adin1140_rx_mode,
700*20e69e67SCiprian Regus 	.ndo_eth_ioctl = phy_do_ioctl_running,
701*20e69e67SCiprian Regus 	.ndo_get_stats64 = adin1140_ndo_get_stats64,
702*20e69e67SCiprian Regus };
703*20e69e67SCiprian Regus 
adin1140_oa_tc6_remove(void * data)704*20e69e67SCiprian Regus static void adin1140_oa_tc6_remove(void *data)
705*20e69e67SCiprian Regus {
706*20e69e67SCiprian Regus 	oa_tc6_exit(data);
707*20e69e67SCiprian Regus }
708*20e69e67SCiprian Regus 
adin1140_probe(struct spi_device * spi)709*20e69e67SCiprian Regus static int adin1140_probe(struct spi_device *spi)
710*20e69e67SCiprian Regus {
711*20e69e67SCiprian Regus 	struct oa_tc6_quirks tc6_quirks = {};
712*20e69e67SCiprian Regus 	struct net_device *netdev;
713*20e69e67SCiprian Regus 	struct adin1140_priv *priv;
714*20e69e67SCiprian Regus 	int ret;
715*20e69e67SCiprian Regus 
716*20e69e67SCiprian Regus 	netdev = devm_alloc_etherdev(&spi->dev, sizeof(struct adin1140_priv));
717*20e69e67SCiprian Regus 	if (!netdev)
718*20e69e67SCiprian Regus 		return -ENOMEM;
719*20e69e67SCiprian Regus 
720*20e69e67SCiprian Regus 	priv = netdev_priv(netdev);
721*20e69e67SCiprian Regus 	priv->netdev = netdev;
722*20e69e67SCiprian Regus 	spi_set_drvdata(spi, priv);
723*20e69e67SCiprian Regus 	spin_lock_init(&priv->stat_lock);
724*20e69e67SCiprian Regus 
725*20e69e67SCiprian Regus 	tc6_quirks.quirk_flags = OA_TC6_BROKEN_PHY;
726*20e69e67SCiprian Regus 
727*20e69e67SCiprian Regus 	priv->tc6 = oa_tc6_init(spi, netdev, &tc6_quirks);
728*20e69e67SCiprian Regus 	if (!priv->tc6)
729*20e69e67SCiprian Regus 		return -ENODEV;
730*20e69e67SCiprian Regus 
731*20e69e67SCiprian Regus 	ret = devm_add_action_or_reset(&spi->dev, adin1140_oa_tc6_remove,
732*20e69e67SCiprian Regus 				       priv->tc6);
733*20e69e67SCiprian Regus 	if (ret)
734*20e69e67SCiprian Regus 		return ret;
735*20e69e67SCiprian Regus 
736*20e69e67SCiprian Regus 	ret = adin1140_phy_init(priv, spi);
737*20e69e67SCiprian Regus 	if (ret)
738*20e69e67SCiprian Regus 		return ret;
739*20e69e67SCiprian Regus 
740*20e69e67SCiprian Regus 	if (device_get_ethdev_address(&spi->dev, netdev))
741*20e69e67SCiprian Regus 		eth_hw_addr_random(netdev);
742*20e69e67SCiprian Regus 
743*20e69e67SCiprian Regus 	ret = adin1140_configure(priv);
744*20e69e67SCiprian Regus 	if (ret)
745*20e69e67SCiprian Regus 		return ret;
746*20e69e67SCiprian Regus 
747*20e69e67SCiprian Regus 	INIT_DELAYED_WORK(&priv->stats_work, adin1140_stats_work);
748*20e69e67SCiprian Regus 
749*20e69e67SCiprian Regus 	netdev->if_port = IF_PORT_10BASET;
750*20e69e67SCiprian Regus 	netdev->irq = spi->irq;
751*20e69e67SCiprian Regus 	netdev->netdev_ops = &adin1140_netdev_ops;
752*20e69e67SCiprian Regus 	netdev->ethtool_ops = &adin1140_ethtool_ops;
753*20e69e67SCiprian Regus 	netdev->netns_immutable = true;
754*20e69e67SCiprian Regus 	netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE |
755*20e69e67SCiprian Regus 			      IFF_UNICAST_FLT;
756*20e69e67SCiprian Regus 
757*20e69e67SCiprian Regus 	ret = devm_register_netdev(&spi->dev, netdev);
758*20e69e67SCiprian Regus 	if (ret)
759*20e69e67SCiprian Regus 		return dev_err_probe(&spi->dev, ret,
760*20e69e67SCiprian Regus 				     "Failed to register netdev");
761*20e69e67SCiprian Regus 
762*20e69e67SCiprian Regus 	return 0;
763*20e69e67SCiprian Regus }
764*20e69e67SCiprian Regus 
765*20e69e67SCiprian Regus static const struct spi_device_id adin1140_spi_id[] = {
766*20e69e67SCiprian Regus 	{ .name = "ad3306" },
767*20e69e67SCiprian Regus 	{ .name = "adin1140" },
768*20e69e67SCiprian Regus 	{},
769*20e69e67SCiprian Regus };
770*20e69e67SCiprian Regus MODULE_DEVICE_TABLE(spi, adin1140_spi_id);
771*20e69e67SCiprian Regus 
772*20e69e67SCiprian Regus static const struct of_device_id adin1140_match_table[] = {
773*20e69e67SCiprian Regus 	{ .compatible = "adi,ad3306" },
774*20e69e67SCiprian Regus 	{ .compatible = "adi,adin1140" },
775*20e69e67SCiprian Regus 	{ }
776*20e69e67SCiprian Regus };
777*20e69e67SCiprian Regus MODULE_DEVICE_TABLE(of, adin1140_match_table);
778*20e69e67SCiprian Regus 
779*20e69e67SCiprian Regus static struct spi_driver adin1140_driver = {
780*20e69e67SCiprian Regus 	.driver = {
781*20e69e67SCiprian Regus 		.name = "adin1140",
782*20e69e67SCiprian Regus 		.of_match_table = adin1140_match_table,
783*20e69e67SCiprian Regus 	 },
784*20e69e67SCiprian Regus 	.probe = adin1140_probe,
785*20e69e67SCiprian Regus 	.id_table = adin1140_spi_id,
786*20e69e67SCiprian Regus };
787*20e69e67SCiprian Regus module_spi_driver(adin1140_driver);
788*20e69e67SCiprian Regus 
789*20e69e67SCiprian Regus MODULE_DESCRIPTION("Analog Devices, Inc. ADIN1140 10BASE-T1S MAC-PHY");
790*20e69e67SCiprian Regus MODULE_AUTHOR("Ciprian Regus <ciprian.regus@analog.com>");
791*20e69e67SCiprian Regus MODULE_LICENSE("GPL");
792