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 		return oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_NCFGR,
71 				       LAN865x_MAC_NCFGR_CAF);
72 	}
73 
74 	if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) {
75 		memcpy(ctx->mac_address, config->mac_address.addr,
76 		       sizeof(ctx->mac_address));
77 
78 		lan865x_write_macaddress(dev);
79 
80 		return net_if_set_link_addr(ctx->iface, ctx->mac_address,
81 				     sizeof(ctx->mac_address),
82 				     NET_LINK_ETHERNET);
83 	}
84 
85 	if (type == ETHERNET_CONFIG_TYPE_T1S_PARAM) {
86 		ret = lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_OFF);
87 		if (ret) {
88 			return ret;
89 		}
90 
91 		if (config->t1s_param.type == ETHERNET_T1S_PARAM_TYPE_PLCA_CONFIG) {
92 			cfg->plca->enable = config->t1s_param.plca.enable;
93 			cfg->plca->node_id = config->t1s_param.plca.node_id;
94 			cfg->plca->node_count = config->t1s_param.plca.node_count;
95 			cfg->plca->burst_count = config->t1s_param.plca.burst_count;
96 			cfg->plca->burst_timer = config->t1s_param.plca.burst_timer;
97 			cfg->plca->to_timer = config->t1s_param.plca.to_timer;
98 		}
99 
100 		/* Reset is required to re-program PLCA new configuration */
101 		lan865x_gpio_reset(dev);
102 	}
103 
104 	return ret;
105 }
106 
lan865x_wait_for_reset(const struct device * dev)107 static int lan865x_wait_for_reset(const struct device *dev)
108 {
109 	struct lan865x_data *ctx = dev->data;
110 	uint8_t i;
111 
112 	/* Wait for end of LAN865x reset */
113 	for (i = 0; !ctx->reset && i < LAN865X_RESET_TIMEOUT; i++) {
114 		k_msleep(1);
115 	}
116 
117 	if (i == LAN865X_RESET_TIMEOUT) {
118 		LOG_ERR("LAN865x reset timeout reached!");
119 		return -ENODEV;
120 	}
121 
122 	return 0;
123 }
124 
lan865x_gpio_reset(const struct device * dev)125 static int lan865x_gpio_reset(const struct device *dev)
126 {
127 	const struct lan865x_config *cfg = dev->config;
128 	struct lan865x_data *ctx = dev->data;
129 
130 	ctx->reset = false;
131 	ctx->tc6->protected = false;
132 
133 	/* Perform (GPIO based) HW reset */
134 	/* assert RESET_N low for 10 µs (5 µs min) */
135 	gpio_pin_set_dt(&cfg->reset, 1);
136 	k_busy_wait(10U);
137 	/* deassert - end of reset indicated by IRQ_N low  */
138 	gpio_pin_set_dt(&cfg->reset, 0);
139 
140 	return lan865x_wait_for_reset(dev);
141 }
142 
lan865x_check_spi(const struct device * dev)143 static int lan865x_check_spi(const struct device *dev)
144 {
145 	struct lan865x_data *ctx = dev->data;
146 	uint32_t val;
147 	int ret;
148 
149 	ret = oa_tc6_reg_read(ctx->tc6, LAN865x_DEVID, &val);
150 	if (ret < 0) {
151 		return -ENODEV;
152 	}
153 
154 	ctx->silicon_rev = val & LAN865X_REV_MASK;
155 	if (ctx->silicon_rev != 1 && ctx->silicon_rev != 2) {
156 		return -ENODEV;
157 	}
158 
159 	ctx->chip_id = (val >> 4) & 0xFFFF;
160 	if (ctx->chip_id != LAN8650_DEVID && ctx->chip_id != LAN8651_DEVID) {
161 		return -ENODEV;
162 	}
163 
164 	return ret;
165 }
166 
167 /* Implementation of pseudo code from AN1760 */
lan865x_read_indirect_reg(const struct device * dev,uint8_t addr,uint8_t mask)168 static uint8_t lan865x_read_indirect_reg(const struct device *dev, uint8_t addr,
169 					 uint8_t mask)
170 {
171 	struct lan865x_data *ctx = dev->data;
172 	uint32_t val;
173 
174 	oa_tc6_reg_write(ctx->tc6, 0x000400D8, addr);
175 	oa_tc6_reg_write(ctx->tc6, 0x000400DA, 0x02);
176 
177 	oa_tc6_reg_read(ctx->tc6, 0x000400D9, &val);
178 
179 	return (uint8_t) val & mask;
180 }
181 
182 /*
183  * Values in the below table for LAN865x rev. B0 and B1 (with place
184  * holders for cfgparamX.
185  */
186 static oa_mem_map_t lan865x_conf[] = {
187 	{ .mms = 0x1, .address = 0x00, .value = 0x0000 },
188 	{ .mms = 0x4, .address = 0xD0, .value = 0x3F31 },
189 	{ .mms = 0x4, .address = 0xE0, .value = 0xC000 },
190 	{ .mms = 0x4, .address = 0x84, .value = 0x0000 }, /* cfgparam1 */
191 	{ .mms = 0x4, .address = 0x8A, .value = 0x0000 }, /* cfgparam2 */
192 	{ .mms = 0x4, .address = 0xE9, .value = 0x9E50 },
193 	{ .mms = 0x4, .address = 0xF5, .value = 0x1CF8 },
194 	{ .mms = 0x4, .address = 0xF4, .value = 0xC020 },
195 	{ .mms = 0x4, .address = 0xF8, .value = 0xB900 },
196 	{ .mms = 0x4, .address = 0xF9, .value = 0x4E53 },
197 	{ .mms = 0x4, .address = 0x91, .value = 0x9660 },
198 	{ .mms = 0x4, .address = 0x77, .value = 0x0028 },
199 	{ .mms = 0x4, .address = 0x43, .value = 0x00FF },
200 	{ .mms = 0x4, .address = 0x44, .value = 0xFFFF },
201 	{ .mms = 0x4, .address = 0x45, .value = 0x0000 },
202 	{ .mms = 0x4, .address = 0x53, .value = 0x00FF },
203 	{ .mms = 0x4, .address = 0x54, .value = 0xFFFF },
204 	{ .mms = 0x4, .address = 0x55, .value = 0x0000 },
205 	{ .mms = 0x4, .address = 0x40, .value = 0x0002 },
206 	{ .mms = 0x4, .address = 0x50, .value = 0x0002 },
207 	{ .mms = 0x4, .address = 0xAD, .value = 0x0000 }, /* cfgparam3 */
208 	{ .mms = 0x4, .address = 0xAE, .value = 0x0000 }, /* cfgparam4 */
209 	{ .mms = 0x4, .address = 0xAF, .value = 0x0000 }, /* cfgparam5 */
210 	{ .mms = 0x4, .address = 0xB0, .value = 0x0103 },
211 	{ .mms = 0x4, .address = 0xB1, .value = 0x0910 },
212 	{ .mms = 0x4, .address = 0xB2, .value = 0x1D26 },
213 	{ .mms = 0x4, .address = 0xB3, .value = 0x002A },
214 	{ .mms = 0x4, .address = 0xB4, .value = 0x0103 },
215 	{ .mms = 0x4, .address = 0xB5, .value = 0x070D },
216 	{ .mms = 0x4, .address = 0xB6, .value = 0x1720 },
217 	{ .mms = 0x4, .address = 0xB7, .value = 0x0027 },
218 	{ .mms = 0x4, .address = 0xB8, .value = 0x0509 },
219 	{ .mms = 0x4, .address = 0xB9, .value = 0x0E13 },
220 	{ .mms = 0x4, .address = 0xBA, .value = 0x1C25 },
221 	{ .mms = 0x4, .address = 0xBB, .value = 0x002B },
222 	{ .mms = 0x4, .address = 0x0C, .value = 0x0100 },
223 	{ .mms = 0x4, .address = 0x81, .value = 0x00E0 },
224 };
225 
226 /* Based on AN1760 DS60001760G pseudo code */
lan865x_init_chip(const struct device * dev,uint8_t silicon_rev)227 static int lan865x_init_chip(const struct device *dev, uint8_t silicon_rev)
228 {
229 	uint16_t cfgparam1, cfgparam2, cfgparam3, cfgparam4, cfgparam5;
230 	uint8_t i, size = ARRAY_SIZE(lan865x_conf);
231 	struct lan865x_data *ctx = dev->data;
232 	int8_t offset1 = 0, offset2 = 0;
233 	uint8_t value1, value2;
234 
235 	/* Enable protected control RW */
236 	oa_tc6_set_protected_ctrl(ctx->tc6, true);
237 
238 	value1 = lan865x_read_indirect_reg(dev, 0x04, 0x1F);
239 	if ((value1 & 0x10) != 0) { /* Convert uint8_t to int8_t */
240 		offset1 = (int8_t)((uint8_t)value1 - 0x20);
241 	} else {
242 		offset1 = (int8_t)value1;
243 	}
244 
245 	value2 = lan865x_read_indirect_reg(dev, 0x08, 0x1F);
246 	if ((value2 & 0x10) != 0) { /* Convert uint8_t to int8_t */
247 		offset2 = (int8_t)((uint8_t)value2 - 0x20);
248 	} else {
249 		offset2 = (int8_t)value2;
250 	}
251 
252 	cfgparam1 = (uint16_t) (((9 + offset1) & 0x3F) << 10) |
253 		(uint16_t) (((14 + offset1) & 0x3F) << 4) | 0x03;
254 	cfgparam2 = (uint16_t) (((40 + offset2) & 0x3F) << 10);
255 	cfgparam3 = (uint16_t) (((5 + offset1) & 0x3F) << 8) |
256 		(uint16_t) ((9 + offset1) & 0x3F);
257 	cfgparam4 = (uint16_t) (((9 + offset1) & 0x3F) << 8) |
258 		(uint16_t) ((14 + offset1) & 0x3F);
259 	cfgparam5 = (uint16_t) (((17 + offset1) & 0x3F) << 8) |
260 		(uint16_t) ((22 + offset1) & 0x3F);
261 
262 	lan865x_update_dev_cfg_array(lan865x_conf, size,
263 				     MMS_REG(0x4, 0x84), cfgparam1);
264 	lan865x_update_dev_cfg_array(lan865x_conf, size,
265 				     MMS_REG(0x4, 0x8A), cfgparam2);
266 	lan865x_update_dev_cfg_array(lan865x_conf, size,
267 				     MMS_REG(0x4, 0xAD), cfgparam3);
268 	lan865x_update_dev_cfg_array(lan865x_conf, size,
269 				     MMS_REG(0x4, 0xAE), cfgparam4);
270 	lan865x_update_dev_cfg_array(lan865x_conf, size,
271 				     MMS_REG(0x4, 0xAF), cfgparam5);
272 
273 	if (silicon_rev == 1) {
274 		/* For silicon rev 1 (B0): (bit [3..0] from 0x0A0084 */
275 		lan865x_update_dev_cfg_array(lan865x_conf, size,
276 					     MMS_REG(0x4, 0xD0), 0x5F21);
277 	}
278 
279 	/* Write LAN865x config with correct order */
280 	for (i = 0; i < size; i++) {
281 		oa_tc6_reg_write(ctx->tc6, MMS_REG(lan865x_conf[i].mms,
282 						   lan865x_conf[i].address),
283 				 (uint32_t)lan865x_conf[i].value);
284 	}
285 
286 	return 0;
287 }
288 /* Implementation of pseudo code from AN1760 - END */
289 
lan865x_config_plca(const struct device * dev,uint8_t node_id,uint8_t node_cnt,uint8_t burst_cnt,uint8_t burst_timer)290 static int lan865x_config_plca(const struct device *dev, uint8_t node_id,
291 			       uint8_t node_cnt, uint8_t burst_cnt, uint8_t burst_timer)
292 {
293 	struct lan865x_data *ctx = dev->data;
294 	uint32_t val;
295 
296 	/* Collision Detection */
297 	oa_tc6_reg_write(ctx->tc6, 0x00040087, 0x0083u); /* COL_DET_CTRL0 */
298 
299 	/* T1S Phy Node ID and Max Node Count */
300 	if (node_id == 0) {
301 		val = (uint32_t)node_cnt << 8;
302 	} else {
303 		val = (uint32_t)node_id;
304 	}
305 	oa_tc6_reg_write(ctx->tc6, 0x0004CA02, val); /* PLCA_CONTROL_1_REGISTER */
306 
307 	/* PLCA Burst Count and Burst Timer */
308 	val = ((uint32_t)burst_cnt << 8) | burst_timer;
309 	oa_tc6_reg_write(ctx->tc6, 0x0004CA05, val); /* PLCA_BURST_MODE_REGISTER */
310 
311 	/* Enable PLCA */
312 	oa_tc6_reg_write(ctx->tc6, 0x0004CA01, BIT(15)); /* PLCA_CONTROL_0_REGISTER */
313 
314 	return 0;
315 }
316 
lan865x_write_macaddress(const struct device * dev)317 static void lan865x_write_macaddress(const struct device *dev)
318 {
319 	struct lan865x_data *ctx = dev->data;
320 	uint8_t *mac = &ctx->mac_address[0];
321 	uint32_t val;
322 
323 	/* SPEC_ADD2_BOTTOM */
324 	val = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0];
325 	oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAB2, val);
326 
327 	/* SPEC_ADD2_TOP */
328 	val = (mac[5] << 8) | mac[4];
329 	oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAT2, val);
330 
331 	/*
332 	 * SPEC_ADD1_BOTTOM - setting unique lower MAC address, back off time is
333 	 * generated out of it.
334 	 */
335 	val = (mac[5] << 24) | (mac[4] << 16) | (mac[3] << 8) | mac[2];
336 	oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAB1, val);
337 }
338 
lan865x_set_specific_multicast_addr(const struct device * dev)339 static int lan865x_set_specific_multicast_addr(const struct device *dev)
340 {
341 	struct lan865x_data *ctx = dev->data;
342 	uint32_t mac_h_hash = 0xffffffff;
343 	uint32_t mac_l_hash = 0xffffffff;
344 	int ret;
345 
346 	/* Enable hash for all multicast addresses */
347 	ret = oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_HRT, mac_h_hash);
348 	if (ret) {
349 		return ret;
350 	}
351 
352 	ret = oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_HRB, mac_l_hash);
353 	if (ret) {
354 		return ret;
355 	}
356 
357 	return oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_NCFGR,
358 				LAN865x_MAC_NCFGR_MTIHEN);
359 }
360 
lan865x_default_config(const struct device * dev,uint8_t silicon_rev)361 static int lan865x_default_config(const struct device *dev, uint8_t silicon_rev)
362 {
363 	const struct lan865x_config *cfg = dev->config;
364 	int ret;
365 
366 	lan865x_write_macaddress(dev);
367 	lan865x_set_specific_multicast_addr(dev);
368 
369 	ret = lan865x_init_chip(dev, silicon_rev);
370 	if (ret < 0) {
371 		return ret;
372 	}
373 
374 	if (cfg->plca->enable) {
375 		ret = lan865x_config_plca(dev, cfg->plca->node_id,
376 					  cfg->plca->node_count,
377 					  cfg->plca->burst_count,
378 					  cfg->plca->burst_timer);
379 		if (ret < 0) {
380 			return ret;
381 		}
382 	}
383 	return 0;
384 }
385 
lan865x_int_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)386 static void lan865x_int_callback(const struct device *dev,
387 				  struct gpio_callback *cb,
388 				  uint32_t pins)
389 {
390 	ARG_UNUSED(dev);
391 	ARG_UNUSED(pins);
392 
393 	struct lan865x_data *ctx =
394 		CONTAINER_OF(cb, struct lan865x_data, gpio_int_callback);
395 
396 	k_sem_give(&ctx->int_sem);
397 }
398 
lan865x_read_chunks(const struct device * dev)399 static void lan865x_read_chunks(const struct device *dev)
400 {
401 	const struct lan865x_config *cfg = dev->config;
402 	struct lan865x_data *ctx = dev->data;
403 	struct oa_tc6 *tc6 = ctx->tc6;
404 	struct net_pkt *pkt;
405 	int ret;
406 
407 	pkt = net_pkt_rx_alloc(K_MSEC(cfg->timeout));
408 	if (!pkt) {
409 		LOG_ERR("OA RX: Could not allocate packet!");
410 		return;
411 	}
412 
413 	k_sem_take(&ctx->tx_rx_sem, K_FOREVER);
414 	ret = oa_tc6_read_chunks(tc6, pkt);
415 	if (ret < 0) {
416 		eth_stats_update_errors_rx(ctx->iface);
417 		net_pkt_unref(pkt);
418 		k_sem_give(&ctx->tx_rx_sem);
419 		return;
420 	}
421 
422 	/* Feed buffer frame to IP stack */
423 	ret = net_recv_data(ctx->iface, pkt);
424 	if (ret < 0) {
425 		LOG_ERR("OA RX: Could not process packet (%d)!", ret);
426 		net_pkt_unref(pkt);
427 	}
428 	k_sem_give(&ctx->tx_rx_sem);
429 }
430 
lan865x_int_thread(const struct device * dev)431 static void lan865x_int_thread(const struct device *dev)
432 {
433 	struct lan865x_data *ctx = dev->data;
434 	struct oa_tc6 *tc6 = ctx->tc6;
435 	uint32_t sts, val, ftr;
436 	int ret;
437 
438 	while (true) {
439 		k_sem_take(&ctx->int_sem, K_FOREVER);
440 		if (!ctx->reset) {
441 			oa_tc6_reg_read(tc6, OA_STATUS0, &sts);
442 			if (sts & OA_STATUS0_RESETC) {
443 				oa_tc6_reg_write(tc6, OA_STATUS0, sts);
444 				lan865x_default_config(dev, ctx->silicon_rev);
445 				oa_tc6_reg_read(tc6, OA_CONFIG0, &val);
446 				val |= OA_CONFIG0_SYNC | OA_CONFIG0_RFA_ZARFE;
447 				oa_tc6_reg_write(tc6, OA_CONFIG0, val);
448 				lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON);
449 
450 				ctx->reset = true;
451 				/*
452 				 * According to OA T1S standard - it is mandatory to
453 				 * read chunk of data to get the IRQ_N negated (deasserted).
454 				 */
455 				oa_tc6_read_status(tc6, &ftr);
456 				continue;
457 			}
458 		}
459 
460 		/*
461 		 * The IRQ_N is asserted when RCA becomes > 0. As described in
462 		 * OPEN Alliance 10BASE-T1x standard it is deasserted when first
463 		 * data header is received by LAN865x.
464 		 *
465 		 * Hence, it is mandatory to ALWAYS read at least one data chunk!
466 		 */
467 		do {
468 			lan865x_read_chunks(dev);
469 		} while (tc6->rca > 0);
470 
471 		ret = oa_tc6_check_status(tc6);
472 		if (ret == -EIO) {
473 			lan865x_gpio_reset(dev);
474 		}
475 	}
476 }
477 
lan865x_init(const struct device * dev)478 static int lan865x_init(const struct device *dev)
479 {
480 	const struct lan865x_config *cfg = dev->config;
481 	struct lan865x_data *ctx = dev->data;
482 	int ret;
483 
484 	__ASSERT(cfg->spi.config.frequency <= LAN865X_SPI_MAX_FREQUENCY,
485 		 "SPI frequency exceeds supported maximum\n");
486 
487 	if (!spi_is_ready_dt(&cfg->spi)) {
488 		LOG_ERR("SPI bus %s not ready", cfg->spi.bus->name);
489 		return -ENODEV;
490 	}
491 
492 	if (!gpio_is_ready_dt(&cfg->interrupt)) {
493 		LOG_ERR("Interrupt GPIO device %s is not ready",
494 			cfg->interrupt.port->name);
495 		return -ENODEV;
496 	}
497 
498 	/* Check SPI communication after reset */
499 	ret = lan865x_check_spi(dev);
500 	if (ret < 0) {
501 		LOG_ERR("SPI communication not working, %d", ret);
502 		return ret;
503 	}
504 
505 	/*
506 	 * Configure interrupt service routine for LAN865x IRQ
507 	 */
508 	ret = gpio_pin_configure_dt(&cfg->interrupt, GPIO_INPUT);
509 	if (ret < 0) {
510 		LOG_ERR("Failed to configure interrupt GPIO, %d", ret);
511 		return ret;
512 	}
513 
514 	gpio_init_callback(&(ctx->gpio_int_callback), lan865x_int_callback,
515 			   BIT(cfg->interrupt.pin));
516 
517 	ret = gpio_add_callback(cfg->interrupt.port, &ctx->gpio_int_callback);
518 	if (ret < 0) {
519 		LOG_ERR("Failed to add INT callback, %d", ret);
520 		return ret;
521 	}
522 
523 	gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_EDGE_TO_ACTIVE);
524 
525 	/* Start interruption-poll thread */
526 	ctx->tid_int =
527 		k_thread_create(&ctx->thread, ctx->thread_stack,
528 				CONFIG_ETH_LAN865X_IRQ_THREAD_STACK_SIZE,
529 				(k_thread_entry_t)lan865x_int_thread,
530 				(void *)dev, NULL, NULL,
531 				K_PRIO_COOP(CONFIG_ETH_LAN865X_IRQ_THREAD_PRIO),
532 				0, K_NO_WAIT);
533 	k_thread_name_set(ctx->tid_int, "lan865x_interrupt");
534 
535 	/* Perform HW reset - 'rst-gpios' required property set in DT */
536 	if (!gpio_is_ready_dt(&cfg->reset)) {
537 		LOG_ERR("Reset GPIO device %s is not ready",
538 			cfg->reset.port->name);
539 		return -ENODEV;
540 	}
541 
542 	ret = gpio_pin_configure_dt(&cfg->reset, GPIO_OUTPUT_INACTIVE);
543 	if (ret < 0) {
544 		LOG_ERR("Failed to configure reset GPIO, %d", ret);
545 		return ret;
546 	}
547 
548 	return lan865x_gpio_reset(dev);
549 }
550 
lan865x_port_send(const struct device * dev,struct net_pkt * pkt)551 static int lan865x_port_send(const struct device *dev, struct net_pkt *pkt)
552 {
553 	struct lan865x_data *ctx = dev->data;
554 	struct oa_tc6 *tc6 = ctx->tc6;
555 	int ret;
556 
557 	k_sem_take(&ctx->tx_rx_sem, K_FOREVER);
558 	ret = oa_tc6_send_chunks(tc6, pkt);
559 
560 	/* Check if rca > 0 during half-duplex TX transmission */
561 	if (tc6->rca > 0) {
562 		k_sem_give(&ctx->int_sem);
563 	}
564 
565 	k_sem_give(&ctx->tx_rx_sem);
566 	if (ret < 0) {
567 		LOG_ERR("TX transmission error, %d", ret);
568 		eth_stats_update_errors_tx(net_pkt_iface(pkt));
569 		return ret;
570 	}
571 
572 	return 0;
573 }
574 
575 static const struct ethernet_api lan865x_api_func = {
576 	.iface_api.init = lan865x_iface_init,
577 	.get_capabilities = lan865x_port_get_capabilities,
578 	.set_config = lan865x_set_config,
579 	.send = lan865x_port_send,
580 };
581 
582 #define LAN865X_DEFINE(inst)                                                                       \
583 	static struct lan865x_config_plca lan865x_config_plca_##inst = {                           \
584 		.node_id = DT_INST_PROP(inst, plca_node_id),                                       \
585 		.node_count = DT_INST_PROP(inst, plca_node_count),                                 \
586 		.burst_count = DT_INST_PROP(inst, plca_burst_count),                               \
587 		.burst_timer = DT_INST_PROP(inst, plca_burst_timer),                               \
588 		.to_timer = DT_INST_PROP(inst, plca_to_timer),                                     \
589 		.enable = DT_INST_PROP(inst, plca_enable),                                         \
590 	};                                                                                         \
591 												   \
592 	static const struct lan865x_config lan865x_config_##inst = {                               \
593 		.spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0),                             \
594 		.interrupt = GPIO_DT_SPEC_INST_GET(inst, int_gpios),                               \
595 		.reset = GPIO_DT_SPEC_INST_GET(inst, rst_gpios),                                   \
596 		.timeout = CONFIG_ETH_LAN865X_TIMEOUT,                                             \
597 		.plca = &lan865x_config_plca_##inst,                                               \
598 	};                                                                                         \
599 												   \
600 	struct oa_tc6 oa_tc6_##inst = {                                                            \
601 		.cps = 64,                                                                         \
602 		.protected = 0,                                                                    \
603 		.spi = &lan865x_config_##inst.spi                                                  \
604 	};                                                                                         \
605 	static struct lan865x_data lan865x_data_##inst = {                                         \
606 		.mac_address = DT_INST_PROP(inst, local_mac_address),                              \
607 		.tx_rx_sem =                                                                       \
608 			Z_SEM_INITIALIZER((lan865x_data_##inst).tx_rx_sem, 1, 1),                  \
609 		.int_sem = Z_SEM_INITIALIZER((lan865x_data_##inst).int_sem, 0, 1),                 \
610 		.tc6 = &oa_tc6_##inst                                                              \
611 	};                                                                                         \
612 												   \
613 	ETH_NET_DEVICE_DT_INST_DEFINE(inst, lan865x_init, NULL, &lan865x_data_##inst,              \
614 				      &lan865x_config_##inst, CONFIG_ETH_INIT_PRIORITY,            \
615 				      &lan865x_api_func, NET_ETH_MTU);
616 
617 DT_INST_FOREACH_STATUS_OKAY(LAN865X_DEFINE);
618