This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 0f498005f05061295547f4362e2201a5548f5220
Author: michal matias <mich4l.mat...@gmail.com>
AuthorDate: Mon Aug 25 01:45:18 2025 +0200

    drivers/net/oa_tc6: Add driver for the Microchip LAN865x SPI MAC-PHY
    
    Add driver for the LAN865x 10BASE-T1S SPI MAC-PHY.
    The driver is a lower-half driver to the OA-TC6 base driver.
    
    Signed-off-by: michal matias <mich4l.mat...@gmail.com>
---
 drivers/net/oa_tc6/CMakeLists.txt   |   4 +
 drivers/net/oa_tc6/Kconfig          |  12 +
 drivers/net/oa_tc6/Make.defs        |   4 +
 drivers/net/oa_tc6/oa_tc6.c         |   9 +
 drivers/net/oa_tc6/oa_tc6_lan865x.c | 724 ++++++++++++++++++++++++++++++++++++
 drivers/net/oa_tc6/oa_tc6_lan865x.h |  59 +++
 include/nuttx/net/oa_tc6.h          |  21 ++
 7 files changed, 833 insertions(+)

diff --git a/drivers/net/oa_tc6/CMakeLists.txt 
b/drivers/net/oa_tc6/CMakeLists.txt
index 945f3e79c94..1769759ae05 100644
--- a/drivers/net/oa_tc6/CMakeLists.txt
+++ b/drivers/net/oa_tc6/CMakeLists.txt
@@ -27,5 +27,9 @@ if(CONFIG_NET_OA_TC6)
     list(APPEND SRCS oa_tc6_ncv7410.c)
   endif()
 
+  if(CONFIG_NET_OA_TC6_LAN865X)
+    list(APPEND SRCS oa_tc6_lan865x.c)
+  endif()
+
   target_sources(drivers PRIVATE ${SRCS})
 endif()
diff --git a/drivers/net/oa_tc6/Kconfig b/drivers/net/oa_tc6/Kconfig
index d31e4165312..65fdb7a80a2 100644
--- a/drivers/net/oa_tc6/Kconfig
+++ b/drivers/net/oa_tc6/Kconfig
@@ -23,4 +23,16 @@ config NET_OA_TC6_NCV7410_LEDS
        ---help---
                Setup DIO0 to blink on TX/RX and DIO1 to reflect the LCTL bit 
in the PHY CONTROL register (Up/Down).
 
+config NET_OA_TC6_LAN865X
+       bool "Microchip LAN865x 10BASE-T1S SPI MAC-PHY Support"
+       default n
+
+config NET_OA_TC6_LAN865X_MAC
+       int "LAN865x lower 3 bytes of MAC address"
+       default 0
+       range 0 16777215
+       depends on NET_OA_TC6_LAN865X
+       ---help---
+               LAN865x does not have a factory-assigned MAC address, it has to 
be provided externally
+
 endif
diff --git a/drivers/net/oa_tc6/Make.defs b/drivers/net/oa_tc6/Make.defs
index 4c1bfdef9f6..07b2eaf0e10 100644
--- a/drivers/net/oa_tc6/Make.defs
+++ b/drivers/net/oa_tc6/Make.defs
@@ -28,6 +28,10 @@ ifeq ($(CONFIG_NET_OA_TC6_NCV7410),y)
 CSRCS += oa_tc6_ncv7410.c
 endif
 
+ifeq ($(CONFIG_NET_OA_TC6_LAN865X),y)
+CSRCS += oa_tc6_lan865x.c
+endif
+
 DEPPATH += --dep-path net/oa_tc6
 CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)drivers$(DELIM)net$(DELIM)oa_tc6
 VPATH += :net/oa_tc6
diff --git a/drivers/net/oa_tc6/oa_tc6.c b/drivers/net/oa_tc6/oa_tc6.c
index 2db2d034686..d1ae60e3ffd 100644
--- a/drivers/net/oa_tc6/oa_tc6.c
+++ b/drivers/net/oa_tc6/oa_tc6.c
@@ -36,6 +36,10 @@
 #include "oa_tc6_ncv7410.h"
 #endif
 
