1 /*
2  * Copyright (c) 2023 DENX Software Engineering GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT microchip_lan865x
8 
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(eth_lan865x, CONFIG_ETHERNET_LOG_LEVEL);
11 
12 #include <zephyr/net/ethernet.h>
13 #include <zephyr/net/phy.h>
14 
15 #include <string.h>
16 #include <errno.h>
17 
18 #include <zephyr/net/net_if.h>
19 #include <zephyr/net/ethernet.h>
20 #include <zephyr/net/phy.h>
21 
22 #include "eth_lan865x_priv.h"
23 
lan865x_mac_rxtx_control(const struct device * dev,bool en)24 static int lan865x_mac_rxtx_control(const struct device *dev, bool en)
25 {
26 	struct lan865x_data *ctx = dev->data;
27 	uint32_t ctl = 0;
28 
29 	if (en) {
30 		ctl = LAN865x_MAC_NCR_TXEN | LAN865x_MAC_NCR_RXEN;
31 	}
32 
33 	return oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_NCR, ctl);
34 }
35 
lan865x_iface_init(struct net_if * iface)36 static void lan865x_iface_init(struct net_if *iface)
37 {
38 	const struct device *dev = net_if_get_device(iface);
39 	struct lan865x_data *ctx = dev->data;
40 
41 	net_if_set_link_addr(iface, ctx->mac_address, sizeof(ctx->mac_address),
42 			     NET_LINK_ETHERNET);
43 
44 	if (ctx->iface == NULL) {
45 		ctx->iface = iface;
46 	}
47 
48 	ethernet_init(iface);
49 
50 	net_eth_carrier_on(iface);
51 	ctx->iface_initialized = true;
52 }
53 
lan865x_port_get_capabilities(const struct device * dev)54 static enum ethernet_hw_caps lan865x_port_get_capabilities(const struct device *dev)
55 {
56 	ARG_UNUSED(dev);
57 	return ETHERNET_LINK_10BASE_T | ETHERNET_PROMISC_MODE;
58 }
59 
60 static int lan865x_gpio_reset(const struct device *dev);
61 static void lan865x_write_macaddress(const struct device *dev);
lan865x_set_config(const struct device * dev,enum ethernet_config_type type,const struct ethernet_config * config)62 static int lan865x_set_config(const struct device *dev, enum ethernet_config_type type,
63 			      const struct ethernet_config *config)
64 {
65 	const struct lan865x_config *cfg = dev->config;
66 	struct lan865x_data *ctx = dev->data;
67 	int ret = -ENOTSUP;
68 
69 	if (type == ETHERNET_CONFIG_TYPE_PROMISC_MODE) {
70 		ret = lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_OFF);
71 		if (ret) {
72 			return ret;
73 		}
74 
75 		ret = oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_NCFGR,
76 				       LAN865x_MAC_NCFGR_CAF);
77 		if (ret) {
78 			return ret;
79 		}
80 
81 		return lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON);
82 	}
83 
84 	if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) {
85 		ret = lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_OFF);
86 		if (ret) {
87 			return ret;
88 		}
89 
90 		memcpy(ctx->mac_address, config->mac_address.addr,
91 		       sizeof(ctx->mac_address));
92 
93 		lan865x_write_macaddress(dev);
94 
95 		net_if_set_link_addr(ctx->iface, ctx->mac_address,
96 				     sizeof(ctx->mac_address),
97 				     NET_LINK_ETHERNET);
98 
99 		return lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON);
100 	}
101 
102 	if (type == ETHERNET_CONFIG_TYPE_T1S_PARAM) {
103 		ret = lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_OFF);
104 		if (ret) {
105 			return ret;
106 		}
107 
108 		if (config->t1s_param.type == ETHERNET_T1S_PARAM_TYPE_PLCA_CONFIG) {
109 			cfg->plca->enable = config->t1s_param.plca.enable;
110 			cfg->plca->node_id = config->t1s_param.plca.node_id;
111 			cfg->plca->node_count = config->t1s_param.plca.node_count;
112 			cfg->plca->burst_count = config->t1s_param.plca.burst_count;
113 			cfg->plca->burst_timer = config->t1s_param.plca.burst_timer;
114 			cfg->plca->to_timer = config->t1s_param.plca.to_timer;
115 		}
116 
117 		/* Reset is required to re-program PLCA new configuration */
118 		lan865x_gpio_reset(dev);
119 	}
120 
121 	return ret;
122 }
123 
lan865x_wait_for_reset(const struct device * dev)124 static int lan865x_wait_for_reset(const struct device *dev)
125 {
126 	struct lan865x_data *ctx = dev->data;
127 	uint8_t i;
128 
129 	/* Wait for end of LAN865x reset */
130 	for (i = 0; !ctx->reset && i < LAN865X_RESET_TIMEOUT; i++) {
131 		k_msleep(1);
132 	}
133 
134 	if (i == LAN865X_RESET_TIMEOUT) {
135 		LOG_ERR("LAN865x reset timeout reached!");
136 		return -ENODEV;
137 	}
138 
139 	return 0;
140 }
141 
lan865x_gpio_reset(const struct device * dev)142 static int lan865x_gpio_reset(const struct device *dev)
143 {
144 	const struct lan865x_config *cfg = dev->config;
145 	struct lan865x_data *ctx = dev->data;
146 
147 	ctx->reset = false;
148 	ctx->tc6->protected = false;
149 
150 	/* Perform (GPIO based) HW reset */
151 	/* assert RESET_N low for 10 µs (5 µs min) */
152 	gpio_pin_set_dt(&cfg->reset, 1);
153 	k_busy_wait(10U);
154 	/* deassert - end of reset indicated by IRQ_N low  */
155 	gpio_pin_set_dt(&cfg->reset, 0);
156 
157 	return lan865x_wait_for_reset(dev);
158 }
159 
lan865x_check_spi(const struct device * dev)160 static int lan865x_check_spi(const struct device *dev)
161 {
162 	struct lan865x_data *ctx = dev->data;
163 	uint32_t val;
164 	int ret;
165 
166 	ret = oa_tc6_reg_read(ctx->tc6, LAN865x_DEVID, &val);
167 	if (ret < 0) {
168 		return -ENODEV;
169 	}
170 
171 	ctx->silicon_rev = val & LAN865X_REV_MASK;
172 	if (ctx->silicon_rev != 1 && ctx->silicon_rev != 2) {
173 		return -ENODEV;
174 	}
175 
176 	ctx->chip_id = (val >> 4) & 0xFFFF;
177 	if (ctx->chip_id != LAN8650_DEVID && ctx->chip_id != LAN8651_DEVID) {
178 		return -ENODEV;
179 	}
180 
181 	return ret;
182 }
183 
184 /* Implementation of pseudo code from AN1760 */
lan865x_read_indirect_reg(const struct device * dev,uint8_t addr,uint8_t mask)185 static uint8_t lan865x_read_indirect_reg(const struct device *dev, uint8_t addr,
186 					 uint8_t mask)
187 {
188 	struct lan865x_data *ctx = dev->data;
189 	uint32_t val;
190 
191 	oa_tc6_reg_write(ctx->tc6, 0x000400D8, addr);
192 	oa_tc6_reg_write(ctx->tc6, 0x000400DA, 0x02);
193 
194 	oa_tc6_reg_read(ctx->tc6, 0x000400D9, &val);
195 
196 	return (uint8_t) val & mask;
197 }
198 
lan865x_init_chip(const struct device * dev,uint8_t silicon_rev)199 static int lan865x_init_chip(const struct device *dev, uint8_t silicon_rev)
200 {
201 	struct lan865x_data *ctx = dev->data;
202 	uint8_t value1, value2;
203 	int8_t offset1 = 0, offset2 = 0, ret;
204 	uint16_t value3, value4, value5, value6, value7;
205 	uint16_t cfgparam1, cfgparam2, cfgparam3, cfgparam4, cfgparam5;
206 	uint32_t val;
207 
208 	ret = lan865x_read_indirect_reg(dev, 0x05, 0x40);
209 	if (ret == 0) {
210 		LOG_ERR("LAN865x error! Please contact microchip support for replacement.");
211 		return -EIO;
212 	}
213 
214 	value1 = lan865x_read_indirect_reg(dev, 0x04, 0x1F);
215 	if ((value1 & 0x10) != 0) { /* Convert uint8_t to int8_t */
216 		offset1 = value1 | 0xE0;
217 		if (offset1 < -5) {
218 			LOG_ERR("LAN865x internal error!");
219 			return -EIO;
220 		}
221 	} else {
222 		offset1 = value1;
223 	}
224 
225 	value2 = lan865x_read_indirect_reg(dev, 0x08, 0x1F);
226 	if ((value2 & 0x10) != 0) { /* Convert uint8_t to int8_t */
227 		offset2 = value2 | 0xE0;
228 	} else {
229 		offset2 = value2;
230 	}
231 
232 	oa_tc6_reg_read(ctx->tc6, 0x00040084, &val);
233 	value3 = (uint16_t)val;
234 
235 	oa_tc6_reg_read(ctx->tc6, 0x0004008A, &val);
236 	value4 = (uint16_t)val;
237 
238 	oa_tc6_reg_read(ctx->tc6, 0x000400AD, &val);
239 	value5 = (uint16_t)val;
240 
241 	oa_tc6_reg_read(ctx->tc6, 0x000400AE, &val);
242 	value6 = (uint8_t)val;
243 
244 	oa_tc6_reg_read(ctx->tc6, 0x000400AF, &val);
245 	value7 = (uint8_t)val;
246 
247 	cfgparam1 = (value3 & 0xF) | (((9 + offset1) << 10) | ((14 + offset1) << 4));
248 	cfgparam2 = (value4 & 0x3FF) | ((40 + offset2) << 10);
249 	cfgparam3 = (value5 & 0xC0C0) | (((5 + offset1) << 8) | (9 + offset1));
250 	cfgparam4 = (value6 & 0xC0C0) | (((9 + offset1) << 8) | (14 + offset1));
251 	cfgparam5 = (value7 & 0xC0C0) | (((17 + offset1) << 8) | (22 + offset1));
252 
253 	oa_tc6_reg_write(ctx->tc6, 0x00040084, (uint32_t) cfgparam1);
254 	oa_tc6_reg_write(ctx->tc6, 0x0004008A, (uint32_t) cfgparam2);
255 	oa_tc6_reg_write(ctx->tc6, 0x000400AD, (uint32_t) cfgparam3);
256 	oa_tc6_reg_write(ctx->tc6, 0x000400AE, (uint32_t) cfgparam4);
257 	oa_tc6_reg_write(ctx->tc6, 0x000400AF, (uint32_t) cfgparam5);
258 
259 	return 0;
260 }
261 /* Implementation of pseudo code from AN1760 - END */
262 
lan865x_config_plca(const struct device * dev,uint8_t node_id,uint8_t node_cnt,uint8_t burst_cnt,uint8_t burst_timer)263 static int lan865x_config_plca(const struct device *dev, uint8_t node_id,
264 			       uint8_t node_cnt, uint8_t burst_cnt, uint8_t burst_timer)
265 {
266 	struct lan865x_data *ctx = dev->data;
267 	uint32_t val;
268 
269 	/* Collision Detection */
270 	oa_tc6_reg_write(ctx->tc6, 0x00040087, 0x0083u); /* COL_DET_CTRL0 */
271 
272 	/* T1S Phy Node Id and Max Node Count */
273 	val = ((uint32_t)node_cnt << 8) | node_id;
274 	oa_tc6_reg_write(ctx->tc6, 0x0004CA02, val); /* PLCA_CONTROL_1_REGISTER */
275 
276 	/* PLCA Burst Count and Burst Timer */
277 	val = ((uint32_t)burst_cnt << 8) | burst_timer;
278 	oa_tc6_reg_write(ctx->tc6, 0x0004CA05, val); /* PLCA_BURST_MODE_REGISTER */
279 
280 	/* Enable PLCA */
281 	oa_tc6_reg_write(ctx->tc6, 0x0004CA01, BIT(15)); /* PLCA_CONTROL_0_REGISTER */
282 
283 	return 0;
284 }
285 
lan865x_write_macaddress(const struct device * dev)286 static void lan865x_write_macaddress(const struct device *dev)
287 {
288 	struct lan865x_data *ctx = dev->data;
289 	uint8_t *mac = &ctx->mac_address[0];
290 	uint32_t val;
291 
292 	/* SPEC_ADD2_BOTTOM */
293 	val = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0];
294 	oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAB2, val);
295 
296 	/* SPEC_ADD2_TOP */
297 	val = (mac[5] << 8) | mac[4];
298 	oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAT2, val);
299 
300 	/* SPEC_ADD1_BOTTOM */
301 	val = (mac[5] << 24) | (mac[4] << 16) | (mac[3] << 8) | mac[2];
302 	oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAB1, val);
303 }
304 
lan865x_default_config(const struct device * dev,uint8_t silicon_rev)305 static int lan865x_default_config(const struct device *dev, uint8_t silicon_rev)
306 {
307 	/* Values in the below table are the same for LAN865x rev. B0 and B1 */
308 	static const oa_mem_map_t lan865x_conf[] = {
309 		{ .address = 0x00010000, .value = 0x00000000 },
310 		{ .address = 0x00040091, .value = 0x00009660 },
311 		{ .address = 0x00040081, .value = 0x00000080 },
312 		{ .address = 0x00010077, .value = 0x00000028 },
313 		{ .address = 0x00040043, .value = 0x000000FF },
314 		{ .address = 0x00040044, .value = 0x0000FFFF },
315 		{ .address = 0x00040045, .value = 0x00000000 },
316 		{ .address = 0x00040053, .value = 0x000000FF },
317 		{ .address = 0x00040054, .value = 0x0000FFFF },
318 		{ .address = 0x00040055, .value = 0x00000000 },
319 		{ .address = 0x00040040, .value = 0x00000002 },
320 		{ .address = 0x00040050, .value = 0x00000002 },
321 		{ .address = 0x000400E9, .value = 0x00009E50 },
322 		{ .address = 0x000400F5, .value = 0x00001CF8 },
323 		{ .address = 0x000400F4, .value = 0x0000C020 },
324 		{ .address = 0x000400F8, .value = 0x00009B00 },
325 		{ .address = 0x000400F9, .value = 0x00004E53 },
326 		{ .address = 0x000400B0, .value = 0x00000103 },
327 		{ .address = 0x000400B1, .value = 0x00000910 },
328 		{ .address = 0x000400B2, .value = 0x00001D26 },
329 		{ .address = 0x000400B3, .value = 0x0000002A },
330 		{ .address = 0x000400B4, .value = 0x00000103 },
331 		{ .address = 0x000400B5, .value = 0x0000070D },
332 		{ .address = 0x000400B6, .value = 0x00001720 },
333 		{ .address = 0x000400B7, .value = 0x00000027 },
334 		{ .address = 0x000400B8, .value = 0x00000509 },
335 		{ .address = 0x000400B9, .value = 0x00000E13 },
336 		{ .address = 0x000400BA, .value = 0x00001C25 },
337 		{ .address = 0x000400BB, .value = 0x0000002B },
338 		{ .address = 0x0000000C, .value = 0x00000100 },
339 		{ .address = 0x00040081, .value = 0x000000E0 },
340 	};
341 	const struct lan865x_config *cfg = dev->config;
342 	uint8_t i, size = ARRAY_SIZE(lan865x_conf);
343 	struct lan865x_data *ctx = dev->data;
344 	int ret;
345 
346 	/* Enable protected control RW */
347 	oa_tc6_set_protected_ctrl(ctx->tc6, true);
348 
349 	for (i = 0; i < size; i++) {
350 		oa_tc6_reg_write(ctx->tc6, lan865x_conf[i].address,
351 				 lan865x_conf[i].value);
352 	}
353 
354 	if (silicon_rev == 1) {
355 		/* For silicon rev 1 (B0): (bit [3..0] from 0x0A0084 */
356 		oa_tc6_reg_write(ctx->tc6, 0x000400D0, 0x5F21);
357 	}
358 
359 	lan865x_write_macaddress(dev);
360 
361 	ret = lan865x_init_chip(dev, silicon_rev);
362 	if (ret < 0)
363 		return ret;
364 
365 	if (cfg->plca->enable) {
366 		ret = lan865x_config_plca(dev, cfg->plca->node_id,
367 					  cfg->plca->node_count,
368 					  cfg->plca->burst_count,
369 					  cfg->plca->burst_timer);
370 		if (ret < 0) {
371 			return ret;
372 		}
373 	}
374 	return 0;
375 }
376 
lan865x_int_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)377 static void lan865x_int_callback(const struct device *dev,
378 				  struct gpio_callback *cb,
379 				  uint32_t pins)
380 {
381 	ARG_UNUSED(dev);
382 	ARG_UNUSED(pins);
383 
384 	struct lan865x_data *ctx =
385 		CONTAINER_OF(cb, struct lan865x_data, gpio_int_callback);
386 
387 	k_sem_give(&ctx->int_sem);
388 }
389 
lan865x_read_chunks(const struct device * dev)390 static void lan865x_read_chunks(const struct device *dev)
391 {
392 	const struct lan865x_config *cfg = dev->config;
393 	struct lan865x_data *ctx = dev->data;
394 	struct oa_tc6 *tc6 = ctx->tc6;
395 	struct net_pkt *pkt;
396 	int ret;
397 
398 	pkt = net_pkt_rx_alloc(K_MSEC(cfg->timeout));
399 	if (!pkt) {
400 		LOG_ERR("OA RX: Could not allocate packet!");
401 		return;
402 	}
403 
404 	k_sem_take(&ctx->tx_rx_sem, K_FOREVER);
405 	ret = oa_tc6_read_chunks(tc6, pkt);
406 	if (ret < 0) {
407 		eth_stats_update_errors_rx(ctx->iface);
408 		net_pkt_unref(pkt);
409 		k_sem_give(&ctx->tx_rx_sem);
410 		return;
411 	}
412 
413 	/* Feed buffer frame to IP stack */
414 	ret = net_recv_data(ctx->iface, pkt);
415 	if (ret < 0) {
416 		LOG_ERR("OA RX: Could not process packet (%d)!", ret);
417 		net_pkt_unref(pkt);
418 	}
419 	k_sem_give(&ctx->tx_rx_sem);
420 }
421 
lan865x_int_thread(const struct device * dev)422 static void lan865x_int_thread(const struct device *dev)
423 {
424 	struct lan865x_data *ctx = dev->data;
425 	struct oa_tc6 *tc6 = ctx->tc6;
426 	uint32_t sts, val, ftr;
427 	int ret;
428 
429 	while (true) {
430 		k_sem_take(&ctx->int_sem, K_FOREVER);
431 		if (!ctx->reset) {
432 			oa_tc6_reg_read(tc6, OA_STATUS0, &sts);
433 			if (sts & OA_STATUS0_RESETC) {
434 				oa_tc6_reg_write(tc6, OA_STATUS0, sts);
435 				lan865x_default_config(dev, ctx->silicon_rev);
436 				oa_tc6_reg_read(tc6, OA_CONFIG0, &val);
437 				val |= OA_CONFIG0_SYNC | OA_CONFIG0_RFA_ZARFE;
438 				oa_tc6_reg_write(tc6, OA_CONFIG0, val);
439 				lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON);
440 
441 				ctx->reset = true;
442 				/*
443 				 * According to OA T1S standard - it is mandatory to
444 				 * read chunk of data to get the IRQ_N negated (deasserted).
445 				 */
446 				oa_tc6_read_status(tc6, &ftr);
447 				continue;
448 			}
449 		}
450 
451 		/*
452 		 * The IRQ_N is asserted when RCA becomes > 0. As described in
453 		 * OPEN Alliance 10BASE-T1x standard it is deasserted when first
454 		 * data header is received by LAN865x.
455 		 *
456 		 * Hence, it is mandatory to ALWAYS read at least one data chunk!
457 		 */
458 		do {
459 			lan865x_read_chunks(dev);
460 		} while (tc6->rca > 0);
461 
462 		ret = oa_tc6_check_status(tc6);
463 		if (ret == -EIO) {
464 			lan865x_gpio_reset(dev);
465 		}
466 	}
467 }
468 
lan865x_init(const struct device * dev)469 static int lan865x_init(const struct device *dev)
470 {
471 	const struct lan865x_config *cfg = dev->config;
472 	struct lan865x_data *ctx = dev->data;
473 	int ret;
474 
475 	__ASSERT(cfg->spi.config.frequency <= LAN865X_SPI_MAX_FREQUENCY,
476 		 "SPI frequency exceeds supported maximum\n");
477 
478 	if (!spi_is_ready_dt(&cfg->spi)) {
479 		LOG_ERR("SPI bus %s not ready", cfg->spi.bus->name);
480 		return -ENODEV;
481 	}
482 
483 	if (!gpio_is_ready_dt(&cfg->interrupt)) {
484 		LOG_ERR("Interrupt GPIO device %s is not ready",
485 			cfg->interrupt.port->name);
486 		return -ENODEV;
487 	}
488 
489 	/* Check SPI communication after reset */
490 	ret = lan865x_check_spi(dev);
491 	if (ret < 0) {
492 		LOG_ERR("SPI communication not working, %d", ret);
493 		return ret;
494 	}
495 
496 	/*
497 	 * Configure interrupt service routine for LAN865x IRQ
498 	 */
499 	ret = gpio_pin_configure_dt(&cfg->interrupt, GPIO_INPUT);
500 	if (ret < 0) {
501 		LOG_ERR("Failed to configure interrupt GPIO, %d", ret);
502 		return ret;
503 	}
504 
505 	gpio_init_callback(&(ctx->gpio_int_callback), lan865x_int_callback,
506 			   BIT(cfg->interrupt.pin));
507 
508 	ret = gpio_add_callback(cfg->interrupt.port, &ctx->gpio_int_callback);
509 	if (ret < 0) {
510 		LOG_ERR("Failed to add INT callback, %d", ret);
511 		return ret;
512 	}
513 
514 	gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_EDGE_TO_ACTIVE);
515 
516 	/* Start interruption-poll thread */
517 	ctx->tid_int =
518 		k_thread_create(&ctx->thread, ctx->thread_stack,
519 				CONFIG_ETH_LAN865X_IRQ_THREAD_STACK_SIZE,
520 				(k_thread_entry_t)lan865x_int_thread,
521 				(void *)dev, NULL, NULL,
522 				K_PRIO_COOP(CONFIG_ETH_LAN865X_IRQ_THREAD_PRIO),
523 				0, K_NO_WAIT);
524 	k_thread_name_set(ctx->tid_int, "lan865x_interrupt");
525 
526 	/* Perform HW reset - 'rst-gpios' required property set in DT */
527 	if (!gpio_is_ready_dt(&cfg->reset)) {
528 		LOG_ERR("Reset GPIO device %s is not ready",
529 			cfg->reset.port->name);
530 		return -ENODEV;
531 	}
532 
533 	ret = gpio_pin_configure_dt(&cfg->reset, GPIO_OUTPUT_INACTIVE);
534 	if (ret < 0) {
535 		LOG_ERR("Failed to configure reset GPIO, %d", ret);
536 		return ret;
537 	}
538 
539 	return lan865x_gpio_reset(dev);
540 }
541 
lan865x_port_send(const struct device * dev,struct net_pkt * pkt)542 static int lan865x_port_send(const struct device *dev, struct net_pkt *pkt)
543 {
544 	struct lan865x_data *ctx = dev->data;
545 	struct oa_tc6 *tc6 = ctx->tc6;
546 	int ret;
547 
548 	k_sem_take(&ctx->tx_rx_sem, K_FOREVER);
549 	ret = oa_tc6_send_chunks(tc6, pkt);
550 
551 	/* Check if rca > 0 during half-duplex TX transmission */
552 	if (tc6->rca > 0) {
553 		k_sem_give(&ctx->int_sem);
554 	}
555 
556 	k_sem_give(&ctx->tx_rx_sem);
557 	if (ret < 0) {
558 		LOG_ERR("TX transmission error, %d", ret);
559 		eth_stats_update_errors_tx(net_pkt_iface(pkt));
560 		return ret;
561 	}
562 
563 	return 0;
564 }
565 
566 static const struct ethernet_api lan865x_api_func = {
567 	.iface_api.init = lan865x_iface_init,
568 	.get_capabilities = lan865x_port_get_capabilities,
569 	.set_config = lan865x_set_config,
570 	.send = lan865x_port_send,
571 };
572 
573 #define LAN865X_DEFINE(inst)                                                                       \
574 	static struct lan865x_config_plca lan865x_config_plca_##inst = {                           \
575 		.node_id = DT_INST_PROP(inst, plca_node_id),                                       \
576 		.node_count = DT_INST_PROP(inst, plca_node_count),                                 \
577 		.burst_count = DT_INST_PROP(inst, plca_burst_count),                               \
578 		.burst_timer = DT_INST_PROP(inst, plca_burst_timer),                               \
579 		.to_timer = DT_INST_PROP(inst, plca_to_timer),                                     \
580 		.enable = DT_INST_PROP(inst, plca_enable),                                         \
581 	};                                                                                         \
582 												   \
583 	static const struct lan865x_config lan865x_config_##inst = {                               \
584 		.spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0),                             \
585 		.interrupt = GPIO_DT_SPEC_INST_GET(inst, int_gpios),                               \
586 		.reset = GPIO_DT_SPEC_INST_GET(inst, rst_gpios),                                   \
587 		.timeout = CONFIG_ETH_LAN865X_TIMEOUT,                                             \
588 		.plca = &lan865x_config_plca_##inst,                                               \
589 	};                                                                                         \
590 												   \
591 	struct oa_tc6 oa_tc6_##inst = {                                                            \
592 		.cps = 64,                                                                         \
593 		.protected = 0,                                                                    \
594 		.spi = &lan865x_config_##inst.spi                                                  \
595 	};                                                                                         \
596 	static struct lan865x_data lan865x_data_##inst = {                                         \
597 		.mac_address = DT_INST_PROP(inst, local_mac_address),                              \
598 		.tx_rx_sem =                                                                       \
599 			Z_SEM_INITIALIZER((lan865x_data_##inst).tx_rx_sem, 1, 1),                  \
600 		.int_sem = Z_SEM_INITIALIZER((lan865x_data_##inst).int_sem, 0, 1),                 \
601 		.tc6 = &oa_tc6_##inst                                                              \
602 	};                                                                                         \
603 												   \
604 	ETH_NET_DEVICE_DT_INST_DEFINE(inst, lan865x_init, NULL, &lan865x_data_##inst,              \
605 				      &lan865x_config_##inst, CONFIG_ETH_INIT_PRIORITY,            \
606 				      &lan865x_api_func, NET_ETH_MTU);
607 
608 DT_INST_FOREACH_STATUS_OKAY(LAN865X_DEFINE);
609