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