+#ifdef CONFIG_NET_OA_TC6_LAN865X
+#include "oa_tc6_lan865x.h"
+#endif
+
 #include "oa_tc6.h"
 
 /****************************************************************************
@@ -1080,6 +1084,11 @@ static int oa_tc6_init_by_id(FAR struct spi_dev_s *spi,
       case OA_TC6_NCV7410_PHYID:
           ninfo("Info: Detected NCV7410 or NCN26010\n");
           return ncv7410_initialize(spi, config);
+#endif
+#ifdef CONFIG_NET_OA_TC6_LAN865X
+      case OA_TC6_LAN865X_PHYID:
+          ninfo("Info: Detected LAN865x\n");
+          return lan865x_initialize(spi, config);
 #endif
       default:
           nerr("Error: Unknown PHYID 0x%08lX. "
diff --git a/drivers/net/oa_tc6/oa_tc6_lan865x.c 
b/drivers/net/oa_tc6/oa_tc6_lan865x.c
new file mode 100644
index 00000000000..44560e7a5ec
--- /dev/null
+++ b/drivers/net/oa_tc6/oa_tc6_lan865x.c
@@ -0,0 +1,724 @@
+/****************************************************************************
+ * drivers/net/oa_tc6/oa_tc6_lan865x.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <string.h>
+
+#include <debug.h>
+
+#include <nuttx/kmalloc.h>
+
+#include "oa_tc6.h"
+#include "oa_tc6_lan865x.h"
+
+/****************************************************************************
+ * Preprocessor Macros
+ ****************************************************************************/
+
+#define LAN865X_ADDR_FILTER_SLOTS 4
+#define LAN865X_ADDR_FILTER_FULL  0xf
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct lan865x_addrfilter
+{
+  uint8_t addrs[LAN865X_ADDR_FILTER_SLOTS][6]; /* Addresses that pass   */
+  uint8_t active;                              /* LSB is the first slot
+                                                * 1 active, 0 inactive  */
+};
+
+struct lan865x_driver_s
+{
+  struct oa_tc6_driver_s oa_tc6_dev;
+
+  struct lan865x_addrfilter filter;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Helper functions */
+
+static int lan865x_init_mac_addr(FAR struct lan865x_driver_s *priv);
+static int lan865x_refresh_mac_filter(FAR struct lan865x_driver_s *priv);
+static int lan865x_set_filter_slot(FAR struct lan865x_driver_s *priv,
+                                   FAR const uint8_t *mac,
+                                   int slot);
+static int lan865x_indirect_read(FAR struct lan865x_driver_s *priv,
+                                 uint8_t addr, uint8_t mask,
+                                 FAR uint8_t *regval);
+static int lan865x_config(FAR struct lan865x_driver_s *priv);
+static int lan865x_enable(FAR struct lan865x_driver_s *priv);
+static int lan865x_disable(FAR struct lan865x_driver_s *priv);
+
+/* OA-TC6 lower callbacks */
+
+static int lan865x_action(FAR struct oa_tc6_driver_s *dev,
+                          enum oa_tc6_action_e action);
+static int lan865x_addmac(FAR struct oa_tc6_driver_s *dev,
+                          FAR const uint8_t *mac);
+static int lan865x_rmmac(FAR struct oa_tc6_driver_s *dev,
+                         FAR const uint8_t *mac);
+#ifdef CONFIG_NETDEV_IOCTL
+static int lan865x_ioctl(FAR struct oa_tc6_driver_s *dev, int cmd,
+                         unsigned long arg);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct oa_tc6_ops_s g_lan865x_ops =
+{
+  lan865x_action,
+  lan865x_addmac,
+  lan865x_rmmac,
+#ifdef CONFIG_NETDEV_IOCTL
+  lan865x_ioctl
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lan865x_init_mac_addr
+ *
+ * Description:
+ *   Read the OUI from the MAC-PHY and use it as the top 3 bytes of the MAC
+ *   address. The lower 3 bytes of the MAC address are read from
+ *   the configuration (LAN865x does not have a factory-assigned MAC
+ *   address).
+ *   Store the created MAC address into the driver structure.
+ *
+ * Input Parameters:
+ *   priv - pointer to the driver-specific state structure
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise ERROR is returned.
+ *
+ ****************************************************************************/
+
+static int lan865x_init_mac_addr(FAR struct lan865x_driver_s *priv)
+{
+  FAR struct oa_tc6_driver_s *dev = &priv->oa_tc6_dev;
+
+  uint32_t regval;
+  uint8_t  mac[6];
+
+  if (oa_tc6_read_reg(dev, OA_TC6_PHYID_REGID, &regval))
+    {
+      return ERROR;
+    }
+
+  mac[0] = oa_tc6_bitrev8(regval >> 26);
+  mac[1] = oa_tc6_bitrev8(regval >> 18);
+  mac[2] = oa_tc6_bitrev8(regval >> 10);
+
+  /* LAN865x has not the factory-assigned MAC address
+   * Load from config, later possibly set using SIOCSIFHWADDR ioctl
+   */
+
+  mac[3] = (uint8_t)(CONFIG_NET_OA_TC6_LAN865X_MAC >> 16);
+  mac[4] = (uint8_t)(CONFIG_NET_OA_TC6_LAN865X_MAC >> 8);
+  mac[5] = (uint8_t)CONFIG_NET_OA_TC6_LAN865X_MAC;
+
+  oa_tc6_store_mac_addr(dev, mac);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan865x_refresh_mac_filter
+ *
+ * Description:
+ *   Reinitialize all filter slots in the MAC-PHY marked active in the filter
+ *   structure. This is called during the config procedure.
+ *   The reason is that the config procedure may be called as a consequence
+ *   of the MAC-PHY losing its configuration, for example as a result of an
+ *   unexpected power cycle.
+ *
+ * Input Parameters:
+ *   priv - pointer to the driver-specific state structure
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise ERROR is returned.
+ *
+ ****************************************************************************/
+
+static int lan865x_refresh_mac_filter(FAR struct lan865x_driver_s *priv)
+{
+  uint8_t active = priv->filter.active;
+  int i;
+
+  for (i = 0; i < LAN865X_ADDR_FILTER_SLOTS; i++)
+    {
+      if (active & (1 << i))
+        {
+          FAR uint8_t *mac = priv->filter.addrs[i];
+
+          /* Slot (i + 1) as LAN865x slots are numbered from 1 */
+
+          if (lan865x_set_filter_slot(priv, mac, i + 1))
+            {
+              return ERROR;
+            }
+        }
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan865x_set_filter_slot
+ *
+ * Description:
+ *   Set the provided MAC address filter slot number with the provided MAC
+ *   address in a way that the given MAC address passes the filter.
+ *
+ * Input Parameters:
+ *   priv - pointer to the driver-specific state structure
+ *   mac  - pointer to the array representing the MAC address
+ *   slot - the number of the slot in the MAC-PHY (accorging to datasheet)
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise ERROR is returned.
+ *
+ ****************************************************************************/
+
+static int lan865x_set_filter_slot(FAR struct lan865x_driver_s *priv,
+                                   FAR const uint8_t *mac,
+                                   int slot)
+{
+  FAR struct oa_tc6_driver_s *dev = &priv->oa_tc6_dev;
+  uint32_t regval;
+
+  /* Write to the MAC-PHY */
+
+  regval =   (mac[3] << 24)
+           | (mac[2] << 16)
+           | (mac[1] << 8)
+           | (mac[0]);
+
+  if (oa_tc6_write_reg(dev, LAN865X_MAC_SAB_REGID(slot), regval))
+    {
+      nerr("Error: Error during SPI transmission\n");
+      return ERROR;
+    }
+
+  regval =   (mac[5] << 8)
+           | (mac[4]);
+
+  if (oa_tc6_write_reg(dev, LAN865X_MAC_SAT_REGID(slot), regval))
+    {
+      nerr("Error: Error during SPI transmission\n");
+      return ERROR;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan865x_indirect_read
+ *
+ * Description:
+ *   Microchip's proprietary configuration mechanism defined in the AN1760
+ *   appnote.
+ *   Note: The interface will probably work even without using
+ *   this mechanism.
+ *
+ * Input Parameters:
+ *   priv   - pointer to the driver-specific state structure
+ *   addr   - as defined in the AN1760
+ *   mask   - as defined in the AN1760
+ *   regval - corresponds to the return value from the AN1760
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise ERROR is returned.
+ *
+ ****************************************************************************/
+
+static int lan865x_indirect_read(FAR struct lan865x_driver_s *priv,
+                                 uint8_t addr, uint8_t mask,
+                                 FAR uint8_t *regval)
+{
+  FAR struct oa_tc6_driver_s *dev = &priv->oa_tc6_dev;
+  uint32_t regval32;
+  int err;
+
+  err = oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x00d8), addr);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x00da), 0x2);
+  err |= oa_tc6_read_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x00d9), &regval32);
+  *regval = (uint8_t)regval32 & mask;
+  if (err)
+    {
+      return ERROR;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan865x_config
+ *
+ * Description:
+ *   Implementation of the OA_TC6_ACTION_CONFIG for the LAN865x.
+ *   Perform the configuration as specified in the AN1760 appnote.
+ *   Disable address filtering if the promiscuous mode is desired.
+ *
+ * Input Parameters:
+ *   priv - pointer to the driver-specific state structure
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise ERROR is returned.
+ *
+ ****************************************************************************/
+
+static int lan865x_config(FAR struct lan865x_driver_s *priv)
+{
+  FAR struct oa_tc6_driver_s *dev = &priv->oa_tc6_dev;
+
+  /* AN1760 appnote variables */
+
+  int err;
+  uint8_t value1;
+  uint8_t value2;
+  int8_t offset1;
+  int8_t offset2;
+  uint16_t cfgparam1;
+  uint16_t cfgparam2;
+
+  ninfo("Info: Configuring LAN865x\n");
+
+  /* Perform the configuration procedure as outlined in the AN1760 appnote */
+
+  err = lan865x_indirect_read(priv, 0x04, 0x1f, &value1);
+  if ((value1 & 0x10) != 0)
+    {
+      offset1 = (int8_t) ((uint8_t)value1 - 0x20);
+    }
+  else
+    {
+      offset1 = (int8_t) value1;
+    }
+
+  err |= lan865x_indirect_read(priv, 0x08, 0x1f, &value2);
+  if ((value2 & 0x10) != 0)
+    {
+      offset2 = (int8_t) ((uint8_t)value2 - 0x20);
+    }
+  else
+    {
+      offset2 = (int8_t) value2;
+    }
+
+  cfgparam1 =   (uint16_t) (((9 + offset1) & 0x3f) << 10)
+              | (uint16_t) (((14 + offset1) & 0x3f) << 4) | 0x03;
+  cfgparam2 = (uint16_t) (((40 + offset2) & 0x3f) << 10);
+
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x00d0), 0x3f31);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x00e0), 0xc000);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x0084), cfgparam1);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x008a), cfgparam2);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x00e9), 0x9e50);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x00f5), 0x1cf8);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x00f4), 0xc020);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x00f8), 0xb900);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x00f9), 0x4e53);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x0081), 0x0080);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x0091), 0x9660);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x1, 0x0077), 0x0028);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x0043), 0x00ff);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x0044), 0xffff);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x0045), 0x0000);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x0053), 0x00ff);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x0054), 0xffff);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x0055), 0x0000);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x0040), 0x0002);
+  err |= oa_tc6_write_reg(dev, OA_TC6_MAKE_REGID(0x4, 0x0050), 0x0002);
+
+  if (err)
+    {
+      return ERROR;
+    }
+
+  /* End of AN1760 appnote */
+
+  if (lan865x_refresh_mac_filter(priv))
+    {
+      return ERROR;
+    }
+
+#ifdef CONFIG_NET_PROMISCUOUS
+  /* Disable MAC address filtering if promiscuous,
+   * use read-modify-write so reserved bits are not overridden
+   */
+
+  if (oa_tc6_set_clear_bits(dev, LAN865X_MAC_NCFGR_REGID,
+                            1 << LAN865X_MAC_NCFGR_CAF_POS, 0))
+    {
+      return ERROR;
+    }
+#endif
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan865x_enable
+ *
+ * Description:
+ *   Implementation of the OA_TC6_ACTION_ENABLE for the LAN865x.
+ *   Enable RX and TX on the MAC level.
+ *
+ * Input Parameters:
+ *   priv - pointer to the driver-specific state structure
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise ERROR is returned.
+ *
+ ****************************************************************************/
+
+static int lan865x_enable(FAR struct lan865x_driver_s *priv)
+{
+  FAR struct oa_tc6_driver_s *dev = &priv->oa_tc6_dev;
+
+  uint32_t setbits;
+
+  ninfo("Info: Enabling LAN865x MAC TX and RX\n");
+
+  /* Enable MAC TX, RX */
+
+  setbits =   (1 << LAN865X_MAC_NCR_TXEN_POS)
+            | (1 << LAN865X_MAC_NCR_RXEN_POS);
+
+  if (oa_tc6_set_clear_bits(dev, LAN865X_MAC_NCR_REGID, setbits, 0))
+    {
+      return ERROR;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan865x_disable
+ *
+ * Description:
+ *   Implementation of the OA_TC6_ACTION_DISABLE for the LAN865x.
+ *   Disable RX and TX on the MAC level.
+ *
+ * Input Parameters:
+ *   priv - pointer to the driver-specific state structure
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise ERROR is returned.
+ *
+ ****************************************************************************/
+
+static int lan865x_disable(FAR struct lan865x_driver_s *priv)
+{
+  FAR struct oa_tc6_driver_s *dev = &priv->oa_tc6_dev;
+
+  uint32_t clearbits;
+
+  ninfo("Info: Disabling LAN865x MAC TX and RX\n");
+
+  /* Enable MAC TX, RX */
+
+  clearbits =   (1 << LAN865X_MAC_NCR_TXEN_POS)
+              | (1 << LAN865X_MAC_NCR_RXEN_POS);
+
+  if (oa_tc6_set_clear_bits(dev, LAN865X_MAC_NCR_REGID, 0, clearbits))
+    {
+      return ERROR;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan865x_action
+ *
+ * Description:
+ *   OA-generic driver callback.
+ *   Perform the operation defined by the action argument if applicable.
+ *
+ * Input Parameters:
+ *   priv   - pointer to the driver-specific state structure
+ *   action - the code of the operation to perform
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise ERROR is returned.
+ *
+ ****************************************************************************/
+
+static int lan865x_action(FAR struct oa_tc6_driver_s *dev,
+                          enum oa_tc6_action_e action)
+{
+  FAR struct lan865x_driver_s *priv = (FAR struct lan865x_driver_s *)dev;
+
+  switch (action)
+    {
+      case OA_TC6_ACTION_CONFIG:
+          return lan865x_config(priv);
+
+      case OA_TC6_ACTION_ENABLE:
+          return lan865x_enable(priv);
+
+      case OA_TC6_ACTION_DISABLE:
+          return lan865x_disable(priv);
+
+      case OA_TC6_ACTION_EXST:
+          break;
+
+      default:
+          nerr("Error: Unknown OA-TC6 lower action number\n");
+          return ERROR;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan865x_addmac
+ *
+ * Description:
+ *   OA-generic driver callback.
+ *   Set the MAC address filter in a way that the given MAC address passes
+ *   the filter.
+ *
+ * Input Parameters:
+ *   priv - pointer to the driver-specific state structure
+ *   mac  - pointer to the array representing the MAC address
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise ERROR is returned.
+ *
+ ****************************************************************************/
+
+static int lan865x_addmac(FAR struct oa_tc6_driver_s *dev,
+                          FAR const uint8_t *mac)
+{
+  FAR struct lan865x_driver_s *priv = (FAR struct lan865x_driver_s *)dev;
+  uint8_t active = priv->filter.active;
+  int i;
+
+  /* Check if there is a free slot in the filter */
+
+  if (active == LAN865X_ADDR_FILTER_FULL)
+    {
+      nerr("Error: The address filter is already full\n");
+      return -EINVAL;
+    }
+
+  /* Check if the addr is already included */
+
+  for (i = 0; i < LAN865X_ADDR_FILTER_SLOTS; i++)
+    {
+      if (((active >> i) & 1) && memcmp(priv->filter.addrs[i], mac, 6) == 0)
+        {
+          nwarn("Warning: The provided address is already in the slot %d "
+                "of the filter\n", i + 1);
+          return OK;
+        }
+    }
+
+  /* Find the first free slot */
+
+  for (i = 0; i < LAN865X_ADDR_FILTER_SLOTS; i++)
+    {
+      if (((active >> i) & 1) == 0)
+        {
+          break;
+        }
+    }
+
+  /* Must write address register (i + 1) as in the case of LAN865x
+   * the MAC address filter registers are numbered from 1
+   */
+
+  if (lan865x_set_filter_slot(priv, mac, i + 1))
+    {
+      nerr("Error: Error setting filter slot\n");
+      return -EIO;
+    }
+
+  /* Update the filter structure */
+
+  memcpy(priv->filter.addrs[i], mac, 6);
+  active |= 1 << i;
+  priv->filter.active = active;
+
+  ninfo("Info: Adding new MAC address to the filter slot %d OK\n", i + 1);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan865x_rmmac
+ *
+ * Description:
+ *   OA-generic driver callback.
+ *   Remove the given MAC address from the MAC address filter.
+ *
+ * Input Parameters:
+ *   priv - pointer to the driver-specific state structure
+ *   mac  - pointer to the array representing the MAC address
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise ERROR is returned.
+ *
+ ****************************************************************************/
+
+static int lan865x_rmmac(FAR struct oa_tc6_driver_s *dev,
+                         FAR const uint8_t *mac)
+{
+  FAR struct lan865x_driver_s *priv = (FAR struct lan865x_driver_s *)dev;
+  uint8_t active = priv->filter.active;
+  int i;
+
+  for (i = 0; i < LAN865X_ADDR_FILTER_SLOTS; i++)
+    {
+      if (((active >> i) & 1) && memcmp(priv->filter.addrs[i], mac, 6) == 0)
+        {
+          break;
+        }
+
+      if (i == LAN865X_ADDR_FILTER_SLOTS - 1)
+        {
+          nwarn("Warning: The address is not present in the filter\n");
+          return OK;
+        }
+    }
+
+  /* Filter is disabled by writing the appropriate MAC_SAB register */
+
+  if (oa_tc6_write_reg(dev, LAN865X_MAC_SAB_REGID(i + 1), 0))
+    {
+      nerr("Error: Error during SPI transmission\n");
+      return -EIO;
+    }
+
+  /* Update the filter structure */
+
+  active &= ~(1 << i);
+  priv->filter.active = active;
+
+  ninfo("Info: Removing the MAC address from the filter slot %d OK\n",
+        i + 1);
+
+  return OK;
+}
+
+#ifdef CONFIG_NETDEV_IOCTL
+static int lan865x_ioctl(FAR struct oa_tc6_driver_s *dev, int cmd,
+                         unsigned long arg)
+{
+  return OA_TC6_IOCTL_CMD_NOT_IMPLEMENTED;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lan865x_initialize
+ *
+ * Description:
+ *   Initialize and register the OA-TC6 and the LAN865x drivers.
+ *   This function is called by the oa_tc6_initialize upon detecting
+ *   the LAN865x MAC-PHY on the SPI, but it also may be called directly from
+ *   the board level code.
+ *
+ * Input Parameters:
+ *   spi    - pointer to the initialized SPI interface
+ *   config - pointer to the initialized MAC-PHY configuration
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise negated errno is returned.
+ *
+ ****************************************************************************/
+
+int lan865x_initialize(FAR struct spi_dev_s *spi,
+                       FAR const struct oa_tc6_config_s *config)
+{
+  FAR struct lan865x_driver_s *priv;
+  FAR struct oa_tc6_driver_s *dev;
+  int retval;
+
+  priv = kmm_zalloc(sizeof(*priv));
+  if (priv == NULL)
+    {
+      nerr("Error: Could not allocate memory for lan865x_driver_s priv\n");
+      return -ENOMEM;
+    }
+
+  dev = &priv->oa_tc6_dev;
+
+  /* Save the ops pointer */
+
+  dev->ops = &g_lan865x_ops;
+
+  retval = oa_tc6_common_init(dev, spi, config);
+  if (retval)
+    {
+      nerr("Error: OA-TC6 common initialization failed\n");
+      goto errout;
+    }
+
+  /* Init MAC address */
+
+  if (lan865x_init_mac_addr(priv))
+    {
+      nerr("Error: Initialization of the MAC address failed\n");
+      retval = -EIO;
+      goto errout;
+    }
+
+  /* Here do something with additional structure fields or with the device
+   * if needed
+   */
+
+  /* Register */
+
+  retval = oa_tc6_register(dev);
+  if (retval == OK)
+    {
+      ninfo("Info: Successfully registered OA-TC6 LAN865x network driver\n");
+      return OK;
+    }
+
+  nerr("Error: Registration of the OA-TC6 LAN865x driver failed: %d\n",
+       retval);
+
+errout:
+  kmm_free(priv);
+  return retval;
+}
diff --git a/drivers/net/oa_tc6/oa_tc6_lan865x.h 
b/drivers/net/oa_tc6/oa_tc6_lan865x.h
new file mode 100644
index 00000000000..fb8665af03e
--- /dev/null
+++ b/drivers/net/oa_tc6/oa_tc6_lan865x.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+ * drivers/net/oa_tc6/oa_tc6_lan865x.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __DRIVERS_NET_OA_TC6_LAN865X_H
+#define __DRIVERS_NET_OA_TC6_LAN865X_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include "oa_tc6.h"
+
+/****************************************************************************
+ * Preprocessor Macros
+ ****************************************************************************/
+
+#define OA_TC6_LAN865X_PHYID 0x0007C1B4U
+
+/* Registers specific to the LAN865x */
+
+#define LAN865X_MAC_NCR_MMS         1
+#define LAN865X_MAC_NCR_ADDR        0x0U
+#define LAN865X_MAC_NCR_REGID       OA_TC6_MAKE_REGID(LAN865X_MAC_NCR_MMS, 
LAN865X_MAC_NCR_ADDR)
+#define LAN865X_MAC_NCR_TXEN_POS    3
+#define LAN865X_MAC_NCR_RXEN_POS    2
+
+#define LAN865X_MAC_NCFGR_MMS       1
+#define LAN865X_MAC_NCFGR_ADDR      0x1U
+#define LAN865X_MAC_NCFGR_REGID     OA_TC6_MAKE_REGID(LAN865X_MAC_NCFGR_MMS, 
LAN865X_MAC_NCFGR_ADDR)
+#define LAN865X_MAC_NCFGR_EFRHD_POS 25
+#define LAN865X_MAC_NCFGR_CAF_POS   4
+
+#define LAN865X_MAC_SAB1_MMS        1
+#define LAN865X_MAC_SAB1_ADDR       0x22U
+#define LAN865X_MAC_SAB1_REGID      OA_TC6_MAKE_REGID(LAN865X_MAC_SAB1_MMS, 
LAN865X_MAC_SAB1_ADDR)
+
+#define LAN865X_MAC_SAB_REGID(i)    OA_TC6_MAKE_REGID(LAN865X_MAC_SAB1_MMS, 
LAN865X_MAC_SAB1_ADDR + 2 * (i - 1))
+#define LAN865X_MAC_SAT_REGID(i)    OA_TC6_MAKE_REGID(LAN865X_MAC_SAB1_MMS, 
LAN865X_MAC_SAB1_ADDR + 2 * (i - 1) + 1)
+
+#endif /* __DRIVERS_NET_OA_TC6_LAN865X_H */
diff --git a/include/nuttx/net/oa_tc6.h b/include/nuttx/net/oa_tc6.h
index 5da121f9193..e18c3e87984 100644
--- a/include/nuttx/net/oa_tc6.h
+++ b/include/nuttx/net/oa_tc6.h
@@ -115,6 +115,27 @@ int oa_tc6_initialize(FAR struct spi_dev_s *spi,
 int ncv7410_initialize(FAR struct spi_dev_s *spi,
                        FAR const struct oa_tc6_config_s *config);
 
+/****************************************************************************
+ * Name: lan865x_initialize
+ *
+ * Description:
+ *   Initialize and register the OA-TC6 and the LAN865x drivers.
+ *   This function is called by the oa_tc6_initialize upon detecting
+ *   the LAN865x MAC-PHY on the SPI, but it also may be called directly from
+ *   the board level code.
+ *
+ * Input Parameters:
+ *   spi    - pointer to the initialized SPI interface
+ *   config - pointer to the initialized MAC-PHY configuration
+ *
+ * Returned Value:
+ *   On success OK is returned, otherwise negated errno is returned.
+ *
+ ****************************************************************************/
+
+int lan865x_initialize(FAR struct spi_dev_s *spi,
+                       FAR const struct oa_tc6_config_s *config);
+
 #undef EXTERN
 #ifdef __cplusplus
 }

Reply via email to