You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2024/02/18 15:40:50 UTC

(nuttx) 03/04: arch/nrf52: add initial support for IEEE 802.15.4

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 b3b543e093b1ed74431b344cc569429816457e7a
Author: raiden00pl <ra...@railab.me>
AuthorDate: Fri Feb 16 21:17:42 2024 +0100

    arch/nrf52: add initial support for IEEE 802.15.4
    
    Supported features:
    
    - frame transmition
    - frame reception and filtering
    - immediate ACK (incoming and outgoing)
    - promiscuous mode
    - delayed transmision
    - radio events trace
    - setting pending bit for all incoming Data Request frames
    - un-slotted CSMA-CA
    
    Work in progres features (some logic is present, but they require more work):
    
    - beacon transmision (periodic transmition works, but requires verification)
    - slotted CSMA-CA
    - GTS
    
    Fetures not implemented:
    
    - enhanced ACK (Enh-ACK)
    - enhanced beacon
    - low power mode
    - advanced features from IEEE 802.15.4e (DSME, TSCH)
    
    Added examples for boards:
    
    - nrf52832-dk: mrf24j40_6lowpan
    - nrf52832-dk: mrf24j40_mac
    - nrf52840-dk: ieee802154_6lowpan
    - nrf52840-dk: ieee802154_mac
    - nrf52840-dongle: ieee802154_mac
    - nrf9160-dk-nrf52: ieee802154_6lowpan
    - nrf9160-dk-nrf52: ieee802154_mac
---
 .../arm/nrf52/boards/nrf52840-dk/index.rst         |   17 +
 Documentation/platforms/arm/nrf52/ieee802154.rst   |   44 +
 Documentation/platforms/arm/nrf52/index.rst        |   14 +-
 arch/arm/src/nrf52/CMakeLists.txt                  |   14 +
 arch/arm/src/nrf52/Kconfig                         |   34 +
 arch/arm/src/nrf52/Make.defs                       |   11 +
 arch/arm/src/nrf52/nrf52_ieee802154.c              |  999 +++++++++
 arch/arm/src/nrf52/nrf52_ieee802154_priv.h         |  144 ++
 arch/arm/src/nrf52/nrf52_ieee802154_radio.c        | 2116 ++++++++++++++++++++
 arch/arm/src/nrf52/nrf52_ieee802154_radio.h        |  246 +++
 arch/arm/src/nrf52/nrf52_ieee802154_rtc.c          |  392 ++++
 .../arm/src/nrf52/nrf52_ieee802154_rtc.h           |  100 +-
 arch/arm/src/nrf52/nrf52_ieee802154_tim.c          |  347 ++++
 .../arm/src/nrf52/nrf52_ieee802154_tim.h           |   89 +-
 arch/arm/src/nrf52/nrf52_ieee802154_trace.c        |  154 ++
 .../arm/src/nrf52/nrf52_ieee802154_trace.h         |  114 +-
 .../arm/src/nrf52/nrf52_radio_ieee802154.h         |   35 +-
 boards/Kconfig                                     |    9 +
 .../include/nrf52_ieee802154.h}                    |   32 +-
 .../include/nrf52_mrf24j40.h}                      |   45 +-
 boards/arm/nrf52/common/src/CMakeLists.txt         |    8 +
 boards/arm/nrf52/common/src/Make.defs              |    8 +
 boards/arm/nrf52/common/src/nrf52_ieee802154.c     |  106 +
 boards/arm/nrf52/common/src/nrf52_mrf24j40.c       |  136 ++
 .../nrf52832-dk/configs/mrf24j40_6lowpan/defconfig |   81 +
 .../nrf52832-dk/configs/mrf24j40_mac/defconfig     |   60 +
 boards/arm/nrf52/nrf52832-dk/include/board.h       |   12 +
 boards/arm/nrf52/nrf52832-dk/src/CMakeLists.txt    |    8 +
 boards/arm/nrf52/nrf52832-dk/src/Make.defs         |    8 +
 boards/arm/nrf52/nrf52832-dk/src/nrf52832-dk.h     |   38 +
 boards/arm/nrf52/nrf52832-dk/src/nrf52_boot.c      |    6 +
 boards/arm/nrf52/nrf52832-dk/src/nrf52_bringup.c   |   15 +
 .../nrf52832-dk/src/nrf52_ieee802154_mrf24j40.c    |  177 ++
 boards/arm/nrf52/nrf52832-dk/src/nrf52_spi.c       |  177 ++
 .../configs/ieee802154_6lowpan/defconfig           |   81 +
 .../nrf52840-dk/configs/ieee802154_mac/defconfig   |   61 +
 boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c   |   15 +-
 .../configs/ieee802154_mac/defconfig               |   65 +
 .../nrf52/nrf52840-dongle/src/nrf52840-dongle.h    |   12 +
 .../arm/nrf52/nrf52840-dongle/src/nrf52_bringup.c  |   24 +
 .../configs/ieee802154_6lowpan/defconfig           |   81 +
 .../configs/ieee802154_mac/defconfig               |   56 +
 .../arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c |   28 +
 .../nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h  |   12 +
 include/nuttx/wireless/ieee802154/ieee802154_mac.h |    6 +
 45 files changed, 6056 insertions(+), 181 deletions(-)

diff --git a/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst b/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst
index 04c565c507..f48585f774 100644
--- a/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst
+++ b/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst
@@ -138,3 +138,20 @@ usbnsh
 ------
 
 Basic NuttShell configuration (CDCACM console enabled in USB Port, at 115200 bps).
+
+ieee802154_6lowpan
+------------------
+
+Cheat Sheet.  Here is a concise summary of all all the steps needed to
+run the UDP test (C=Coordinator; E=Endpoint)::
+
+         C: nsh> i8 wpan0 startpan cd:ab
+         C: nsh> i8 set saddr 0A:00
+         C: nsh> i8 set ep_saddr 0B:00
+         C: nsh> i8 acceptassoc
+         E: nsh> i8 wpan0 assoc
+         C: nsh> ifup wpan0
+         C: nsh> ifconfig          <-- To get the <server-ip>
+         E: nsh> ifup wpan0
+         C: nsh> udpserver &
+         E: nsh> udpclient <server-ip> &
diff --git a/Documentation/platforms/arm/nrf52/ieee802154.rst b/Documentation/platforms/arm/nrf52/ieee802154.rst
new file mode 100644
index 0000000000..7d2c348ec5
--- /dev/null
+++ b/Documentation/platforms/arm/nrf52/ieee802154.rst
@@ -0,0 +1,44 @@
+==========================
+Nordic nRF52 IEEE 802.15.4
+==========================
+
+.. note::
+
+   This driver is highly experimental.
+   Help with development and testing will be appreciated ;)
+
+Supported features:
+
+* frame transmission
+* frame reception and filtering
+* immediate ACK (incoming and outgoing)
+* promiscuous mode
+* delayed transmision
+* radio events trace
+* setting pending bit for all incoming Data Request frames
+* un-slotted CSMA-CA
+
+Work in progres features (some logic is present, but they require more work):
+    
+* beacon transmision (periodic transmition works, but requires verification)
+* slotted CSMA-CA
+* GTS
+
+Fetures not implemented:
+
+* enhanced ACK (Enh-ACK)
+* enhanced beacon
+* low power mode
+* advanced features from IEEE 802.15.4e (DSME, TSCH)
+
+Reserved peripherals
+====================
+
+This implementation reserves the following peripherals:
+
+* ``RADIO`` - used for radio operations
+
+* ``TIMER0`` - used as high resolution timer for ACK, IFS and other radio delays
+
+* ``RTC0`` - if superframe support is enabled, used as low power timer to hande
+  superframe events
diff --git a/Documentation/platforms/arm/nrf52/index.rst b/Documentation/platforms/arm/nrf52/index.rst
index 2bb73de03c..912422ee17 100644
--- a/Documentation/platforms/arm/nrf52/index.rst
+++ b/Documentation/platforms/arm/nrf52/index.rst
@@ -51,9 +51,9 @@ Peripheral Support
 
 The following list indicates peripherals supported in NuttX:
 
-==========  ======= =====
+==========  ======= ===============
 Peripheral  Support Notes
-==========  ======= =====
+==========  ======= ===============
 GPIO        Yes
 GPIOTE      Yes
 I2S         No
@@ -64,7 +64,7 @@ PPI         Yes
 PWM         Yes
 QDEC        No
 QSPI        Yes
-RADIO       Yes     Basic
+RADIO       Yes     BLE, IEEE 802.15.4
 RNG         Yes
 RTC         Yes
 SAADC       Yes
@@ -78,7 +78,7 @@ UART        Yes
 UARTE       No
 USBD        Yes
 WDT         Yes
-==========  ======= =====
+==========  ======= ===============
 
 Peripherals such as AAR, ACL, CCM, ECB are not directly used by NuttX since they
 are part of BLE controller implementation (link).
@@ -206,6 +206,11 @@ is provided with settings already set.
 Note that in this case, some peripherals (mostly those related to BLE) will be unavailable. Some PPI
 channels will also be ocuppied (``NRF52_PPI_NUM_CONFIGURABLE_CHANNELS`` will be set accordingly in this case).
 
+IEEE 802.15.4 Support
+=====================
+
+Details about IEEE 802.15.4 support for nRF52 can be found in :doc:`ieee802154`.
+
 Supported Boards
 ================
 
@@ -214,3 +219,4 @@ Supported Boards
    :maxdepth: 1
 
    boards/*/*
+   ieee802154.rst
diff --git a/arch/arm/src/nrf52/CMakeLists.txt b/arch/arm/src/nrf52/CMakeLists.txt
index 409db39c17..80b8c84408 100644
--- a/arch/arm/src/nrf52/CMakeLists.txt
+++ b/arch/arm/src/nrf52/CMakeLists.txt
@@ -94,6 +94,20 @@ endif()
 
 if(CONFIG_NRF52_RADIO)
   list(APPEND SRCS nrf52_radio.c)
+
+  if(CONFIG_NRF52_RADIO_IEEE802154)
+    list(APPEND SRCS nrf52_ieee802154_radio.c)
+    list(APPEND SRCS nrf52_ieee802154_tim.c)
+    list(APPEND SRCS nrf52_ieee802154.c)
+
+    if(CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME)
+      list(APPEND SRCS nrf52_ieee802154_rtc.c)
+    endif()
+
+    if(CONFIG_NRF52_RADIO_IEEE802154_TRACE)
+      list(APPEND SRCS nrf52_ieee802154_trace.c)
+    endif()
+  endif()
 endif()
 
 if(CONFIG_NRF52_TIMER)
diff --git a/arch/arm/src/nrf52/Kconfig b/arch/arm/src/nrf52/Kconfig
index 887404af28..5bd0a293bb 100644
--- a/arch/arm/src/nrf52/Kconfig
+++ b/arch/arm/src/nrf52/Kconfig
@@ -629,6 +629,40 @@ config NRF52_RADIO_CUSTOM
 	bool "RADIO uses custom IRQ handlers"
 	default n
 
+config NRF52_RADIO_IEEE802154
+	bool "RADIO IEEE802.15.4 protocol"
+	default n
+	depends on NRF52_HAVE_IEEE802154
+	select ARMV7M_USEBASEPRI
+	select ARCH_RAMVECTORS
+	select ARCH_IRQPRIO
+	select NRF52_RADIO_CUSTOM
+	select NRF52_TIMER0
+
+if NRF52_RADIO_IEEE802154
+
+config NRF52_RADIO_IEEE802154_SUPERFRAME
+	bool "RADIO IEEE802.15.4 superframe support"
+	default n
+	select NRF52_RTC0
+	select NRF52_USE_LFCLK
+
+config NRF52_RADIO_IEEE802154_GTS_SLOTS
+	int "RADIO IEEE802.15.4 GTS slots"
+	default 2
+	depends on NRF52_RADIO_IEEE802154_SUPERFRAME
+
+config NRF52_RADIO_IEEE802154_TRACE
+	bool "RADIO IEEE802.15.4 trace support"
+	default n
+
+config NRF52_RADIO_IEEE802154_TRACE_BUFSIZE
+	int "RADIO IEEE802.15.4 trace buffer size"
+	depends on NRF52_RADIO_IEEE802154_TRACE
+	default 1024
+
+endif
+
 endif #NRF52_RADIO
 
 endmenu # "RADIO Configuration"
diff --git a/arch/arm/src/nrf52/Make.defs b/arch/arm/src/nrf52/Make.defs
index c570f66ff4..12650bc976 100644
--- a/arch/arm/src/nrf52/Make.defs
+++ b/arch/arm/src/nrf52/Make.defs
@@ -89,6 +89,17 @@ endif
 
 ifeq ($(CONFIG_NRF52_RADIO),y)
 CHIP_CSRCS += nrf52_radio.c
+ifeq ($(CONFIG_NRF52_RADIO_IEEE802154),y)
+CHIP_CSRCS += nrf52_ieee802154_radio.c 
+CHIP_CSRCS += nrf52_ieee802154_tim.c 
+CHIP_CSRCS += nrf52_ieee802154.c
+ifeq ($(CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME),y)
+CHIP_CSRCS += nrf52_ieee802154_rtc.c 
+endif
+ifeq ($(CONFIG_NRF52_RADIO_IEEE802154_TRACE),y)
+CHIP_CSRCS += nrf52_ieee802154_trace.c
+endif
+endif
 endif
 
 ifeq ($(CONFIG_NRF52_TIMER),y)
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154.c b/arch/arm/src/nrf52/nrf52_ieee802154.c
new file mode 100644
index 0000000000..28956ce75e
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_ieee802154.c
@@ -0,0 +1,999 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_ieee802154.c
+ *
+ * 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 <nuttx/config.h>
+
+#include <debug.h>
+#include <string.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/mutex.h>
+#include <nuttx/wqueue.h>
+
+#include <nuttx/mm/iob.h>
+
+#include "nrf52_ieee802154_trace.h"
+
+#include "nrf52_ieee802154_priv.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_NRF52_RADIO_CUSTOM
+#  error RADIO custom interrupts must be enabled
+#endif
+
+#ifndef CONFIG_SCHED_HPWORK
+#  error High priority work queue required in this driver
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* IEEE 802.15.4 radio data */
+
+static struct nrf52_radioi8_dev_s g_nrf52_radioi8;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Set/get radio attributes */
+
+static int nrf52_radioi8_setrxmode(struct nrf52_radioi8_dev_s *dev,
+                                   int mode);
+static int nrf52_radioi8_setpanid(struct nrf52_radioi8_dev_s *dev,
+                                  const uint8_t *panid);
+static int nrf52_radioi8_setsaddr(struct nrf52_radioi8_dev_s *dev,
+                                  const uint8_t *saddr);
+static int nrf52_radioi8_seteaddr(struct nrf52_radioi8_dev_s *dev,
+                                  const uint8_t *eaddr);
+static int nrf52_radioi8_setcoordsaddr(struct nrf52_radioi8_dev_s *dev,
+                                       const uint8_t *saddr);
+static int nrf52_radioi8_setdevmode(struct nrf52_radioi8_dev_s *dev,
+                                    uint8_t mode);
+
+/* Radio ops */
+
+static int nrf52_radioi8_bind(struct ieee802154_radio_s *radio,
+                              struct ieee802154_radiocb_s *radiocb);
+static int nrf52_radioi8_reset(struct ieee802154_radio_s *radio);
+static int nrf52_radioi8_getattr(struct ieee802154_radio_s *radio,
+                                 enum ieee802154_attr_e attr,
+                                 union ieee802154_attr_u *attrval);
+static int nrf52_radioi8_setattr(struct ieee802154_radio_s *radio,
+                                 enum ieee802154_attr_e attr,
+                                 const union ieee802154_attr_u *attrval);
+static int nrf52_radioi8_txnotify(struct ieee802154_radio_s *radio,
+                                  bool gts);
+static int nrf52_radioi8_txdelayed(struct ieee802154_radio_s *radio,
+                                   struct ieee802154_txdesc_s *txdesc,
+                                   uint32_t symboldelay);
+static int nrf52_radioi8_rxenable(struct ieee802154_radio_s *radio,
+                                  bool enable);
+static int nrf52_radioi8_setchannel(struct nrf52_radioi8_dev_s *dev,
+                                    uint8_t chan);
+static int nrf52_radioi8_setcca(struct nrf52_radioi8_dev_s *dev,
+                                struct ieee802154_cca_s *cca);
+static int nrf52_radioi8_energydetect(struct ieee802154_radio_s *radio,
+                                      uint32_t nsymbols);
+
+static int
+nrf52_radioi8_beaconstart(struct ieee802154_radio_s *radio,
+                          const struct ieee802154_superframespec_s *sfspec,
+                          struct ieee802154_beaconframe_s *beacon);
+static int
+nrf52_radioi8_beaconupdate(struct ieee802154_radio_s *radio,
+                           struct ieee802154_beaconframe_s *beacon);
+static int nrf52_radioi8_beaconstop(struct ieee802154_radio_s *radio);
+static int
+nrf52_radioi8_sfupdate(struct ieee802154_radio_s *radio,
+                       const struct ieee802154_superframespec_s *sfspec);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_radioi8_setrxmode
+ *
+ * Description:
+ *   Set the RX mode (normal, promiscuous, no CRC).
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_setrxmode(struct nrf52_radioi8_dev_s *dev,
+                                   int mode)
+{
+  wlinfo("setrxmode %d\n", mode);
+
+  if (mode < NRF52_RXMODE_NORMAL || mode > NRF52_RXMODE_NOCRC)
+    {
+      return -EINVAL;
+    }
+
+  dev->state.rxmode = mode;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_setpanid
+ *
+ * Description:
+ *   Define the PAN ID the device is operating on.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_setpanid(struct nrf52_radioi8_dev_s *dev,
+                                  const uint8_t *panid)
+{
+  wlinfo("setpanid: %02X:%02X\n", panid[0], panid[1]);
+  IEEE802154_PANIDCOPY(dev->state.addr.panid, panid);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_setsaddr
+ *
+ * Description:
+ *   Define the device short address. The following addresses are special:
+ *
+ *     FFFEh : Broadcast
+ *     FFFFh : Unspecified
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_setsaddr(struct nrf52_radioi8_dev_s *dev,
+                                  const uint8_t *saddr)
+{
+  wlinfo("setsaddr: %02X:%02X\n", saddr[0], saddr[1]);
+  IEEE802154_SADDRCOPY(dev->state.addr.saddr, saddr);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_seteaddr
+ *
+ * Description:
+ *   Define the device extended address. The following addresses are special:
+ *
+ *     ffffffffffffffffh : Unspecified
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_seteaddr(struct nrf52_radioi8_dev_s *dev,
+                                  const uint8_t *eaddr)
+{
+  int i = 0;
+
+  wlinfo("seteaddr: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+         eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5],
+         eaddr[6], eaddr[7]);
+
+  for (i = 0; i < 8; i++)
+    {
+      dev->state.addr.eaddr[i] = eaddr[i];
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_setcoordsaddr
+ *
+ * Description:
+ *   Define the coordinator short address. The following addresses are
+ *   special:
+ *
+ *     FFFEh : Broadcast
+ *     FFFFh : Unspecified
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_setcoordsaddr(struct nrf52_radioi8_dev_s *dev,
+                                       const uint8_t *saddr)
+{
+  IEEE802154_SADDRCOPY(dev->state.addr.saddr, saddr);
+
+  wlinfo("setcoordsaddr: %02X:%02X\n", saddr[0], saddr[1]);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_setcoordeaddr
+ *
+ * Description:
+ *   Define the coordinator extended address. The following addresses are
+ *   special:
+ *
+ *     FFFFFFFFFFFFFFFFh : Unspecified
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_setcoordeaddr(struct nrf52_radioi8_dev_s *dev,
+                                       const uint8_t *eaddr)
+{
+  int i = 0;
+
+  wlinfo("setcoordeaddr: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+         eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5],
+         eaddr[6], eaddr[7]);
+
+  for (i = 0; i < 8; i++)
+    {
+      dev->state.addr.eaddr[i] = eaddr[i];
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_setdevmode
+ *
+ * Description:
+ *   Define the device behaviour: endpoint, coord or PAN coord.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_setdevmode(struct nrf52_radioi8_dev_s *dev,
+                                    uint8_t mode)
+{
+  wlinfo("setdevmode %d\n", mode);
+
+  if (mode < IEEE802154_DEVMODE_ENDPOINT ||
+      mode > IEEE802154_DEVMODE_PANCOORD)
+    {
+      return -EINVAL;
+    }
+
+  dev->state.devmode = mode;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_bind
+ *
+ * Description:
+ *   Bind radio callbacks.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_bind(struct ieee802154_radio_s *radio,
+                              struct ieee802154_radiocb_s *radiocb)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+
+  DEBUGASSERT(dev != NULL);
+  dev->radiocb = radiocb;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_reset
+ *
+ * Description:
+ *   Reset radio.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_reset(struct ieee802154_radio_s *radio)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+  struct ieee802154_cca_s     cca;
+  int                         ret = OK;
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_TRACE
+  /* Reset trace */
+
+  nrf52_radioi8_trace_init();
+#endif
+
+  /* Reset radio state */
+
+  memset(&dev->state, 0, sizeof(struct nrf52_radioi8_state_s));
+
+  /* Initialize radio in IEEE 802.15.4 mode */
+
+  ret = dev->radio->ops->reset(dev->radio);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  /* Reset TIMER */
+
+  dev->tim->ops->reset(dev);
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  /* Reset RTC */
+
+  dev->rtc->ops->reset(dev);
+#endif
+
+  /* Set channel */
+
+  nrf52_radioi8_setchannel(dev, 11);
+
+  /* Configure default CCA:
+   *   - CCA mode ED
+   *   - no carrier sense
+   *   - recommenced ED threshold -69 dBm
+   */
+
+  cca.use_ed = 1;
+  cca.use_cs = 0;
+  cca.edth   = 0x60;
+  cca.csth   = 0x00;
+  nrf52_radioi8_setcca(dev, &cca);
+
+  /* Configure initial RX mode */
+
+  nrf52_radioi8_setrxmode(dev, NRF52_RXMODE_NORMAL);
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_getattr
+ *
+ * Description:
+ *   Get radio attribute.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_getattr(struct ieee802154_radio_s *radio,
+                                 enum ieee802154_attr_e attr,
+                                 union ieee802154_attr_u *attrval)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+  int                         ret = OK;
+
+  switch (attr)
+    {
+      case IEEE802154_ATTR_MAC_EADDR:
+        {
+          memcpy(&attrval->mac.eaddr[0], &dev->state.addr.eaddr[0], 8);
+          ret = IEEE802154_STATUS_SUCCESS;
+          break;
+        }
+
+      case IEEE802154_ATTR_MAC_MAX_FRAME_WAITTIME:
+        {
+          attrval->mac.max_frame_waittime =
+            dev->radio->state.max_frame_waittime;
+          ret                             = IEEE802154_STATUS_SUCCESS;
+          break;
+        }
+
+      case IEEE802154_ATTR_PHY_SYMBOL_DURATION:
+        {
+          attrval->phy.symdur_picosec = (IEEE802154_SYMBOL_US * 1000000);
+          ret                         = IEEE802154_STATUS_SUCCESS;
+          break;
+        }
+
+      case IEEE802154_ATTR_PHY_CHAN:
+        {
+          attrval->phy.chan = dev->state.chan;
+          ret               = IEEE802154_STATUS_SUCCESS;
+          break;
+        }
+
+      case IEEE802154_ATTR_PHY_FCS_LEN:
+        {
+          attrval->phy.fcslen = 2;
+          ret                 = IEEE802154_STATUS_SUCCESS;
+          break;
+        }
+
+      case IEEE802154_ATTR_PHY_REGDUMP:
+        {
+          NRF52_RADIO_DUMPREGS(dev->radio->lower);
+          break;
+        }
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_TRACE
+      case IEEE802154_ATTR_PHY_TRACEDUMP:
+        {
+          nrf52_radioi8_trace_dump();
+          break;
+        }
+#endif
+
+      default:
+        {
+          ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE;
+          break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_setattr
+ *
+ * Description:
+ *   Set radio attribute.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_setattr(struct ieee802154_radio_s *radio,
+                                 enum ieee802154_attr_e attr,
+                                 const union ieee802154_attr_u *attrval)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+  int                         ret = IEEE802154_STATUS_SUCCESS;
+
+  switch (attr)
+    {
+      case IEEE802154_ATTR_MAC_PANID:
+        {
+          nrf52_radioi8_setpanid(dev, attrval->mac.panid);
+          break;
+        }
+
+      case IEEE802154_ATTR_MAC_SADDR:
+        {
+          nrf52_radioi8_setsaddr(dev, attrval->mac.saddr);
+          break;
+        }
+
+      case IEEE802154_ATTR_MAC_EADDR:
+        {
+          nrf52_radioi8_seteaddr(dev, attrval->mac.eaddr);
+          break;
+        }
+
+      case IEEE802154_ATTR_MAC_COORD_SADDR:
+        {
+          nrf52_radioi8_setcoordsaddr(dev, attrval->mac.coordsaddr);
+          break;
+        }
+
+      case IEEE802154_ATTR_MAC_COORD_EADDR:
+        {
+          nrf52_radioi8_setcoordeaddr(dev, attrval->mac.coordeaddr);
+          break;
+        }
+
+      case IEEE802154_ATTR_MAC_PROMISCUOUS_MODE:
+        {
+          if (attrval->mac.promisc_mode)
+            {
+              nrf52_radioi8_setrxmode(dev, NRF52_RXMODE_PROMISC);
+            }
+          else
+            {
+              nrf52_radioi8_setrxmode(dev, NRF52_RXMODE_NORMAL);
+            }
+          break;
+        }
+
+      case IEEE802154_ATTR_PHY_CHAN:
+        {
+          nrf52_radioi8_setchannel(dev, attrval->phy.chan);
+          break;
+        }
+
+      case IEEE802154_ATTR_MAC_DEVMODE:
+        {
+          nrf52_radioi8_setdevmode(dev, attrval->mac.devmode);
+          break;
+        }
+
+      default:
+        {
+          ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE;
+          break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_txnotify
+ *
+ * Description:
+ *   Driver callback invoked when new TX data is available.  This is a
+ *   stimulus perform an out-of-cycle poll and, thereby, reduce the TX
+ *   latency.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_txnotify(struct ieee802154_radio_s *radio,
+                                  bool gts)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+  int                         ret = OK;
+
+  if (gts)
+    {
+      ret = dev->radio->ops->gts_poll(dev);
+    }
+  else
+    {
+      ret = dev->radio->ops->csma_poll(dev);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_txdelayed
+ *
+ * Description:
+ *   Transmit a packet without regard to supeframe structure after a certain
+ *   number of symbols.  This function is used to send Data Request
+ *   responses.  It can also be used to send data immediately if the delay
+ *   is set to 0.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_txdelayed(struct ieee802154_radio_s *radio,
+                                   struct ieee802154_txdesc_s *txdesc,
+                                   uint32_t symboldelay)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+  int                         ret = OK;
+
+  /* Get exclusive access to the radio device */
+
+  ret = nxmutex_lock(&dev->lock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* There should never be more than one of these transactions at once. */
+
+  DEBUGASSERT(!dev->state.txdelayed_busy);
+
+  dev->state.txdelayed_desc = txdesc;
+  dev->state.txdelayed_busy = true;
+
+  /* TODO: should we add txdelayed to queue ? */
+
+  if (dev->radio->state.csma_busy)
+    {
+      return -EBUSY;
+    }
+
+  /* Wait for ACKTX done - we start transmition in
+   * nrf52_radioi8_state_acktx()
+   */
+
+  if (dev->radio->state.state == NRF52_RADIO_STATE_ACKTX)
+    {
+      goto out;
+    }
+
+  /* Setup TX */
+
+  dev->radio->ops->norm_setup(dev, txdesc->frame, false);
+
+  if (symboldelay == 0)
+    {
+      /* Send now */
+
+      dev->radio->ops->norm_trigger(dev);
+    }
+  else
+    {
+      /* Run TIMER - TX is handled in timer isr */
+
+      dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY, symboldelay);
+    }
+
+out:
+  nxmutex_unlock(&dev->lock);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rxenable
+ *
+ * Description:
+ *  Enable/Disable receiver.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_rxenable(struct ieee802154_radio_s *radio,
+                                  bool enable)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+
+  wlinfo("rxenable %d\n", enable);
+  return dev->radio->ops->rxenable(dev, enable);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_energydetect
+ *
+ * Description:
+ *   Start the energy detect measurement.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_energydetect(struct ieee802154_radio_s *radio,
+                                      uint32_t nsymbols)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+
+  return dev->radio->ops->energydetect(dev, nsymbols);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_setchannel
+ *
+ * Description:
+ *   Define the current radio channel the device is operating on.
+ *   In the 2.4 GHz, there are 16 channels, each 2 MHz wide, 5 MHz spacing:
+ *
+ *   Chan   MHz       Chan   MHz       Chan   MHz       Chan   MHz
+ *     11  2405         15  2425         19  2445         23  2465
+ *     12  2410         16  2430         20  2450         24  2470
+ *     13  2415         17  2435         21  2455         25  2475
+ *     14  2420         18  2440         22  2460         26  2480
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_setchannel(struct nrf52_radioi8_dev_s *dev,
+                                    uint8_t chan)
+{
+  int ret = OK;
+
+  wlinfo("setchannel: %u\n", (unsigned)chan);
+
+  if (dev->state.chan == chan)
+    {
+      return OK;
+    }
+
+  if (chan < 11 || chan > 26)
+    {
+      wlerr("Invalid chan: %d\n", chan);
+      return -EINVAL;
+    }
+
+  ret = dev->radio->ops->setchannel(dev, chan);
+  if (ret < 0)
+    {
+      wlerr("dev->radio->ops->setchannel failed %d\n", ret);
+      return -EINVAL;
+    }
+
+  dev->state.chan = chan;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_setcca
+ *
+ * Description:
+ *   Define the Clear Channel Assessement method.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_setcca(struct nrf52_radioi8_dev_s *dev,
+                                struct ieee802154_cca_s *cca)
+{
+  int ret = OK;
+
+  if (!cca->use_ed && !cca->use_cs)
+    {
+      return -EINVAL;
+    }
+
+  if (cca->use_cs && cca->csth > 0x0f)
+    {
+      return -EINVAL;
+    }
+
+  /* Configure CCA */
+
+  ret = dev->radio->ops->setcca(dev, cca);
+  if (ret < 0)
+    {
+      wlerr("dev->radio->ops->setcca failed %d\n", ret);
+      return -EINVAL;
+    }
+
+  memcpy(&dev->state.cca, cca, sizeof(struct ieee802154_cca_s));
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_beaconstart
+ *
+ * Description:
+ *   Start beacon.
+ *
+ ****************************************************************************/
+
+static int
+nrf52_radioi8_beaconstart(struct ieee802154_radio_s *radio,
+                          const struct ieee802154_superframespec_s *sfspec,
+                          struct ieee802154_beaconframe_s *beacon)
+{
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+  irqstate_t                  flags;
+
+  if (sfspec->pancoord)
+    {
+      flags = enter_critical_section();
+
+      /* Local copy */
+
+      memcpy(&dev->state.sf, (void *)sfspec,
+             sizeof(struct ieee802154_superframespec_s));
+
+      /* Setup beacon transmition */
+
+      dev->radio->ops->beacon_setup(dev, beacon->bf_data, beacon->bf_len);
+
+      /* Configure RTC events */
+
+      dev->rtc->ops->setup(dev, &dev->state.sf);
+
+      /* Start RTC */
+
+      dev->rtc->ops->start(dev);
+
+      leave_critical_section(flags);
+    }
+  else
+    {
+      /* TODO: missing logic for non-PAN coord */
+
+      return -ENOTTY;
+    }
+
+  return OK;
+#else
+  return -ENOTSUP;
+#endif
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_beaconupdate
+ *
+ * Description:
+ *   Update beacon.
+ *
+ ****************************************************************************/
+
+static int
+nrf52_radioi8_beaconupdate(struct ieee802154_radio_s *radio,
+                           struct ieee802154_beaconframe_s *beacon)
+{
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+  irqstate_t                  flags;
+
+  flags = enter_critical_section();
+
+  /* Arm the beacon TX buffer */
+
+  memcpy(&dev->radio->beaconbuf[1], beacon->bf_data, beacon->bf_len);
+
+  /* Length = Frame data + CRC */
+
+  dev->radio->beaconbuf[0] = beacon->bf_len + 2;
+
+  leave_critical_section(flags);
+
+  return OK;
+#else
+  return -ENOTSUP;
+#endif
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_beaconstop
+ *
+ * Description:
+ *   Stop beacon.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_beaconstop(struct ieee802154_radio_s *radio)
+{
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+  irqstate_t                  flags;
+
+  flags = enter_critical_section();
+
+  /* Stop RTC */
+
+  dev->rtc->ops->stop(dev);
+
+  leave_critical_section(flags);
+
+  return OK;
+#else
+  return -ENOTSUP;
+#endif
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_sfupdate
+ *
+ * Description:
+ *   Update super frame.
+ *
+ ****************************************************************************/
+
+static int
+nrf52_radioi8_sfupdate(struct ieee802154_radio_s *radio,
+                       const struct ieee802154_superframespec_s *sfspec)
+{
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
+  irqstate_t                  flags;
+
+  flags = enter_critical_section();
+
+  /* Local copy */
+
+  memcpy(&dev->state.sf, (void *)sfspec,
+         sizeof(struct ieee802154_superframespec_s));
+
+  /* If we are operating on a beacon-enabled network, use slotted CSMA */
+
+  if (sfspec->beaconorder < 15)
+    {
+      /* Need slotted CSMA-CA */
+
+      dev->radio->state.slotted = true;
+
+      /* Configure RTC */
+
+      dev->rtc->ops->setup(dev, &dev->state.sf);
+
+      /* Wait for beacon to sync */
+
+      dev->radio->state.wait_for_beacon = true;
+    }
+  else
+    {
+      /* Need un-slotted CSMA-CA */
+
+      dev->radio->state.slotted = false;
+    }
+
+  leave_critical_section(flags);
+
+  return OK;
+#else
+  return -ENOTSUP;
+#endif
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_radioi8_register
+ *
+ * Description:
+ *   Register NRF52 radio in IEE802154 mode.
+ *
+ ****************************************************************************/
+
+struct ieee802154_radio_s *
+nrf52_radioi8_register(struct nrf52_radio_board_s *board)
+{
+  struct nrf52_radioi8_dev_s *dev = &g_nrf52_radioi8;
+
+  /* Reset data */
+
+  memset(&g_nrf52_radioi8, 0, sizeof(struct nrf52_radioi8_dev_s));
+
+  /* Allow exclusive access to the privmac struct */
+
+  nxmutex_init(&dev->lock);
+
+  /* Initialize lower-half radio */
+
+  dev->radio = nrf52_radioi8_radio_init(dev, board);
+  if (dev->radio == NULL)
+    {
+      wlerr("nrf52_radioi8_radio_init failed %d\n", -errno);
+      return NULL;
+    }
+
+  DEBUGASSERT(dev->radio->ops->txstart);
+  DEBUGASSERT(dev->radio->ops->notify_noack);
+  DEBUGASSERT(dev->radio->ops->ccastart);
+  DEBUGASSERT(dev->radio->ops->rxenable);
+  DEBUGASSERT(dev->radio->ops->energydetect);
+  DEBUGASSERT(dev->radio->ops->setchannel);
+  DEBUGASSERT(dev->radio->ops->setcca);
+  DEBUGASSERT(dev->radio->ops->norm_setup);
+  DEBUGASSERT(dev->radio->ops->norm_trigger);
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  DEBUGASSERT(dev->radio->ops->beacon_setup);
+  DEBUGASSERT(dev->radio->ops->beacon_tx);
+#endif
+  DEBUGASSERT(dev->radio->ops->reset);
+  DEBUGASSERT(dev->radio->ops->csma_poll);
+  DEBUGASSERT(dev->radio->ops->gts_poll);
+
+  /* Initialize TIMER */
+
+  dev->tim = nrf52_radioi8_tim_init(dev);
+  if (dev->tim == NULL)
+    {
+      wlerr("nrf52_radioi8_tim_init failed %d\n", -errno);
+      return NULL;
+    }
+
+  DEBUGASSERT(dev->tim->ops->setup);
+  DEBUGASSERT(dev->tim->ops->stop);
+  DEBUGASSERT(dev->tim->ops->reset);
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  /* Initialize RTC */
+
+  dev->rtc = nrf52_radioi8_rtc_init(dev);
+  if (dev->rtc == NULL)
+    {
+      wlerr("nrf52_radioi8_rtc_init failed %d\n", -errno);
+      return NULL;
+    }
+
+  DEBUGASSERT(dev->rtc->ops->setup);
+  DEBUGASSERT(dev->rtc->ops->start);
+  DEBUGASSERT(dev->rtc->ops->stop);
+  DEBUGASSERT(dev->rtc->ops->reset);
+#endif
+
+  /* Connect MAC ops */
+
+  dev->macops.bind         = nrf52_radioi8_bind;
+  dev->macops.reset        = nrf52_radioi8_reset;
+  dev->macops.getattr      = nrf52_radioi8_getattr;
+  dev->macops.setattr      = nrf52_radioi8_setattr;
+  dev->macops.txnotify     = nrf52_radioi8_txnotify;
+  dev->macops.txdelayed    = nrf52_radioi8_txdelayed;
+  dev->macops.rxenable     = nrf52_radioi8_rxenable;
+  dev->macops.energydetect = nrf52_radioi8_energydetect;
+  dev->macops.beaconstart  = nrf52_radioi8_beaconstart;
+  dev->macops.beaconupdate = nrf52_radioi8_beaconupdate;
+  dev->macops.beaconstop   = nrf52_radioi8_beaconstop;
+  dev->macops.sfupdate     = nrf52_radioi8_sfupdate;
+
+  return &dev->macops;
+}
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_priv.h b/arch/arm/src/nrf52/nrf52_ieee802154_priv.h
new file mode 100644
index 0000000000..04e542ee3a
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_priv.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_ieee802154_priv.h
+ *
+ * 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 __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_PRIV_H
+#define __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_PRIV_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
+#include <nuttx/wireless/ieee802154/ieee802154_radio.h>
+
+#include "nrf52_ieee802154_radio.h"
+#include "nrf52_ieee802154_rtc.h"
+#include "nrf52_ieee802154_tim.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* GTS slots */
+
+#ifndef CONFIG_NRF52_RADIO_IEEE802154_GTS_SLOTS
+#  define NRF52_GTS_SLOTS 0
+#else
+#  define NRF52_GTS_SLOTS CONFIG_NRF52_RADIO_IEEE802154_GTS_SLOTS
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* RX modes */
+
+enum nrf52_ieee802154_rxmode_e
+{
+  NRF52_RXMODE_NORMAL,
+  NRF52_RXMODE_PROMISC,
+  NRF52_RXMODE_NOCRC
+};
+
+/* Device modes */
+
+enum nrf52_ieee802154_devmode_e
+{
+  NRF52_DEVMODE_ENDPOINT,
+  NRF52_DEVMODE_COORD,
+  NRF52_DEVMODE_PANCOORD
+};
+
+/* IEEE 802.15.4 device state */
+
+struct nrf52_radioi8_state_s
+{
+  /* MAC Attributes */
+
+  struct ieee802154_addr_s addr; /* Address */
+  struct ieee802154_cca_s  cca;  /* Clear channel assessement method */
+
+  /* TX CSMA */
+
+  struct ieee802154_txdesc_s *txdelayed_desc;
+  struct ieee802154_txdesc_s *csma_desc;
+
+  /* Radio state */
+
+  uint8_t  chan;                /* 11 to 26 for the 2.4 GHz band */
+  uint8_t  devmode;             /* device mode: endpoint, coord, PAN coord */
+  uint8_t  rxmode;              /* Reception mode: Normal, no CRC, promiscuous */
+
+  /* TX state */
+
+  bool     txdelayed_busy;      /* No CSMA transfer */
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  /* Superframe data */
+
+  struct ieee802154_superframespec_s sf;
+
+  /* TX GTS */
+
+  struct ieee802154_txdesc_s *gts_desc[NRF52_GTS_SLOTS];
+  bool                        gts_busy[NRF52_GTS_SLOTS];
+#endif
+};
+
+/* IEEE 802.15.4 radio device */
+
+struct nrf52_radioi8_dev_s
+{
+  /* The public device instance - must be first */
+
+  struct ieee802154_radio_s macops;
+
+  /* Registered callbacks */
+
+  struct ieee802154_radiocb_s *radiocb;
+
+  /* Radio interface */
+
+  struct nrf52_radioi8_radio_s *radio;
+
+  /* High resolution timer */
+
+  struct nrf52_radioi8_tim_s *tim;
+
+  /* Low resolution, low power timer */
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  struct nrf52_radioi8_rtc_s *rtc;
+#endif
+
+  /* Radio state */
+
+  struct nrf52_radioi8_state_s state;
+
+  /* Exclusive access to this struct */
+
+  mutex_t lock;
+};
+
+#endif  /* __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_PRIV_H */
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_radio.c b/arch/arm/src/nrf52/nrf52_ieee802154_radio.c
new file mode 100644
index 0000000000..e4c671504d
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_radio.c
@@ -0,0 +1,2116 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_ieee802154_radio.c
+ *
+ * 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 <nuttx/config.h>
+
+#include <debug.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/param.h>
+
+#include <nuttx/wqueue.h>
+#include <nuttx/mm/iob.h>
+
+#include "nrf52_ieee802154_radio.h"
+#include "nrf52_ieee802154_trace.h"
+
+#include "nrf52_ieee802154_priv.h"
+
+#include "hardware/nrf52_utils.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Constant from NRF52 manual */
+
+#define NRF52_ED_RSSISCALE            (4)
+
+/* ED configuration:
+ *   - IRQ on EDEND event (sampling of energy detection complete)
+ *   - shortcut between READY and EDSTART
+ *   - shortcut between EDEND and DISABLE
+ *
+ * Set in nrf52_radioi8_energydetect() reset in nrf52_radioi8_isr_radio().
+ *
+ * EDSTART task set in nrf52_radioi8_energydetect().
+ */
+
+#define IEEE802154_ED_INT             (RADIO_INT_EDEND)
+#define IEEE802154_ED_SHORTS          (RADIO_SHORTS_READY_EDSTART | \
+                                       RADIO_SHORTS_EDEND_DISABLE)
+
+/* RX configuration:
+ *   - IRQ on END event (packet recveived)
+ *   - shortcut between RXREADY and START
+ *   - shortcut between END and DISABLE
+ *
+ * Set in nrf52_radioi8_rxenable() reset in nrf52_radioi8_rxenable().
+ *
+ * RXEN task set in nrf52_radioi8_rxenable() and
+ * nrf52_radioi8_isr_radio() after RX handled and no pending ACKTX.
+ */
+
+#define IEEE802154_RX_INT              (RADIO_INT_END)
+#define IEEE802154_RX_SHORTS           (RADIO_SHORTS_RXREADY_START |  \
+                                        RADIO_SHORTS_END_DISABLE)
+
+/* NOTE: for TX we trigger interrupts on PHYEND event, not END! */
+
+/* TX CCA un-slotted configuration:
+ *   - IRQ on PHYEND event
+ *   - IRQ on CCABUSY event
+ *   - shortcut between TXREADY and START
+ *   - shortcut between PHYEND and DISABLE
+ *   - shortcut between RXREADY and CCASTART
+ *   - shortcut between CCAIDLE and STOP
+ *   - shortcut between CCAIDLE and TXEN
+ *
+ * Set in nrf52_radioi8_radio_norm_setup() reset in
+ * nrf52_radioi8_isr_radio().
+ *
+ * CCASTART task set in nrf52_radioi8_isr_tim() when CCA transfer.
+ */
+
+#define IEEE802154_TXCCAUNSLT_INT      (RADIO_INT_PHYEND |              \
+                                        RADIO_INT_CCABUSY)
+#define IEEE802154_TXCCAUNSLT_SHORTS   (RADIO_SHORTS_TXREADY_START |    \
+                                        RADIO_SHORTS_PHYEND_DISABLE |   \
+                                        RADIO_SHORTS_RXREADY_CCASTART | \
+                                        RADIO_SHORTS_CCAIDLE_STOP |     \
+                                        RADIO_SHORTS_CCAIDLE_TXEN)
+
+/* TX CCA slotted configuration:
+ *   - IRQ on PHYEND event
+ *   - IRQ on CCABUSY event
+ *   - IRQ on CCAIDLE event
+ *   - shortcut between TXREADY and START
+ *   - shortcut between PHYEND and DISABLE
+ *
+ * Set in nrf52_radioi8_radio_norm_setup() reset in
+ * nrf52_radioi8_isr_radio().
+ *
+ * CCASTART task set in nrf52_radioi8_isr_tim() when CCA transfer.
+ */
+
+#define IEEE802154_TXCCASLT_INT        (RADIO_INT_PHYEND |              \
+                                        RADIO_INT_CCAIDLE |             \
+                                        RADIO_INT_CCABUSY)
+#define IEEE802154_TXCCASLT_SHORTS     (RADIO_SHORTS_TXREADY_START |    \
+                                        RADIO_SHORTS_PHYEND_DISABLE |   \
+                                        RADIO_SHORTS_RXREADY_CCASTART)
+
+/* TX no-CCA configuration:
+ *   - IRQ on PHYEND event
+ *   - shortcut between TXREADY and START
+ *   - shortcut between PHYEND and DISABLE
+ *
+ * Set in nrf52_radioi8_radio_norm_setup() reset in
+ * nrf52_radioi8_isr_radio().
+ *
+ * TXEN task set in nrf52_radioi8_radio_norm_trigger() when non-CCA
+ * transfer or in nrf52_radioi8_isr_tim() for TXDELAY.
+ */
+
+#define IEEE802154_TX_INT              (RADIO_INT_PHYEND)
+#define IEEE802154_TX_SHORTS           (RADIO_SHORTS_TXREADY_START |  \
+                                        RADIO_SHORTS_PHYEND_DISABLE)
+
+/* ACK configuration:
+ *   - IRQ on PHYEND event
+ *   - shortcut between PHYEND and DISABLE
+ *
+ * Set in nrf52_radioi8_ack_transmit reset in nrf52_radioi8_isr_radio().
+ *
+ * TXEN task set in nrf52_radioi8_ack_transmit().
+ * START task set in nrf52_radioi8_isr_tim().
+ */
+
+#define IEEE802154_ACKTX_INT            (RADIO_INT_PHYEND)
+#define IEEE802154_ACKTX_SHORTS         (RADIO_SHORTS_PHYEND_DISABLE)
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void nrf52_radioi8_rx_parse(struct nrf52_radioi8_dev_s *dev,
+                                   uint8_t *ftype, uint8_t *cmdtype);
+static void nrf52_radioi8_ack_transmit(struct nrf52_radioi8_dev_s *dev);
+static bool nrf52_radioi8_filter(struct nrf52_radioi8_dev_s *dev);
+#if NRF52_GTS_SLOTS > 0
+static void nrf52_radioi8_gts_setup(struct nrf52_radioi8_dev_s *dev,
+                                    uint8_t fifo, struct iob_s *frame);
+#endif
+
+/* Ops */
+
+static void nrf52_radioi8_txstart(struct nrf52_radioi8_dev_s *dev);
+static void nrf52_radioi8_ccastart(struct nrf52_radioi8_dev_s *dev);
+static void nrf52_radioi8_notify_noack(struct nrf52_radioi8_dev_s *dev);
+static int nrf52_radioi8_rxenable(struct nrf52_radioi8_dev_s *dev,
+                                  bool enable);
+static int nrf52_radioi8_energydetect(struct nrf52_radioi8_dev_s *dev,
+                                      uint32_t nsymbols);
+static int nrf52_radioi8_setchannel(struct nrf52_radioi8_dev_s *dev,
+                                    uint8_t chan);
+static int nrf52_radioi8_setcca(struct nrf52_radioi8_dev_s *dev,
+                                struct ieee802154_cca_s *cca);
+static void nrf52_radioi8_norm_setup_buf(struct nrf52_radioi8_dev_s *dev,
+                                         uint8_t *buf, bool csma);
+static void nrf52_radioi8_norm_setup(struct nrf52_radioi8_dev_s *dev,
+                                     struct iob_s *frame, bool csma);
+static void nrf52_radioi8_norm_trigger(struct nrf52_radioi8_dev_s *dev);
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+static void nrf52_radioi8_beacon_setup(struct nrf52_radioi8_dev_s *dev,
+                                       uint8_t *data, uint8_t len);
+static void nrf52_radioi8_beacon_tx(struct nrf52_radioi8_dev_s *dev);
+#endif
+static int nrf52_radioi8_reset(struct nrf52_radioi8_radio_s *dev);
+static int nrf52_radioi8_csmapoll(struct nrf52_radioi8_dev_s *dev);
+static int nrf52_radioi8_gtspoll(struct nrf52_radioi8_dev_s *dev);
+
+/* Interrupts logic */
+
+static void nrf52_radioi8_work_noack(void *arg);
+static void nrf52_radioi8_work_rx(void *arg);
+static void nrf52_radioi8_work_tx(void *arg);
+static void nrf52_radioi8_work_busy(void *arg);
+static void nrf52_radioi8_work_ed(void *arg);
+static void nrf52_radioi8_state_rx(struct nrf52_radioi8_dev_s *dev);
+static void nrf52_radioi8_state_tx(struct nrf52_radioi8_dev_s *dev);
+static void nrf52_radioi8_state_acktx(struct nrf52_radioi8_dev_s *dev);
+static void nrf52_radioi8_state_ed(struct nrf52_radioi8_dev_s *dev);
+static int nrf52_radioi8_isr_radio(int irq, void *context, void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Packet buffers - must be byte aligned in RAM.
+ *
+ * NOTE: The first byte is PHR, the last byte is LQI.
+ */
+
+static uint8_t aligned_data(8)
+  g_nrf52_radioi8_rxbuf[IEEE802154_MAX_PHY_PACKET_SIZE + 2];
+
+static uint8_t aligned_data(8)
+  g_nrf52_radioi8_txbuf[IEEE802154_MAX_PHY_PACKET_SIZE + 2];
+
+static uint8_t aligned_data(8)
+  g_nrf52_radioi8_ackbuf[IEEE802154_ACK_FRAME_SIZE + 1];
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+static uint8_t aligned_data(8)
+  g_nrf52_radioi8_beaconbuf[IEEE802154_MAX_PHY_PACKET_SIZE + 2];
+#endif
+
+/* Radio ops */
+
+static struct nrf52_radioi8_radio_ops_s g_radioi8_radio_ops =
+{
+  .txstart      = nrf52_radioi8_txstart,
+  .ccastart     = nrf52_radioi8_ccastart,
+  .notify_noack = nrf52_radioi8_notify_noack,
+  .rxenable     = nrf52_radioi8_rxenable,
+  .energydetect = nrf52_radioi8_energydetect,
+  .setchannel   = nrf52_radioi8_setchannel,
+  .setcca       = nrf52_radioi8_setcca,
+  .norm_setup   = nrf52_radioi8_norm_setup,
+  .norm_trigger = nrf52_radioi8_norm_trigger,
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  .beacon_setup = nrf52_radioi8_beacon_setup,
+  .beacon_tx    = nrf52_radioi8_beacon_tx,
+#endif
+  .reset        = nrf52_radioi8_reset,
+  .csma_poll    = nrf52_radioi8_csmapoll,
+  .gts_poll     = nrf52_radioi8_gtspoll
+};
+
+/* Radio interface */
+
+static struct nrf52_radioi8_radio_s g_radioi8_radio;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rx_parse
+ *
+ * Description:
+ *   Get the RX frame type and command type if present.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_rx_parse(struct nrf52_radioi8_dev_s *dev,
+                                   uint8_t *ftype, uint8_t *cmdtype)
+{
+  uint16_t *frame_ctrl = NULL;
+  uint8_t   smode      = 0;
+  uint8_t   dmode      = 0;
+  uint8_t   panid_comp = 0;
+  int       i          = 0;
+
+  /* Frame starts from offset 1 */
+
+  i = 1;
+
+  /* Frame ctrl */
+
+  frame_ctrl = (uint16_t *)&dev->radio->rxbuf[i];
+  i += sizeof(uint16_t);
+
+  /* Frame seq */
+
+  i += 1;
+
+  /* Return now if a given frame is not a command frame */
+
+  *ftype = ((*frame_ctrl & IEEE802154_FRAMECTRL_FTYPE) >>
+            IEEE802154_FRAMECTRL_SHIFT_FTYPE);
+  if (*ftype != IEEE802154_FRAME_COMMAND)
+    {
+      return;
+    }
+
+  /* Now we have to find the offset for the frame command type */
+
+  smode = ((*frame_ctrl & IEEE802154_FRAMECTRL_SADDR) >>
+           IEEE802154_FRAMECTRL_SHIFT_SADDR);
+
+  dmode = ((*frame_ctrl & IEEE802154_FRAMECTRL_DADDR) >>
+           IEEE802154_FRAMECTRL_SHIFT_DADDR);
+
+  panid_comp = ((*frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP) >>
+                IEEE802154_FRAMECTRL_SHIFT_PANIDCOMP);
+
+  if (dmode != IEEE802154_ADDRMODE_NONE)
+    {
+      i += IEEE802154_PANIDSIZE;
+
+      if (dmode == IEEE802154_ADDRMODE_SHORT)
+        {
+          i += IEEE802154_SADDRSIZE;
+        }
+      else if (dmode == IEEE802154_ADDRMODE_EXTENDED)
+        {
+          i += IEEE802154_EADDRSIZE;
+        }
+    }
+
+  if (smode != IEEE802154_ADDRMODE_NONE)
+    {
+      if (!panid_comp)
+        {
+          i += IEEE802154_PANIDSIZE;
+        }
+
+      if (smode == IEEE802154_ADDRMODE_SHORT)
+        {
+          i += IEEE802154_SADDRSIZE;
+        }
+      else if (smode == IEEE802154_ADDRMODE_EXTENDED)
+        {
+          i += IEEE802154_EADDRSIZE;
+        }
+    }
+
+  *cmdtype = dev->radio->rxbuf[i];
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_ack_transmit
+ *
+ * Description:
+ *   Transmit ACK.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_ack_transmit(struct nrf52_radioi8_dev_s *dev)
+{
+  struct nrf52_radio_dev_s *lower   = NULL;
+  uint8_t                  *ackbuf  = dev->radio->ackbuf;
+  uint32_t                  regval  = 0;
+  uint8_t                   ftype   = 0;
+  uint8_t                   cmdtype = 0;
+  bool                      pending = false;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  /* Restore RX after ACK - we already are in DISABLE state so no need to
+   * disable RX
+   */
+
+  if (dev->radio->state.rxenabled)
+    {
+      dev->radio->state.rxrestore = true;
+    }
+
+  /* Clear events */
+
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_READY_OFFSET, 0);
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_TXREADY_OFFSET, 0);
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_RXREADY_OFFSET, 0);
+
+  /* Fill ACK buffer */
+
+  ackbuf[0] = IEEE802154_ACK_FRAME_SIZE;
+  ackbuf[1] = 0x02;
+  ackbuf[2] = 0;
+  ackbuf[3] = dev->radio->rxbuf[3];
+
+  /* Get RX frame type */
+
+  nrf52_radioi8_rx_parse(dev, &ftype, &cmdtype);
+
+  /* If this is ACK for Data Request command - set frame pending flag */
+
+  if (dev->state.devmode != NRF52_DEVMODE_ENDPOINT &&
+      ftype == IEEE802154_FRAME_COMMAND &&
+      cmdtype == IEEE802154_CMD_DATA_REQ)
+    {
+      pending = true;
+    }
+
+  /* Set frame pedning flag for this ACK */
+
+  if (pending)
+    {
+      ackbuf[1] |= 0x10;
+    }
+
+  /* Configure shorts and interrupts */
+
+  NRF52_RADIO_SHRTSET(lower, IEEE802154_ACKTX_SHORTS);
+  NRF52_RADIO_INTEN(lower, IEEE802154_ACKTX_INT);
+
+  /* Set packet pointer - buffer must be aligned */
+
+  regval = (uint32_t)ackbuf;
+  DEBUGASSERT(nrf52_easydma_valid(regval));
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_PACKETPTR_OFFSET, regval);
+
+  /* Set state to ACK */
+
+  dev->radio->state.state = NRF52_RADIO_STATE_ACKTX;
+
+  /* Enable TX - start TX is called from timer interrupt */
+
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_TXEN_OFFSET, 1);
+
+  /* Run TIMER - TX is handled in timer isr */
+
+  nrf52_radioi8_trace_put(RADIO_TRACE_ACKTX, pending);
+  dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_ACK, IEEE802154_ACKIFS_SYMBOLS);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_filter
+ *
+ * Description:
+ *   Filter received frames.
+ *
+ ****************************************************************************/
+
+static bool nrf52_radioi8_filter(struct nrf52_radioi8_dev_s *dev)
+{
+  struct ieee802154_addr_s  addr;
+  uint8_t                  *rx = &dev->radio->rxbuf[1];
+  uint16_t                 *fc = (uint16_t *)&rx[0];
+
+  /* Promiscuous mode */
+
+  if (dev->state.rxmode == NRF52_RXMODE_PROMISC)
+    {
+      return true;
+    }
+
+  /* Beacon frame */
+
+  if (((*fc & IEEE802154_FRAMECTRL_FTYPE) == IEEE802154_FRAME_BEACON) &&
+      IEEE802154_PANIDCMP(IEEE802154_PANID_UNSPEC, &dev->state.addr.panid))
+    {
+      return true;
+    }
+
+  /* Get destination address */
+
+  IEEE802154_PANIDCOPY(addr.panid, &rx[3]);
+  addr.mode = ((*fc & IEEE802154_FRAMECTRL_DADDR) >>
+               IEEE802154_FRAMECTRL_SHIFT_DADDR);
+  if (addr.mode == IEEE802154_ADDRMODE_SHORT)
+    {
+      IEEE802154_SADDRCOPY(addr.saddr, &rx[5]);
+    }
+  else if (addr.mode == IEEE802154_ADDRMODE_EXTENDED)
+    {
+      IEEE802154_EADDRCOPY(addr.eaddr, &rx[5]);
+    }
+
+  /* PAN ID match */
+
+  if (!IEEE802154_PANIDCMP(IEEE802154_PANID_UNSPEC, dev->state.addr.panid) &&
+      !IEEE802154_PANIDCMP(addr.panid, &dev->state.addr.panid))
+    {
+      return false;
+    }
+
+  /* Destination address match */
+
+  if (addr.mode == IEEE802154_ADDRMODE_SHORT)
+    {
+      if (IEEE802154_SADDRCMP(addr.saddr,
+                              &dev->state.addr.saddr))
+        {
+          return true;
+        }
+
+      else if (IEEE802154_SADDRCMP(addr.saddr,
+                                   IEEE802154_SADDR_UNSPEC))
+        {
+          return true;
+        }
+    }
+  else if (addr.mode == IEEE802154_ADDRMODE_EXTENDED)
+    {
+      if (IEEE802154_EADDRCMP(addr.eaddr,
+                              &dev->state.addr.eaddr))
+        {
+          return true;
+        }
+
+      else if (IEEE802154_EADDRCMP(addr.eaddr,
+                                   IEEE802154_EADDR_UNSPEC))
+        {
+          return true;
+        }
+    }
+
+  /* Otherwise drop this frame */
+
+  return false;
+}
+
+#if NRF52_GTS_SLOTS > 0
+/****************************************************************************
+ * Name: nrf52_radioi8_gts_setup
+ *
+ * Description:
+ *   Setup a GTS transaction.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_gts_setup(struct nrf52_radioi8_dev_s *dev,
+                                    uint8_t fifo, struct iob_s *frame)
+{
+  /* Missing logic */
+
+  ASSERT(0);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_dopoll_gts
+ *
+ * Description:
+ *   This function is called in order to perform an out-of-sequence TX poll.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_dopoll_gts(void *arg)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg;
+  int                         gts = 0;
+  int                         len = 0;
+
+  /* Get exclusive access to the driver */
+
+  while (nxmutex_lock(&dev->lock) < 0)
+    {
+    }
+
+  for (gts = 0; gts < NRF52_GTS_SLOTS; gts++)
+    {
+      if (!dev->state.gts_busy[gts])
+        {
+          len = dev->radiocb->poll(dev->radiocb, true,
+                                   &dev->state.gts_desc[gts]);
+
+          if (len > 0)
+            {
+              /* Now the txdesc is in use */
+
+              dev->state.gts_busy[gts] = 1;
+
+              /* Setup the GTS transaction */
+
+              nrf52_radioi8_gts_setup(dev, gts,
+                                      dev->state.gts_desc[gts]->frame);
+            }
+        }
+    }
+
+  nxmutex_unlock(&dev->lock);
+}
+#endif  /* NRF52_GTS_SLOTS > 0 */
+
+/****************************************************************************
+ * Name: nrf52_radioi8_txstart
+ *
+ * Description:
+ *   Start transmition, TX must be armed (TXEN must be set).
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_txstart(struct nrf52_radioi8_dev_s *dev)
+{
+  struct nrf52_radio_dev_s *lower = NULL;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_START_OFFSET, 1);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_ccastart
+ *
+ * Description:
+ *   Start CCA, RX must be armed (RXEN must be set).
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_ccastart(struct nrf52_radioi8_dev_s *dev)
+{
+  struct nrf52_radio_dev_s *lower = NULL;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_CCASTART_OFFSET, 1);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_notify_noack
+ *
+ * Description:
+ *   Notify Radio layer about noack event.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_notify_noack(struct nrf52_radioi8_dev_s *dev)
+{
+  /* If flag is set - no ACK was received */
+
+  if (dev->radio->state.waitack == true)
+    {
+      /* Notify MAC layer */
+
+      DEBUGASSERT(work_available(&dev->radio->noackwork));
+      work_queue(HPWORK, &dev->radio->noackwork,
+                 nrf52_radioi8_work_noack, (void *)dev, 0);
+
+      /* Clear flag */
+
+      dev->radio->state.waitack = false;
+    }
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rxenable
+ *
+ * Description:
+ *  Enable/Disable receiver.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_rxenable(struct nrf52_radioi8_dev_s *dev,
+                                  bool enable)
+{
+  struct nrf52_radio_dev_s *lower  = NULL;
+  uint32_t                  regval = 0;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  if (enable)
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_RXENABLE, 0);
+
+      /* Clear events */
+
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_END_OFFSET, 0);
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_READY_OFFSET, 0);
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_PHYEND_OFFSET, 0);
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_TXREADY_OFFSET, 0);
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_RXREADY_OFFSET, 0);
+
+      /* Configure shorts and interrupts */
+
+      NRF52_RADIO_SHRTSET(lower, IEEE802154_RX_SHORTS);
+      NRF52_RADIO_INTEN(lower, IEEE802154_RX_INT);
+
+      /* Set packet pointer - buffer must be aligned */
+
+      regval = (uint32_t)dev->radio->rxbuf;
+      DEBUGASSERT(nrf52_easydma_valid(regval));
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_PACKETPTR_OFFSET, regval);
+
+      /* Set state to RX */
+
+      dev->radio->state.state = NRF52_RADIO_STATE_RX;
+
+      /* Start RX */
+
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_RXEN_OFFSET, 1);
+    }
+  else
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_RXDISABLE, 0);
+
+      /* Disalbe interrups and shorts */
+
+      NRF52_RADIO_INTCLR(lower, IEEE802154_RX_INT);
+      NRF52_RADIO_SHRTSET(lower, 0);
+
+      /* Disable RX */
+
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_DISABLE_OFFSET, 1);
+    }
+
+  /* Store state */
+
+  dev->radio->state.rxenabled = enable;
+
+  /* Data returned by callback in ISR */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_energydetect
+ *
+ * Description:
+ *   Start the energy detect measurement.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_energydetect(struct nrf52_radioi8_dev_s *dev,
+                                      uint32_t nsymbols)
+{
+  struct nrf52_radio_dev_s *lower = NULL;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  /* Clear events */
+
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_EDEND_OFFSET, 0);
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_READY_OFFSET, 0);
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_RXREADY_OFFSET, 0);
+
+  /* Configure shortucts and interrupts */
+
+  NRF52_RADIO_SHRTSET(lower, IEEE802154_ED_SHORTS);
+  NRF52_RADIO_INTEN(lower, IEEE802154_ED_INT);
+
+  /* Configure ED symbols */
+
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EDCNT_OFFSET, nsymbols);
+
+  /* Set state to ENERGY_DETECT (ED) */
+
+  dev->radio->state.state = NRF52_RADIO_STATE_ED;
+
+  /* Start RX */
+
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_RXEN_OFFSET, 1);
+
+  /* Data returned by callback in ISR */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_setchannel
+ *
+ * Description:
+ *   Define the current radio channel the device is operating on.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_setchannel(struct nrf52_radioi8_dev_s *dev,
+                                   uint8_t chan)
+{
+  struct nrf52_radio_dev_s *lower = NULL;
+  uint32_t                  freq  = 2405 + 5 * (chan - 11);
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  return NRF52_RADIO_FREQSET(lower, freq);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_setcca
+ *
+ * Description:
+ *   Configure the Clear Channel Assessement.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_setcca(struct nrf52_radioi8_dev_s *dev,
+                                      struct ieee802154_cca_s *cca)
+{
+  struct nrf52_radio_dev_s *lower = NULL;
+  struct nrf52_radio_cca_s  c;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  /* Fill radio sturcture */
+
+  memset(&c, 0, sizeof(struct nrf52_radio_cca_s));
+
+  if (cca->use_ed && !cca->use_cs)
+    {
+      c.mode = NRF52_RADIO_CCA_ED;
+    }
+  else if (~cca->use_ed && cca->use_cs)
+    {
+      c.mode = NRF52_RADIO_CCA_CARRIER;
+    }
+  else if (cca->use_ed && cca->use_cs)
+    {
+      c.mode = NRF52_RADIO_CCA_CARRIER_AND_ED;
+    }
+
+  c.edthres   = cca->edth;
+  c.corrthres = cca->csth;
+  c.corrcnt   = 5;
+
+  /* Configure radio */
+
+  NRF52_RADIO_CCACFG(lower, &c);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_norm_setup_buf
+ *
+ * Description:
+ *   Setup a normal transaction (non GTS) from buffer.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_norm_setup_buf(struct nrf52_radioi8_dev_s *dev,
+                                         uint8_t *buf, bool csma)
+{
+  struct nrf52_radio_dev_s *lower  = NULL;
+  uint32_t                  regval = 0;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  nrf52_radioi8_trace_put(RADIO_TRACE_CSMASETUP, csma);
+
+  /* If RX is enabled - we have to temporarly disable it */
+
+  if (dev->radio->state.rxenabled)
+    {
+      dev->macops.rxenable((struct ieee802154_radio_s *)dev, false);
+
+      /* Restore RX after TX completed */
+
+      dev->radio->state.rxrestore = true;
+    }
+
+  /* Set packet pointer - buffer must be aligned */
+
+  regval = (uint32_t)buf;
+  DEBUGASSERT(nrf52_easydma_valid(regval));
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_PACKETPTR_OFFSET, regval);
+
+  if (csma)
+    {
+      /* Clear events */
+
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_END_OFFSET, 0);
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_READY_OFFSET, 0);
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_PHYEND_OFFSET, 0);
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_TXREADY_OFFSET, 0);
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_CCABUSY_OFFSET, 0);
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_CCAIDLE_OFFSET, 0);
+
+      /* Configure shorts and interrupts */
+
+      if (dev->radio->state.slotted)
+        {
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+          NRF52_RADIO_SHRTSET(lower, IEEE802154_TXCCASLT_SHORTS);
+          NRF52_RADIO_INTEN(lower, IEEE802154_TXCCASLT_INT);
+#else
+          ASSERT(0);
+#endif
+        }
+      else
+        {
+          NRF52_RADIO_SHRTSET(lower, IEEE802154_TXCCAUNSLT_SHORTS);
+          NRF52_RADIO_INTEN(lower, IEEE802154_TXCCAUNSLT_INT);
+        }
+
+      dev->radio->state.state = NRF52_RADIO_STATE_TX_CSMA;
+    }
+  else
+    {
+      /* Clear events */
+
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_END_OFFSET, 0);
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_READY_OFFSET, 0);
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_PHYEND_OFFSET, 0);
+
+      /* Configure shorts and interrupts */
+
+      NRF52_RADIO_SHRTSET(lower, IEEE802154_TX_SHORTS);
+      NRF52_RADIO_INTEN(lower, IEEE802154_TX_INT);
+      dev->radio->state.state = NRF52_RADIO_STATE_TX_NOCSMA;
+    }
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_norm_setup
+ *
+ * Description:
+ *   Setup a normal transaction (non GTS).
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_norm_setup(struct nrf52_radioi8_dev_s *dev,
+                                     struct iob_s *frame, bool csma)
+{
+  /* The first byte in TX buffer is PHR */
+
+  dev->radio->txbuf[0] = frame->io_len;
+
+  /* Allocate space for CRC */
+
+  dev->radio->txbuf[0] += 2;
+
+  /* Copy frame to RX buffer - we must send from aligned buffer */
+
+  memcpy(&dev->radio->txbuf[1], &frame->io_data[0], frame->io_len);
+
+  /* Setup buffer */
+
+  nrf52_radioi8_norm_setup_buf(dev, dev->radio->txbuf, csma);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_trg_csma
+ *
+ * Description:
+ *   Trigger transaction with CSMA-CA.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_trg_csma(struct nrf52_radioi8_dev_s *dev)
+{
+  uint32_t delay = 0;
+
+  /* Set state to TX */
+
+  dev->radio->state.state = NRF52_RADIO_STATE_TX;
+
+  /* Need slotted CSMA-CA */
+
+  if (dev->radio->state.slotted)
+    {
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+      if (!dev->radio->state.csma_busy)
+        {
+          /* Initial backoff state */
+
+          dev->radio->state.NB = 0;
+          dev->radio->state.CW = IEEE802154_CW0;
+        }
+
+      /* Battery life extension */
+
+      if (dev->radio->state.ble)
+        {
+          dev->radio->state.BE = MIN(2, dev->radio->state.min_be);
+        }
+      else
+        {
+          dev->radio->state.BE = dev->radio->state.min_be;
+        }
+
+      /* Get random unit backoff period delay */
+
+      delay = rand() % ((1 << dev->radio->state.BE) - 1);
+
+      /* TODO:
+       *  - locate backoff period boundary
+       *  - perform CCA on backoff period boundary
+       */
+
+      ASSERT(0);
+#else
+      ASSERT(0);
+#endif
+    }
+
+  /* Need un-slotted CSMA-CA */
+
+  else
+    {
+      if (!dev->radio->state.csma_busy)
+        {
+          /* Initial backoff state */
+
+          dev->radio->state.NB = 0;
+          dev->radio->state.BE = dev->radio->state.min_be;
+        }
+
+      /* Get random unit backoff period delay */
+
+      delay = rand() % ((1 << dev->radio->state.BE) - 1);
+    }
+
+  /* CSMA is in use */
+
+  dev->radio->state.csma_busy = true;
+  nrf52_radioi8_trace_put(RADIO_TRACE_CSMATRIGGER, delay);
+
+  dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_CSMADELAY,
+                       delay * IEEE802154_UNIT_BACKOFF_PERIOD);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_trg_nocsma
+ *
+ * Description:
+ *   Trigger transaction without CSMA-CA;
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_trg_nocsma(struct nrf52_radioi8_dev_s *dev)
+{
+  struct nrf52_radio_dev_s *lower = NULL;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  /* Set state to TX */
+
+  dev->radio->state.state = NRF52_RADIO_STATE_TX;
+
+  /* Start TX - we transmit immediately */
+
+  nrf52_radioi8_trace_put(RADIO_TRACE_NOCSMATRIGGER,
+                          dev->radio->state.state);
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_TXEN_OFFSET, 1);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_norm_trigger
+ *
+ * Description:
+ *   Trigger normal transaction (non GTS).
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_norm_trigger(struct nrf52_radioi8_dev_s *dev)
+{
+  /* Wait for ACK */
+
+  if (dev->radio->txbuf[1] & IEEE802154_FRAMECTRL_ACKREQ)
+    {
+      dev->radio->state.waitack = true;
+    }
+
+  /* CSMA transmition */
+
+  if (dev->radio->state.state == NRF52_RADIO_STATE_TX_CSMA)
+    {
+      nrf52_radioi8_trg_csma(dev);
+    }
+
+  /* No-CSMA transmition */
+
+  else if (dev->radio->state.state == NRF52_RADIO_STATE_TX_NOCSMA)
+    {
+      nrf52_radioi8_trg_nocsma(dev);
+    }
+
+  /* Invalid state */
+
+  else
+    {
+      /* We should not be there */
+
+      DEBUGASSERT(0);
+    }
+}
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+/****************************************************************************
+ * Name: nrf52_radioi8_beacon_setup
+ *
+ * Description:
+ *   Setup a beacon frame transfer
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_beacon_setup(struct nrf52_radioi8_dev_s *dev,
+                                       uint8_t *data, uint8_t len)
+{
+  /* Set beacon TX buffer */
+
+  memcpy(&dev->radio->beaconbuf[1], data, len);
+
+  /* Length = Frame data + CRC */
+
+  dev->radio->beaconbuf[0] = len + 2;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_beacon_tx
+ *
+ * Description:
+ *   Transmit a beacon frame (non CSMA-CA transfer).
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_beacon_tx(struct nrf52_radioi8_dev_s *dev)
+{
+  /* Beacon buffer is ready to send - transmit as non CSMA-CA */
+
+  nrf52_radioi8_norm_setup_buf(dev, dev->radio->beaconbuf, false);
+
+  /* Send now */
+
+  nrf52_radioi8_norm_trigger(dev);
+}
+#endif
+
+/****************************************************************************
+ * Name: nrf52_radioi8_reset
+ *
+ * Description:
+ *   Reset radio state to work with IEEE 802.15.4.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_reset(struct nrf52_radioi8_radio_s *dev)
+{
+  struct nrf52_radio_dev_s    *radio = NULL;
+  struct nrf52_radio_crc_s     crc;
+  struct nrf52_radio_pktcfg_s  pcfg;
+  int                          ret   = OK;
+
+  DEBUGASSERT(dev);
+  radio = dev->lower;
+
+  /* Reset radio state */
+
+  memset(&dev->state, 0, sizeof(struct nrf52_radioi8_radio_data_s));
+
+  /* Reset radio */
+
+  NRF52_RADIO_RESET(radio);
+
+  /* MAC prameters */
+
+  dev->state.max_frame_waittime = IEEE802154_MAX_FRAME_WAITTIME;
+  dev->state.max_csma_backoffs  = IEEE802154_MAX_CSMA_BACKOFFS;
+  dev->state.min_be             = IEEE802154_MIN_BE;
+  dev->state.max_be             = IEEE802154_MAX_BE;
+
+  /* Set radio IEEE 802.15.4 mode */
+
+  ret = NRF52_RADIO_MODESET(radio, NRF52_RADIO_MODE_IEEE802154);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  /* Configure CRC */
+
+  crc.len  = 2;
+  crc.skip = NRF52_RADIO_CRC_SKIPADDR_IEEE802154;
+  crc.poly = 0x011021;
+  crc.init = 0;
+
+  ret = NRF52_RADIO_CRCCFG(radio, &crc);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  /* Configure packet for IEEE 802.15.4 mode */
+
+  pcfg.max_len  = IEEE802154_MAX_PHY_PACKET_SIZE;
+  pcfg.stat_len = 0;
+  pcfg.bal_len  = 0;
+  pcfg.lf_len   = 8;
+  pcfg.s0_len   = 0;
+  pcfg.s1_len   = 0;
+  pcfg.ci_len   = 0;
+  pcfg.pl_len   = NRF52_RADIO_PREAMBLE_32BITZERO;
+  pcfg.term_len = 0;
+  pcfg.crcinc   = true;
+  pcfg.endian   = false;
+  pcfg.whiteen  = false;
+
+  ret = NRF52_RADIO_PKTCFG(radio, &pcfg);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  /* Disable hardware TIFS */
+
+  NRF52_RADIO_PUTREG(radio, NRF52_RADIO_MODECNF0_OFFSET,
+                     RADIO_MODECNF0_RU);
+
+  /* Set TX power */
+
+  NRF52_RADIO_TXPWRSET(radio, 0);
+
+  /* TODO: Configure LNA/PA */
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_dopoll_csma
+ *
+ * Description:
+ *   Out-of-sequence TX poll.
+ *
+ ****************************************************************************/
+
+void nrf52_radioi8_dopoll_csma(void *arg)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg;
+  int                         len = 0;
+
+  /* Get exclusive access to the driver */
+
+  while (nxmutex_lock(&dev->lock) < 0)
+    {
+    }
+
+  /* If this a CSMA transaction and we have room in the CSMA */
+
+  if (!dev->radio->state.csma_busy)
+    {
+      wlinfo("Polling for frame\n");
+      len = dev->radiocb->poll(dev->radiocb, false, &dev->state.csma_desc);
+
+      if (len > 0)
+        {
+          wlinfo("Frame received. Frame length: %d\n", len);
+
+          /* Setup the CSMA transaction */
+
+          dev->radio->ops->norm_setup(dev, dev->state.csma_desc->frame,
+                                      true);
+          dev->radio->ops->norm_trigger(dev);
+        }
+    }
+
+  nxmutex_unlock(&dev->lock);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_csmapoll
+ *
+ * Description:
+ *   Handle CSMA poll.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_csmapoll(struct nrf52_radioi8_dev_s *dev)
+{
+  /* Is our single work structure available?  It may not be if there are
+   * pending interrupt actions and we will have to ignore the Tx
+   * availability action.
+   */
+
+  if (work_available(&dev->radio->csma_pollwork))
+    {
+      /* Schedule to serialize the poll on the worker thread. */
+
+      work_queue(HPWORK, &dev->radio->csma_pollwork,
+                 nrf52_radioi8_dopoll_csma, dev, 0);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_gtspoll
+ *
+ * Description:
+ *   Handle GTS poll.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_gtspoll(struct nrf52_radioi8_dev_s *dev)
+{
+#if NRF52_GTS_SLOTS > 0
+  /* Is our single work structure available?  It may not be if there are
+   * pending interrupt actions and we will have to ignore the Tx
+   * availability action.
+   */
+
+  if (work_available(&dev->radio->gts_pollwork))
+    {
+      /* Schedule to serialize the poll on the worker thread. */
+
+      work_queue(HPWORK, &dev->radio->gts_pollwork,
+                 nrf52_radioi8_dopoll_gts, dev, 0);
+    }
+
+  return OK;
+#else
+  /* GTS not supported */
+
+  return -ENOTSUP;
+#endif
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_work_noack
+ *
+ * Description:
+ *   Handle no ACK work.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_work_noack(void *arg)
+{
+  struct nrf52_radioi8_dev_s *dev   = (struct nrf52_radioi8_dev_s *)arg;
+  struct nrf52_radio_dev_s   *lower = NULL;
+  struct ieee802154_txdesc_s *tx    = NULL;
+  bool                       *busy  = NULL;
+  bool                        csma  = false;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  nrf52_radioi8_trace_put(RADIO_TRACE_WORK_NOACK, 0);
+
+  /* Get exclusive access to the driver */
+
+  while (nxmutex_lock(&dev->lock) < 0)
+    {
+    }
+
+  if (dev->state.txdelayed_busy)
+    {
+      tx   = dev->state.txdelayed_desc;
+      busy = &dev->state.txdelayed_busy;
+      csma = false;
+    }
+  else
+    {
+      tx   = dev->state.csma_desc;
+      busy = &dev->radio->state.csma_busy;
+      csma = true;
+    }
+
+  if (tx->retrycount > 0)
+    {
+      /* Disable RX */
+
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_DISABLE_OFFSET, 1);
+
+      /* Try again */
+
+      tx->retrycount -= 1;
+      nrf52_radioi8_trace_put(RADIO_TRACE_TXRETRY, tx->retrycount);
+      nrf52_radioi8_norm_setup(dev, tx->frame, csma);
+      nrf52_radioi8_norm_trigger(dev);
+    }
+  else
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_NOACK, 0);
+
+      tx->conf->status = IEEE802154_STATUS_NO_ACK;
+      tx->framepending = false;
+      dev->radiocb->txdone(dev->radiocb, tx);
+      *busy = false;
+    }
+
+  /* Unlock the radio device */
+
+  nxmutex_unlock(&dev->lock);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_work_irq
+ *
+ * Description:
+ *   Handle RX work.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_work_rx(void *arg)
+{
+  struct nrf52_radioi8_dev_s    *dev   = (struct nrf52_radioi8_dev_s *)arg;
+  struct nrf52_radio_dev_s      *lower = NULL;
+  struct ieee802154_primitive_s *prim  = NULL;
+  struct ieee802154_data_ind_s  *ind   = NULL;
+  uint8_t                        index = 0;
+  bool                           crcok = false;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  nrf52_radioi8_trace_put(RADIO_TRACE_WORK_RX, 0);
+
+  /* Get exclusive access to the driver */
+
+  while (nxmutex_lock(&dev->lock) < 0)
+    {
+    }
+
+  /* Check CRC */
+
+  crcok = NRF52_RADIO_GETREG(lower, NRF52_RADIO_CRCSTATUS_OFFSET);
+  if (dev->state.rxmode != NRF52_RXMODE_NOCRC && crcok == false)
+    {
+      goto out;
+    }
+
+  /* Allocate a data_ind to put the frame in */
+
+  prim = ieee802154_primitive_allocate();
+  ind = (struct ieee802154_data_ind_s *)prim;
+  if (ind == NULL)
+    {
+      wlerr("ERROR: Unable to allocate data_ind. Discarding frame\n");
+      goto out;
+    }
+
+  prim->type = IEEE802154_PRIMITIVE_IND_DATA;
+
+  /* Allocate an IOB to put the frame into */
+
+  ind->frame = iob_alloc(false);
+  DEBUGASSERT(ind->frame != NULL);
+
+  /* First byte is the PHR */
+
+  ind->frame->io_len = dev->radio->rxbuf[0];
+
+  /* Reduce len by 2, we only receive frames with correct crc, no check
+   * required.
+   */
+
+  ind->frame->io_len -= 2;
+
+  for (index = 0; index < ind->frame->io_len; index++)
+    {
+      ind->frame->io_data[index] = dev->radio->rxbuf[index + 1];
+    }
+
+  /* Set CRC fields to 0 */
+
+  ind->frame->io_data[index + 1] = 0;
+  ind->frame->io_data[index + 2] = 0;
+
+  /* LQI is the last byte in RAM */
+
+  ind->lqi = dev->radio->rxbuf[index + 1];
+
+  /* RSSI is non-standard field and is not supported here.
+   * TODO: get RSSI from LQI ?
+   */
+
+  ind->rssi = 0;
+
+  /* Callback the receiver in the next highest layer */
+
+  dev->radiocb->rxframe(dev->radiocb, ind);
+
+out:
+
+  /* Re-Enable RX if not handling ACK TX now */
+
+  if (dev->radio->state.state != NRF52_RADIO_STATE_ACKTX)
+    {
+      /* Enable packet reception */
+
+      dev->macops.rxenable((struct ieee802154_radio_s *)dev, true);
+    }
+
+  /* Unlock the radio device */
+
+  nxmutex_unlock(&dev->lock);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_work_tx
+ *
+ * Description:
+ *   Handle TX work.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_work_tx(void *arg)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg;
+  enum ieee802154_status_e    status;
+  bool                        fpending = false;
+
+  nrf52_radioi8_trace_put(RADIO_TRACE_WORK_TX, 0);
+
+  /* Get exclusive access to the driver */
+
+  while (nxmutex_lock(&dev->lock) < 0)
+    {
+    }
+
+  /* Get frame pending flag from the last TX ACK */
+
+  fpending = dev->radio->state.framepending;
+  dev->radio->state.framepending = false;
+
+  status = IEEE802154_STATUS_SUCCESS;
+
+  if (dev->state.txdelayed_busy)
+    {
+      /* Inform the next layer of the transmission success/failure */
+
+      dev->state.txdelayed_desc->conf->status = status;
+      dev->state.txdelayed_desc->framepending = fpending;
+      dev->radiocb->txdone(dev->radiocb, dev->state.txdelayed_desc);
+      dev->state.txdelayed_desc = NULL;
+      dev->state.txdelayed_busy = false;
+    }
+  else
+    {
+      /* Inform the next layer of the transmission success/failure */
+
+      dev->state.csma_desc->conf->status = status;
+      dev->state.csma_desc->framepending = fpending;
+      dev->radiocb->txdone(dev->radiocb, dev->state.csma_desc);
+      dev->state.csma_desc = NULL;
+
+      /* We are now done with the transaction */
+
+      dev->radio->state.csma_busy = false;
+
+      /* Must unlock the radio before calling poll */
+
+      nxmutex_unlock(&dev->lock);
+      nrf52_radioi8_dopoll_csma(dev);
+      while (nxmutex_lock(&dev->lock) < 0)
+        {
+        }
+    }
+
+  /* Re-Enable RX if not handling ACK TX now */
+
+  if (dev->radio->state.state != NRF52_RADIO_STATE_ACKTX)
+    {
+      /* Enable packet reception */
+
+      dev->macops.rxenable((struct ieee802154_radio_s *)dev, true);
+    }
+
+  /* Unlock the radio device */
+
+  nxmutex_unlock(&dev->lock);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_work_busy
+ *
+ * Description:
+ *   Handle CCABUSY work.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_work_busy(void *arg)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg;
+
+  nrf52_radioi8_trace_put(RADIO_TRACE_WORK_BUSY, 0);
+
+  /* Get exclusive access to the driver */
+
+  while (nxmutex_lock(&dev->lock) < 0)
+    {
+    }
+
+  dev->state.txdelayed_desc->conf->status =
+    IEEE802154_STATUS_CHANNEL_ACCESS_FAILURE;
+
+  dev->radiocb->txdone(dev->radiocb, dev->state.txdelayed_desc);
+
+  /* Unlock the radio device */
+
+  nxmutex_unlock(&dev->lock);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_work_ed
+ *
+ * Description:
+ *   Handle ED work.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_work_ed(void *arg)
+{
+  struct nrf52_radioi8_dev_s *dev   = (struct nrf52_radioi8_dev_s *)arg;
+  struct nrf52_radio_dev_s   *lower = NULL;
+  int                         ed    = 0;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  nrf52_radioi8_trace_put(RADIO_TRACE_WORK_ED, 0);
+
+  /* Get result */
+
+  ed = NRF52_RADIO_GETREG(lower, NRF52_RADIO_EDSAMPLE_OFFSET);
+
+  /* Convert to IEEE 802.15.4 scale */
+
+  ed = ((ed > 63) ? 255: (ed * NRF52_ED_RSSISCALE));
+
+  /* Callback the receiver in the next highest layer */
+
+  dev->radiocb->edresult(dev->radiocb, ed);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_state_rx
+ *
+ * Description:
+ *   Handle radio interrupt for RX state.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_state_rx(struct nrf52_radioi8_dev_s *dev)
+{
+  uint8_t *rxbuf = dev->radio->rxbuf;
+
+  /* Frame filter */
+
+  if (dev->radio->state.waitack == false)
+    {
+      if (!nrf52_radioi8_filter(dev))
+        {
+          nrf52_radioi8_trace_put(RADIO_TRACE_DROPFRAME, 0);
+
+          /* Enable RX and ignore this frame */
+
+          dev->macops.rxenable((struct ieee802154_radio_s *)dev,
+                              true);
+          return;
+        }
+    }
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  /* TODO: resync with beacon ? */
+
+  if (dev->radio->state.wait_for_beacon == true)
+    {
+      uint16_t *fc = (uint16_t *)&rxbuf[0];
+
+      /* TODO: NOT TESTES, should we check panid here ? */
+
+      if (((*fc & IEEE802154_FRAMECTRL_FTYPE) == IEEE802154_FRAME_BEACON) &&
+          IEEE802154_PANIDCMP(IEEE802154_PANID_UNSPEC,
+                              &dev->state.addr.panid))
+        {
+          /* Start RTC */
+
+          dev->rtc->ops->start(dev);
+
+          dev->radio->state.wait_for_beacon = false;
+        }
+    }
+#endif
+
+  /* Start ACK handling now - this must be done in isr */
+
+  if (dev->state.rxmode == NRF52_RXMODE_NORMAL &&
+      rxbuf[1] & IEEE802154_FRAMECTRL_ACKREQ &&
+      rxbuf[0] != IEEE802154_ACK_FRAME_SIZE)
+    {
+      nrf52_radioi8_ack_transmit(dev);
+    }
+
+  /* Store RX frame long flag */
+
+  dev->radio->state.rxlong = rxbuf[0] > 18 ? true : false;
+
+  /* We don't wait for TX ACK - forward this frame to MAC */
+
+  if (dev->radio->state.waitack == false)
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RXDONE, 0);
+
+      /* Receive DONE */
+
+      if (work_available(&dev->radio->irqwork))
+        {
+          work_queue(HPWORK, &dev->radio->irqwork,
+                     nrf52_radioi8_work_rx, (void *)dev, 0);
+        }
+    }
+
+  /* We wait for TX ACK and this frame is ACK - confirm TX to MAC */
+
+  else if (rxbuf[0] == IEEE802154_ACK_FRAME_SIZE &&
+           dev->radio->state.waitack == true)
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RXACKDONE, 0);
+
+      /* ACK frame received */
+
+      dev->radio->state.waitack = false;
+
+      /* Get frame pedning flag */
+
+      dev->radio->state.framepending = rxbuf[1] & 0x10;
+
+      /* Clear timer */
+
+      dev->tim->ops->stop(dev);
+
+      /* This is ACK - notify MAC that TX complete */
+
+      if (work_available(&dev->radio->irqwork))
+        {
+          work_queue(HPWORK, &dev->radio->irqwork,
+                     nrf52_radioi8_work_tx, (void *)dev, 0);
+        }
+    }
+
+  /* We wait for TX ACK and this is not ACK - notify TX failure */
+
+  else
+    {
+      /* Clear flag */
+
+      dev->radio->state.waitack = false;
+
+      /* And notify MAC */
+
+      DEBUGASSERT(work_available(&dev->radio->noackwork));
+      work_queue(HPWORK, &dev->radio->noackwork,
+                 nrf52_radioi8_work_noack, (void *)dev, 0);
+    }
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_state_tx
+ *
+ * Description:
+ *   Handle radio interrupt for TX state.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_state_tx(struct nrf52_radioi8_dev_s *dev)
+{
+  struct nrf52_radio_dev_s *lower   = NULL;
+
+  DEBUGASSERT(dev);
+  lower = dev->radio->lower;
+
+  if (dev->radio->state.waitack == true)
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_WAITACK, 0);
+
+      /* Start timer and wait for ACK */
+
+      dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_WAITACK,
+                           IEEE802154_ACK_WAIT);
+    }
+  else
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TXDONE, 0);
+
+      /* Transmit DONE */
+
+      if (work_available(&dev->radio->irqwork))
+        {
+          work_queue(HPWORK, &dev->radio->irqwork,
+                     nrf52_radioi8_work_tx, (void *)dev, 0);
+        }
+    }
+
+  /* CCABUSY event for TX */
+
+  if (NRF52_RADIO_GETREG(lower, NRF52_RADIO_EVENTS_CCABUSY_OFFSET))
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TXCCABUSY, 0);
+
+      /* Clear event */
+
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_CCABUSY_OFFSET, 0);
+
+      /* Slotted CSMA-CA */
+
+      if (dev->radio->state.slotted == true)
+        {
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+          dev->radio->state.NB += 1;
+          dev->radio->state.CW = IEEE802154_CW0;
+          dev->radio->state.BE = MIN(2, dev->radio->state.min_be);
+
+          if (dev->radio->state.NB > dev->radio->state.max_csma_backoffs)
+            {
+              /* Return fauilure to MAC */
+
+              if (work_available(&dev->radio->irqwork))
+                {
+                  work_queue(HPWORK, &dev->radio->irqwork,
+                             nrf52_radioi8_work_busy, (void *)dev, 0);
+                }
+            }
+          else
+            {
+              /* Try again */
+
+              dev->radio->state.state = NRF52_RADIO_STATE_TX_CSMA;
+              nrf52_radioi8_norm_trigger(dev);
+
+              /* Do not restore RX */
+
+              return;
+            }
+#else
+          ASSERT(0);
+#endif
+        }
+
+      /* Un-slotted CSMA-CA */
+
+      else
+        {
+          /* Update backoff */
+
+          dev->radio->state.NB -= 1;
+          dev->radio->state.BE = MIN(dev->radio->state.BE + 1,
+                                     dev->radio->state.max_be);
+
+          if (dev->radio->state.NB > dev->radio->state.max_csma_backoffs)
+            {
+              /* Return fauilure to MAC */
+
+              if (work_available(&dev->radio->irqwork))
+                {
+                  work_queue(HPWORK, &dev->radio->irqwork,
+                             nrf52_radioi8_work_busy, (void *)dev, 0);
+                }
+            }
+          else
+            {
+              /* Try again */
+
+              dev->radio->state.state = NRF52_RADIO_STATE_TX_CSMA;
+              nrf52_radioi8_norm_trigger(dev);
+
+              /* Do not restore RX */
+
+              return;
+            }
+        }
+    }
+
+  /* CCAIDLE event for TX */
+
+  if (NRF52_RADIO_GETREG(lower, NRF52_RADIO_EVENTS_CCAIDLE_OFFSET))
+    {
+      /* Clear event */
+
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_CCAIDLE_OFFSET, 0);
+
+      /* Slotted CSMA-CA */
+
+      if (dev->radio->state.slotted == true)
+        {
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+          dev->radio->state.CW -= 1;
+
+          if (dev->radio->state.CW == 0)
+            {
+              /* Enable TX - short TXREADY-START is enabled */
+
+              NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_TXEN_OFFSET, 1);
+            }
+          else
+            {
+              /* Do not restore RX */
+
+              return;
+            }
+#else
+          ASSERT(0);
+#endif
+        }
+
+      /* Un-slotted CSMA-CA */
+
+      else
+        {
+          /* Nothing here */
+        }
+    }
+
+  /* Restore RX */
+
+  if (dev->radio->state.rxrestore | dev->radio->state.waitack)
+    {
+      dev->macops.rxenable((struct ieee802154_radio_s *)dev, true);
+      dev->radio->state.rxrestore = false;
+    }
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_state_acktx
+ *
+ * Description:
+ *   Handle radio interrupt for ACKTX state.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_state_acktx(struct nrf52_radioi8_dev_s *dev)
+{
+  nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_ACKTX, 0);
+
+  /* Handle pending TX */
+
+  if (dev->state.txdelayed_busy)
+    {
+      nrf52_radioi8_norm_setup(dev,
+                               dev->state.txdelayed_desc->frame,
+                               false);
+
+      /* Send with timer to keep IFS */
+
+      if (dev->radio->state.rxlong)
+        {
+          dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY,
+                               IEEE802154_LIFS_SYMBOLS);
+        }
+      else
+        {
+          dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY,
+                               IEEE802154_SIFS_SYMBOLS);
+        }
+    }
+
+  /* Restore RX */
+
+  else if (dev->radio->state.rxrestore)
+    {
+      dev->macops.rxenable((struct ieee802154_radio_s *)dev, true);
+      dev->radio->state.rxrestore = false;
+    }
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_state_ed
+ *
+ * Description:
+ *   Handle radio interrupt for ED state.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_state_ed(struct nrf52_radioi8_dev_s *dev)
+{
+  /* Energy detect DONE */
+
+  DEBUGASSERT(work_available(&dev->radio->irqwork));
+  work_queue(HPWORK, &dev->radio->irqwork,
+             nrf52_radioi8_work_ed, (void *)dev, 0);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_isr_radio
+ *
+ * Description:
+ *   Radio IEEE 802.15.4 interrupt handler.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_isr_radio(int irq, void *context, void *arg)
+{
+  struct nrf52_radioi8_dev_s *dev   = (struct nrf52_radioi8_dev_s *)arg;
+  struct nrf52_radio_dev_s   *lower = NULL;
+  irqstate_t                  flags;
+  uint8_t                     state;
+
+  DEBUGASSERT(dev != NULL);
+  lower = dev->radio->lower;
+
+  flags = enter_critical_section();
+
+  nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RADIO, 0);
+
+  /* Get state */
+
+  state = dev->radio->state.state;
+  dev->radio->state.state = NRF52_RADIO_STATE_DISABLED;
+
+  /* Always clear END and PHYEND events */
+
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_END_OFFSET, 0);
+  NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_PHYEND_OFFSET, 0);
+
+  /* Clear interrupts and shorts */
+
+  NRF52_RADIO_INTCLR(lower, 0xffffffff);
+  NRF52_RADIO_SHRTSET(lower, 0);
+
+  /* If by chance radio is not disabled - disable it now. This should be
+   * handled by SHORTS, but this not always work...
+   */
+
+  if (NRF52_RADIO_GETREG(lower, NRF52_RADIO_STATE_OFFSET)
+      != RADIO_STATE_DISABLED)
+    {
+      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_DISABLE_OFFSET, 1);
+
+      /* Don't wait for the DISABLED event, hopefully the radio will be
+       * disabled by the time we use it again. Max delay is TX->DSIABLED
+       * and takes 21us.
+       */
+    }
+
+  /* Handle IRQ depending on the current state */
+
+  switch (state)
+    {
+      case NRF52_RADIO_STATE_RX:
+        {
+          nrf52_radioi8_state_rx(dev);
+
+          break;
+        }
+
+      case NRF52_RADIO_STATE_TX:
+        {
+          nrf52_radioi8_state_tx(dev);
+
+          break;
+        }
+
+      case NRF52_RADIO_STATE_ACKTX:
+        {
+          nrf52_radioi8_state_acktx(dev);
+
+          break;
+        }
+
+      case NRF52_RADIO_STATE_ED:
+        {
+          /* Clear event */
+
+          NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_EDEND_OFFSET, 0);
+
+          nrf52_radioi8_state_ed(dev);
+
+          break;
+        }
+
+      default:
+        {
+          ASSERT(0);
+          break;
+        }
+    }
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_radioi8_radio_init
+ *
+ * Description:
+ *   Initialize RADIO for IEEE802154 operations.
+ *
+ ****************************************************************************/
+
+struct nrf52_radioi8_radio_s *
+nrf52_radioi8_radio_init(struct nrf52_radioi8_dev_s *dev,
+                         struct nrf52_radio_board_s *board)
+{
+  struct nrf52_radio_dev_s *radio = NULL;
+
+  /* Initialize lower-half radio */
+
+  radio = nrf52_radio_initialize(0, board);
+  if (radio == NULL)
+    {
+      wlerr("nrf52_radio_initialize failed %d\n", -errno);
+      return NULL;
+    }
+
+  /* Attach custom RADIO interrupt */
+
+  irq_attach(radio->irq, nrf52_radioi8_isr_radio, dev);
+  up_enable_irq(radio->irq);
+
+  /* Set interrupts priority */
+
+  up_prioritize_irq(radio->irq, 0);
+
+  /* Connect radioer */
+
+  memset(&g_radioi8_radio, 0, sizeof(struct nrf52_radioi8_radio_s));
+  g_radioi8_radio.ops   = &g_radioi8_radio_ops;
+  g_radioi8_radio.lower = radio;
+
+  /* Connect buffers */
+
+  g_radioi8_radio.rxbuf     = g_nrf52_radioi8_rxbuf;
+  g_radioi8_radio.txbuf     = g_nrf52_radioi8_txbuf;
+  g_radioi8_radio.ackbuf    = g_nrf52_radioi8_ackbuf;
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  g_radioi8_radio.beaconbuf = g_nrf52_radioi8_beaconbuf;
+#endif
+
+  return &g_radioi8_radio;
+}
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_radio.h b/arch/arm/src/nrf52/nrf52_ieee802154_radio.h
new file mode 100644
index 0000000000..8dd9146bd0
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_radio.h
@@ -0,0 +1,246 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_ieee802154_radio.h
+ *
+ * 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 __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RADIO_H
+#define __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RADIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/wqueue.h>
+
+#include "hardware/nrf52_radio.h"
+
+#include "nrf52_radio.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* IEEE 802.15.4 constants */
+
+#define IEEE802154_MAX_FRAME_WAITTIME (16 + 32 + 4064)
+#define IEEE802154_MAX_CSMA_BACKOFFS  (1)
+#define IEEE802154_MIN_BE             (3)
+#define IEEE802154_MAX_BE             (5)
+#define IEEE802154_CW0                (2)
+
+/* ACK_SYM + turnaround symbols + backoff */
+
+#define IEEE802154_ACK_WAIT           (12+                              \
+                                       IEEE802154_TURN_AROUND_TIME+     \
+                                       IEEE802154_UNIT_BACKOFF_PERIOD)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Radio state */
+
+enum nrf52_radioi8_state_e
+{
+  NRF52_RADIO_STATE_DISABLED  = 0, /* Radio disabled */
+  NRF52_RADIO_STATE_TX_CSMA,       /* CSMA TX armed */
+  NRF52_RADIO_STATE_TX_NOCSMA,     /* Non CSMA TX armed */
+  NRF52_RADIO_STATE_TX,            /* TX on the air */
+  NRF52_RADIO_STATE_RX,            /* RX active */
+  NRF52_RADIO_STATE_ACKTX,         /* Transmiting ACK now */
+  NRF52_RADIO_STATE_ED,            /* Energy detection now */
+};
+
+/* Radio data */
+
+struct nrf52_radioi8_radio_data_s
+{
+  /* Radio state */
+
+  uint8_t  state;
+
+  /* CSMA-CA */
+
+  uint8_t  NB;                  /* Number of required back offs */
+  uint8_t  CW;                  /* Contention window length */
+  uint8_t  BE;                  /* Backoff exponent */
+
+  /* RX state */
+
+  bool     rxenabled;           /* RX enabled now */
+  bool     rxrestore;           /* RX needs to be restored */
+  bool     rxlong;              /* Last RX frame was long */
+
+  /* TX state */
+
+  bool     waitack;             /* TX needs ACK */
+  bool     framepending;        /* Frame pending from the last TX ACK */
+  bool     csma_busy;           /* Un-slotted CSMA busy */
+  bool     slotted;             /* Slotted CSMA-CA */
+
+  /* Radio configuration */
+
+  uint32_t max_frame_waittime;  /* Max Frame wait time */
+  uint8_t  max_csma_backoffs;   /* Max CSMA backoffs */
+  uint8_t  min_be;              /* Min backoff exponent (BE) */
+  uint8_t  max_be;              /* Max backoff exponent (BE) */
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  /* Superframe data */
+
+  bool    wait_for_beacon;      /* Device wait for beacon */
+  bool    ble;                  /* Batter life extension */
+#endif
+};
+
+/* Forward reference */
+
+struct nrf52_radioi8_radio_s;
+struct ieee802154_radio_s;
+struct nrf52_radioi8_dev_s;
+struct ieee802154_cca_s;
+
+/* Radio ops */
+
+struct nrf52_radioi8_radio_ops_s
+{
+  /* Start transmition - TX must be armed (TXEN set) */
+
+  void (*txstart)(struct nrf52_radioi8_dev_s *dev);
+
+  /* Start CCA - RX must be armed (RXEN set) */
+
+  void (*ccastart)(struct nrf52_radioi8_dev_s *dev);
+
+  /* Notify MAC about no ACK */
+
+  void (*notify_noack)(struct nrf52_radioi8_dev_s *dev);
+
+  /* Enable/Disable receiver */
+
+  int (*rxenable)(struct nrf52_radioi8_dev_s *dev, bool enable);
+
+  /* Start the energy detect measurement */
+
+  int (*energydetect)(struct nrf52_radioi8_dev_s *dev, uint32_t nsymbols);
+
+  /* Define the current radio channel the device is operating on */
+
+  int (*setchannel)(struct nrf52_radioi8_dev_s *dev, uint8_t chan);
+
+  /* Configure the Clear Channel Assessement */
+
+  int (*setcca)(struct nrf52_radioi8_dev_s *dev,
+                struct ieee802154_cca_s *cca);
+
+  /* Setup a normal transaction (non GTS) */
+
+  void (*norm_setup)(struct nrf52_radioi8_dev_s *dev,
+                     struct iob_s *frame, bool csma);
+
+  /* Trigger normal transaction (non GTS) */
+
+  void (*norm_trigger)(struct nrf52_radioi8_dev_s *dev);
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  /* Setup a beacon frame transfe */
+
+  void (*beacon_setup)(struct nrf52_radioi8_dev_s *dev,
+                       uint8_t *data, uint8_t len);
+
+  /* Transmit a beacon frame (non CSMA-CA transfer) */
+
+  void (*beacon_tx)(struct nrf52_radioi8_dev_s *dev);
+#endif
+
+  /* Reset radio state to work with IEEE 802.15.4 */
+
+  int (*reset)(struct nrf52_radioi8_radio_s *dev);
+
+  /* Handle TX poll (no GTS) */
+
+  int (*csma_poll)(struct nrf52_radioi8_dev_s *dev);
+
+  /* Handle GTS poll */
+
+  int (*gts_poll)(struct nrf52_radioi8_dev_s *dev);
+};
+
+/* Radio interface */
+
+struct nrf52_radioi8_radio_s
+{
+  /* Radio lower-half */
+
+  struct nrf52_radio_dev_s *lower;
+
+  /* IEEE 802.15.4 radio operations */
+
+  struct nrf52_radioi8_radio_ops_s *ops;
+
+  /* Packet buffers */
+
+  uint8_t *rxbuf;
+  uint8_t *txbuf;
+  uint8_t *ackbuf;
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  uint8_t *beaconbuf;
+#endif
+
+  /* For deferring interrupts work */
+
+  struct work_s irqwork;
+
+  /* For deferring no ACK work */
+
+  struct work_s noackwork;
+
+  /* For deferring poll work to the work queue */
+
+  struct work_s csma_pollwork;
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  /* For deferring poll work to the work queue */
+
+  struct work_s gts_pollwork;
+#endif
+
+  /* Radio data */
+
+  struct nrf52_radioi8_radio_data_s state;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_radioi8_radio_init
+ *
+ * Description:
+ *   Initialize RADIO for IEEE802154 operations.
+ *
+ ****************************************************************************/
+
+struct nrf52_radioi8_radio_s *
+nrf52_radioi8_radio_init(struct nrf52_radioi8_dev_s *dev,
+                         struct nrf52_radio_board_s *board);
+
+#endif  /* __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RADIO_H */
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_rtc.c b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.c
new file mode 100644
index 0000000000..7d32b3df78
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.c
@@ -0,0 +1,392 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_ieee802154_rtc.c
+ *
+ * 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 <nuttx/config.h>
+
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wqueue.h>
+
+#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
+
+#include "nrf52_ieee802154_rtc.h"
+#include "nrf52_ieee802154_trace.h"
+
+#include "nrf52_ieee802154_priv.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+#  warning Beacon and superframe support work in progress
+#endif
+
+#ifndef CONFIG_NRF52_RTC0
+#  error CONFIG_NRF52_RTC0 is needed to handle radio timings
+#endif
+
+/* RTC instance - 0 */
+
+#define NRF52_IEEE802154_RTC0   (0)
+
+/* RTC prescaler set to 0, freq = 32.768kHz, resolution = 30.517 us */
+
+#define NRF52_RTC_PRESCALER     (0)
+#define NRF52_RTC_FREQUENCY     (32768)
+
+#define NRF52_RTC_RESOLUTION_NS (30517)
+
+/* 31 * 30.517us = 946.027us */
+
+#define NRF52_RTC_TIMESLOT_CC   (31)
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* RTC ops */
+
+static int nrf52_radioi8_rtc(struct nrf52_radioi8_dev_s *dev,
+                             struct ieee802154_superframespec_s *sfspec);
+static int nrf52_radioi8_rtc_start(struct nrf52_radioi8_dev_s *dev);
+static int nrf52_radioi8_rtc_stop(struct nrf52_radioi8_dev_s *dev);
+static void nrf52_radioi8_rtc_reset(struct nrf52_radioi8_dev_s *dev);
+
+/* Interrupts logic */
+
+static void nrf52_radioi8_work_inactive(void *arg);
+static int nrf52_radioi8_isr_rtc(int irq, void *context, void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* RTC ops */
+
+static struct nrf52_radioi8_rtc_ops_s g_radioi8_rtc_ops =
+{
+  .setup = nrf52_radioi8_rtc,
+  .start = nrf52_radioi8_rtc_start,
+  .stop  = nrf52_radioi8_rtc_stop,
+  .reset = nrf52_radioi8_rtc_reset
+};
+
+/* RTC instance */
+
+static struct nrf52_radioi8_rtc_s g_radioi8_rtc;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc
+ *
+ * Description:
+ *   Configure RTC events according to superframe spec.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_rtc(struct nrf52_radioi8_dev_s *dev,
+                             struct ieee802154_superframespec_s *sfspec)
+{
+  uint32_t   bi     = 0;
+  uint32_t   sd     = 0;
+  uint32_t   cap    = 0;
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  /* Stop RTC and clear the counter */
+
+  NRF52_RTC_STOP(dev->rtc->rtc);
+  NRF52_RTC_CLEAR(dev->rtc->rtc);
+
+  /* Initialize BI counter */
+
+  bi = ((IEEE802154_BASE_SUPERFRAME_DURATION *
+        (2 << sfspec->beaconorder) *
+         IEEE802154_SYMBOL_US * 1000)  /
+        NRF52_RTC_RESOLUTION_NS);
+  NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_BI, bi);
+
+  /* Initialize SD counter */
+
+  sd = ((IEEE802154_BASE_SUPERFRAME_DURATION *
+         (2 << sfspec->sforder) *
+         IEEE802154_SYMBOL_US * 1000) /
+        NRF52_RTC_RESOLUTION_NS);
+  NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_SD, sd);
+
+  /* Initialize CAP counter */
+
+  cap = ((sfspec->final_capslot *
+          IEEE802154_TIMESLOT_US * 1000) /
+         NRF52_RTC_RESOLUTION_NS);
+  NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_CAP, cap);
+
+  /* Initialize timeslot counter */
+
+  dev->rtc->rtc_timeslot = NRF52_RTC_TIMESLOT_CC;
+  NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_TIMESLOT, dev->rtc->rtc_timeslot);
+
+  /* Configure interupts */
+
+  NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_BI);
+  NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_SD);
+  NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_CAP);
+  NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_TIMESLOT);
+
+  /* Configure events */
+
+  NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_BI);
+  NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_SD);
+  NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_CAP);
+  NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_TIMESLOT);
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc_start
+ *
+ * Description:
+ *   Start RTC.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_rtc_start(struct nrf52_radioi8_dev_s *dev)
+{
+  NRF52_RTC_START(dev->rtc->rtc);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc_stop
+ *
+ * Description:
+ *   Stop RTC.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_rtc_stop(struct nrf52_radioi8_dev_s *dev)
+{
+  NRF52_RTC_STOP(dev->rtc->rtc);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc_reset
+ *
+ * Description:
+ *   Reset RTC.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_rtc_reset(struct nrf52_radioi8_dev_s *dev)
+{
+  /* Configure RTC - freq = 32.768 kHz */
+
+  NRF52_RTC_STOP(dev->rtc->rtc);
+  NRF52_RTC_SETPRE(dev->rtc->rtc, NRF52_RTC_PRESCALER);
+
+  /* Reset data */
+
+  dev->rtc->rtc_timeslot = 0;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_work_inactive
+ *
+ * Description:
+ *   Work when we enter inactive state.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_work_inactive(void *arg)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg;
+  enum ieee802154_sfevent_e   sfevent;
+
+  /* Notify MAC */
+
+  sfevent = IEEE802154_SFEVENT_ENDOFACTIVE;
+  dev->radiocb->sfevent(dev->radiocb, sfevent);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_isr_rtc
+ *
+ * Description:
+ *   Helper RTC0 interrupt handler.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_isr_rtc(int irq, void *context, void *arg)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg;
+  struct nrf52_radioi8_rtc_s *rtc = NULL;
+  irqstate_t                  flags;
+
+  DEBUGASSERT(dev != NULL);
+  rtc = dev->rtc;
+
+  flags = enter_critical_section();
+
+  /* End of CAP */
+
+  if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_CAP))
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCCAP, 0);
+
+      /* TODO */
+
+      /* Clear event */
+
+      NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_CAP);
+    }
+
+  /* End of active portion */
+
+  else if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_SD))
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCSD, 0);
+
+      /* Schedule work */
+
+      DEBUGASSERT(work_available(&dev->rtc->inactive_work));
+      work_queue(HPWORK, &dev->rtc->inactive_work,
+                 nrf52_radioi8_work_inactive, dev, 0);
+
+      /* Reset timeslot */
+
+      rtc->rtc_timeslot = NRF52_RTC_TIMESLOT_CC;
+
+      /* Clear event */
+
+      NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_SD);
+    }
+
+  /* Beacon interval */
+
+  else if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_BI))
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCBI, 0);
+
+      /* Transmit beacon if we are not endpoint */
+
+      if (dev->state.devmode != NRF52_DEVMODE_ENDPOINT)
+        {
+          /* Transmit data from beaconbuf */
+
+          dev->radio->ops->beacon_tx(dev);
+        }
+
+      /* Clear event */
+
+      NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_BI);
+
+      /* Next cycle */
+
+      NRF52_RTC_TRGOVRFLW(rtc->rtc);
+
+      /* TODO: resync with beacon ? */
+    }
+
+  /* Timeslot in active portion */
+
+  if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_TIMESLOT))
+    {
+      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCTIMESLOT, 0);
+
+      /* TODO: how to sync transmition with timeslot ?
+       *       do we need count every timeslot here ?
+       *       or wait for the timeslot we are interested in ?
+       *       or just use txdelay ?
+       */
+
+      /* Update timeslot */
+
+      rtc->rtc_timeslot += NRF52_RTC_TIMESLOT_CC;
+      NRF52_RTC_SETCC(rtc->rtc, NRF52_RTC_TIMESLOT, rtc->rtc_timeslot);
+
+      /* Clear event */
+
+      NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_TIMESLOT);
+    }
+
+    leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc_init
+ *
+ * Description:
+ *   Initialize low resoluton, low power timer for IEEE802154 operations.
+ *   Used to handle superframe timings.
+ *
+ ****************************************************************************/
+
+struct nrf52_radioi8_rtc_s *
+nrf52_radioi8_rtc_init(struct nrf52_radioi8_dev_s *dev)
+{
+  struct nrf52_rtc_dev_s *rtc = NULL;
+
+  /* Reserve RTC0 */
+
+  rtc = nrf52_rtc_init(NRF52_IEEE802154_RTC0);
+  if (rtc == NULL)
+    {
+      wlerr("nrf52_rtc_init(0) failed %d\n", -errno);
+      return NULL;
+    }
+
+  /* Atach RTC interrupt */
+
+  NRF52_RTC_SETISR(rtc, nrf52_radioi8_isr_rtc, dev);
+
+  /* Set interrupts priority */
+
+  up_prioritize_irq(NRF52_IRQ_RTC0, 0);
+
+  /* Connect RTC */
+
+  memset(&g_radioi8_rtc, 0, sizeof(struct nrf52_radioi8_rtc_s));
+  g_radioi8_rtc.ops = &g_radioi8_rtc_ops;
+  g_radioi8_rtc.rtc = rtc;
+
+  return &g_radioi8_rtc;
+}
diff --git a/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.h
similarity index 53%
copy from boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
copy to arch/arm/src/nrf52/nrf52_ieee802154_rtc.h
index e2f688fb5a..de6f475ff2 100644
--- a/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
+ * arch/arm/src/nrf52/nrf52_ieee802154_rtc.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,69 +18,99 @@
  *
  ****************************************************************************/
 
-#ifndef __BOARDS_ARM_NRF52_NRF52840_DONGLE_SRC_NRF52840_DONGLE_H
-#define __BOARDS_ARM_NRF52_NRF52840_DONGLE_SRC_NRF52840_DONGLE_H
+#ifndef __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RTC_H
+#define __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RTC_H
 
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
-#include <nuttx/compiler.h>
 
-#include "nrf52_gpio.h"
+#include "nrf52_rtc.h"
 
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
-/* LED definitions **********************************************************/
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
 
-/* Definitions to configure LED GPIO as outputs */
+/* RTC events */
 
-#define GPIO_LED1  (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT0 | GPIO_PIN(6))
+enum nrf52_ieee802154_rtc_e
+{
+  NRF52_RTC_BI       = 0,       /* Beacon Interval interval (BI) */
+  NRF52_RTC_TIMESLOT = 1,       /* Time slot */
+  NRF52_RTC_CAP      = 2,       /* Contention Access Period (CAP) */
+  NRF52_RTC_SD       = 3        /* Super Frame Duration (SD) */
+};
 
-/* RGB LED - LD2:
- *   RGB_RED   - P0-8
- *   RGB_GREEN - P1-9
- *   RGB_BLUE  - P0-12
- */
+/* Forward reference */
 
-/* Button definitions *******************************************************/
+struct nrf52_radioi8_rtc_s;
+struct nrf52_radioi8_dev_s;
 
-/* Board supports four buttons. */
+/* RTC ops  */
 
-#define GPIO_BUTTON1 (GPIO_INPUT | GPIO_PULLUP | GPIO_PORT1 | GPIO_PIN(6))
+struct nrf52_radioi8_rtc_ops_s
+{
+  /* Configure RTC events according to superframe spec */
 
-/****************************************************************************
- * Public Types
- ****************************************************************************/
+  int (*setup)(struct nrf52_radioi8_dev_s *dev,
+               struct ieee802154_superframespec_s *sfspec);
 
-/****************************************************************************
- * Public Data
- ****************************************************************************/
+  /* Start RTC */
+
+  int (*start)(struct nrf52_radioi8_dev_s *dev);
+
+  /* Stop RTC */
+
+  int (*stop)(struct nrf52_radioi8_dev_s *dev);
+
+  /* Reset RTC */
 
-#ifndef __ASSEMBLY__
+  void (*reset)(struct nrf52_radioi8_dev_s *dev);
+};
+
+/* RTC interface */
+
+struct nrf52_radioi8_rtc_s
+{
+  /* RTC lower-half */
+
+  struct nrf52_rtc_dev_s *rtc;
+
+  /* IEEE 802.15.4 RTC operations */
+
+  struct nrf52_radioi8_rtc_ops_s *ops;
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+  /* For deferring inactive state work to the work queue */
+
+  struct work_s inactive_work;
+
+  /* RTC state */
+
+  uint32_t rtc_timeslot;
+#endif
+};
 
 /****************************************************************************
- * Public Functions Prototypes
+ * Public Function Prototypes
  ****************************************************************************/
 
 /****************************************************************************
- * Name: nrf52_bringup
+ * Name: nrf52_radioi8_rtc_init
  *
  * Description:
- *   Perform architecture-specific initialization
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=y :
- *     Called from board_late_initialize().
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y :
- *     Called from the NSH library
+ *   Initialize low resoluton, low power timer for IEEE802154 operations.
+ *   Used to handle superframe timings.
  *
  ****************************************************************************/
 
-int nrf52_bringup(void);
+struct nrf52_radioi8_rtc_s *
+nrf52_radioi8_rtc_init(struct nrf52_radioi8_dev_s *dev);
 
-#endif /* __ASSEMBLY__ */
-#endif /* __BOARDS_ARM_NRF52_NRF52840_DONGLE_SRC_NRF52840_DONGLE_H */
+#endif  /* __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RTC_H */
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_tim.c b/arch/arm/src/nrf52/nrf52_ieee802154_tim.c
new file mode 100644
index 0000000000..7e8dd5749c
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_tim.c
@@ -0,0 +1,347 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_ieee802154_tim.c
+ *
+ * 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 <nuttx/config.h>
+
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wqueue.h>
+
+#include "nrf52_ieee802154_tim.h"
+#include "nrf52_ieee802154_trace.h"
+
+#include "nrf52_ieee802154_priv.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_NRF52_TIMER0
+#  error CONFIG_NRF52_TIMER0 is needed to handle radio timings
+#endif
+
+/* Timer instance - 0 */
+
+#define NRF52_IEEE802154_TIMER0 (0)
+
+/* Timer period set to 16us (symbol duration) */
+
+#define NRF52_TIMER_FREQUENCY   (1000000 / 16)
+
+/* 16MHz / (2 ** 8) =  62500 */
+
+#define NRF52_TIMER_PRESCALER   (8)
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* RTC ops */
+
+static int nrf52_radioi8_tim(struct nrf52_radioi8_dev_s *dev, uint8_t chan,
+                             uint32_t val);
+static void nrf52_radioi8_tim_stop(struct nrf52_radioi8_dev_s *dev);
+static void nrf52_radioi8_tim_reset(struct nrf52_radioi8_dev_s *dev);
+
+/* Interrupts logic */
+
+static int nrf52_radioi8_isr_tim(int irq, void *context, void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Timer ops */
+
+static struct nrf52_radioi8_tim_ops_s g_radioi8_tim_ops =
+{
+  .setup = nrf52_radioi8_tim,
+  .stop  = nrf52_radioi8_tim_stop,
+  .reset = nrf52_radioi8_tim_reset
+};
+
+/* Timer instance */
+
+static struct nrf52_radioi8_tim_s g_radioi8_tim;
+
+/****************************************************************************
+ * Private Function
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_radioi8_tim
+ *
+ * Description:
+ *   Configure TIMER event.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_tim(struct nrf52_radioi8_dev_s *dev, uint8_t chan,
+                             uint32_t val)
+{
+  struct nrf52_radioi8_tim_s *tim = NULL;
+  irqstate_t                  flags;
+
+  DEBUGASSERT(dev != NULL);
+  tim = dev->tim;
+
+  flags = enter_critical_section();
+
+  if (tim->tim_pending == true)
+    {
+      wlerr("TIMER busy! drop %" PRId8 " %" PRId32 " request\n", chan, val);
+      ASSERT(0);
+      return -EBUSY;
+    }
+
+  /* Stop timer and clear the counter */
+
+  NRF52_TIM_STOP(tim->tim);
+  NRF52_TIM_CLEAR(tim->tim);
+
+  /* Clear the previous event */
+
+  NRF52_TIM_ACKINT(tim->tim, chan);
+
+  /* Set compare register */
+
+  NRF52_TIM_SETCC(tim->tim, chan, val);
+
+  /* Configure interupt */
+
+  NRF52_TIM_ENABLEINT(tim->tim, chan);
+
+  /* Set TIMER pending flag and used channel */
+
+  tim->tim_pending = true;
+  tim->tim_now     = chan;
+
+  /* Start timer */
+
+  nrf52_radioi8_trace_put(RADIO_TRACE_TIMSTART, chan);
+
+  if (val > 0)
+    {
+      NRF52_TIM_START(tim->tim);
+    }
+  else
+    {
+      /* Call handler now */
+
+      nrf52_radioi8_isr_tim(0, NULL, dev);
+    }
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_tim_stop
+ *
+ * Description:
+ *   Stop timer.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_tim_stop(struct nrf52_radioi8_dev_s *dev)
+{
+  NRF52_TIM_STOP(dev->tim->tim);
+  NRF52_TIM_DISABLEINT(dev->tim->tim, dev->tim->tim_now);
+
+  /* Reset state */
+
+  dev->tim->tim_pending = false;
+  dev->tim->tim_now     = -1;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_tim_reset
+ *
+ * Description:
+ *   Reset TIMER.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_tim_reset(struct nrf52_radioi8_dev_s *dev)
+{
+  /* Configure TIMER - freq = 62500 */
+
+  NRF52_TIM_STOP(dev->tim->tim);
+  NRF52_TIM_CONFIGURE(dev->tim->tim, NRF52_TIM_MODE_TIMER,
+                      NRF52_TIM_WIDTH_32B);
+  NRF52_TIM_SETPRE(dev->tim->tim, NRF52_TIMER_PRESCALER);
+
+  /* Reset state */
+
+  dev->tim->tim_pending = false;
+  dev->tim->tim_now     = -1;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_isr_tim
+ *
+ * Description:
+ *   Helper tim interrupt handler.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_isr_tim(int irq, void *context, void *arg)
+{
+  struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg;
+  struct nrf52_radioi8_tim_s *tim = NULL;
+  irqstate_t                  flags;
+
+  DEBUGASSERT(dev != NULL);
+  tim = dev->tim;
+
+  flags = enter_critical_section();
+
+  switch (tim->tim_now)
+    {
+      /* RX ACK handler */
+
+      case NRF52_TIMER_CHAN_ACK:
+        {
+          nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TIMACKTX, 0);
+
+          /* Start TX */
+
+          dev->radio->ops->txstart(dev);
+
+          break;
+        }
+
+      /* Delayed TX handler */
+
+      case NRF52_TIMER_CHAN_TXDELAY:
+        {
+          nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TIMTXDELAY, 0);
+
+          /* Trigger TX */
+
+          dev->radio->ops->norm_trigger(dev);
+
+          break;
+        }
+
+      /* ACK wait handler */
+
+      case NRF52_TIMER_CHAN_WAITACK:
+        {
+          nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TIMWAITACK, 0);
+
+          /* Notify radio layer */
+
+          dev->radio->ops->notify_noack(dev);
+
+          break;
+        }
+
+      case NRF52_TIMER_CHAN_CSMADELAY:
+        {
+          nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TIMCSMADELAY, 0);
+
+          /* Start CCA - we transmit immediately after the CCA procedure ends
+           * (CCAIDLE_TXEN short), or CCABUSY interrupt happen.
+           */
+
+          dev->radio->ops->ccastart(dev);
+
+          break;
+        }
+
+      default:
+        {
+          ASSERT(0);
+          break;
+        }
+    }
+
+  /* Stop timer */
+
+  NRF52_TIM_STOP(tim->tim);
+
+  /* Disable and clear interrupts */
+
+  NRF52_TIM_DISABLEINT(tim->tim, tim->tim_now);
+  NRF52_TIM_ACKINT(tim->tim, tim->tim_now);
+
+  /* Clear TIMER pending flag and used channel */
+
+  tim->tim_pending = false;
+  tim->tim_now     = -1;
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_radioi8_tim_init
+ *
+ * Description:
+ *   Initialize high resoluton timer for IEEE802154 operations.
+ *   Used to handle short radio timeouts like ACK, IFS or delayed
+ *   transmitions.
+ *
+ ****************************************************************************/
+
+struct nrf52_radioi8_tim_s *
+nrf52_radioi8_tim_init(struct nrf52_radioi8_dev_s *dev)
+{
+  struct nrf52_tim_dev_s *tim = NULL;
+
+  /* Reserve TIMER0 */
+
+  tim = nrf52_tim_init(NRF52_IEEE802154_TIMER0);
+  if (tim == NULL)
+    {
+      wlerr("nrf52_tim_init(0) failed %d\n", -errno);
+      return NULL;
+    }
+
+  /* Atach TIMER interrupt */
+
+  NRF52_TIM_SETISR(tim, nrf52_radioi8_isr_tim, dev);
+
+  /* Set interrupts priority */
+
+  up_prioritize_irq(NRF52_IRQ_TIMER0, 0);
+
+  /* Connect timer */
+
+  memset(&g_radioi8_tim, 0, sizeof(struct nrf52_radioi8_tim_s));
+  g_radioi8_tim.ops = &g_radioi8_tim_ops;
+  g_radioi8_tim.tim = tim;
+
+  return &g_radioi8_tim;
+}
diff --git a/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h b/arch/arm/src/nrf52/nrf52_ieee802154_tim.h
similarity index 56%
copy from boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
copy to arch/arm/src/nrf52/nrf52_ieee802154_tim.h
index e2f688fb5a..0821353475 100644
--- a/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_tim.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
+ * arch/arm/src/nrf52/nrf52_ieee802154_tim.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,69 +18,88 @@
  *
  ****************************************************************************/
 
-#ifndef __BOARDS_ARM_NRF52_NRF52840_DONGLE_SRC_NRF52840_DONGLE_H
-#define __BOARDS_ARM_NRF52_NRF52840_DONGLE_SRC_NRF52840_DONGLE_H
+#ifndef __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TIM_H
+#define __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TIM_H
 
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
-#include <nuttx/compiler.h>
 
-#include "nrf52_gpio.h"
+#include "nrf52_tim.h"
 
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
-/* LED definitions **********************************************************/
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
 
-/* Definitions to configure LED GPIO as outputs */
+enum nrf52_ieee802154_timer_e
+{
+  NRF52_TIMER_CHAN_ACK       = 0, /* Handle ACK time */
+  NRF52_TIMER_CHAN_TXDELAY   = 1, /* Handle TX delay */
+  NRF52_TIMER_CHAN_WAITACK   = 2, /* Handle ACK wait */
+  NRF52_TIMER_CHAN_CSMADELAY = 3, /* Handle CSMA wait */
+};
 
-#define GPIO_LED1  (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT0 | GPIO_PIN(6))
+/* Forward reference */
 
-/* RGB LED - LD2:
- *   RGB_RED   - P0-8
- *   RGB_GREEN - P1-9
- *   RGB_BLUE  - P0-12
- */
+struct nrf52_radioi8_tim_s;
+struct nrf52_radioi8_dev_s;
 
-/* Button definitions *******************************************************/
+/* Timer ops  */
 
-/* Board supports four buttons. */
+struct nrf52_radioi8_tim_ops_s
+{
+  /* Configure TIMER event */
 
-#define GPIO_BUTTON1 (GPIO_INPUT | GPIO_PULLUP | GPIO_PORT1 | GPIO_PIN(6))
+  int (*setup)(struct nrf52_radioi8_dev_s *dev, uint8_t chan, uint32_t val);
 
-/****************************************************************************
- * Public Types
- ****************************************************************************/
+  /* Stop timer */
 
-/****************************************************************************
- * Public Data
- ****************************************************************************/
+  void (*stop)(struct nrf52_radioi8_dev_s *dev);
+
+  /* Reset timer */
 
-#ifndef __ASSEMBLY__
+  void (*reset)(struct nrf52_radioi8_dev_s *dev);
+};
+
+/* Timer interface */
+
+struct nrf52_radioi8_tim_s
+{
+  /* Timer lower-half */
+
+  struct nrf52_tim_dev_s *tim;
+
+  /* IEEE 802.15.4 timer operations */
+
+  struct nrf52_radioi8_tim_ops_s *ops;
+
+  /* Timer state */
+
+  int8_t tim_now;
+  bool   tim_pending;
+};
 
 /****************************************************************************
- * Public Functions Prototypes
+ * Public Function Prototypes
  ****************************************************************************/
 
 /****************************************************************************
- * Name: nrf52_bringup
+ * Name: nrf52_radioi8_tim_init
  *
  * Description:
- *   Perform architecture-specific initialization
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=y :
- *     Called from board_late_initialize().
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y :
- *     Called from the NSH library
+ *   Initialize high resoluton timer for IEEE802154 operations.
+ *   Used to handle short radio timeouts like ACK, IFS or delayed
+ *   transmitions.
  *
  ****************************************************************************/
 
-int nrf52_bringup(void);
+struct nrf52_radioi8_tim_s *
+nrf52_radioi8_tim_init(struct nrf52_radioi8_dev_s *dev);
 
-#endif /* __ASSEMBLY__ */
-#endif /* __BOARDS_ARM_NRF52_NRF52840_DONGLE_SRC_NRF52840_DONGLE_H */
+#endif  /* __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TIM_H */
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_trace.c b/arch/arm/src/nrf52/nrf52_ieee802154_trace.c
new file mode 100644
index 0000000000..69d6f7f668
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_trace.c
@@ -0,0 +1,154 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_ieee802154_trace.c
+ *
+ * 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 <nuttx/config.h>
+
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <arch/board/board.h>
+
+#include "nrf52_ieee802154_trace.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* This must match enum radio_trace_type_e */
+
+static const char *g_radio_trace_str[] =
+{
+  "RADIO IRQ",
+  "RADIO IRQ: RX DONE",
+  "RADIO IRQ: TX DONE",
+  "RADIO IRQ: ACK TX",
+  "RADIO IRQ: WAIT ACK",
+  "RADIO IRQ: RX ACK DONE",
+  "RADIO IRQ: TX CCA BUSY",
+
+  "TIM IRQ: TIM ACK TX",
+  "TIM IRQ; TIM TX DELAY",
+  "TIM IRQ: TIM WAIT ACK",
+  "TIM IRQ: TIM CSMA DELAY",
+  "RTC IRQ: RTC SD",
+  "RTC IRQ: RTC CAP",
+  "RTC IRQ: RTC TIMESLOT",
+  "RTC IRQ: RTC BI",
+
+  "WORK: RX",
+  "WORK: TX",
+  "WORK: BUSY",
+  "WORK: ED",
+  "WORK: NO ACK",
+
+  "ACKTX",
+  "TIMSTART",
+  "RXENABLE",
+  "RXDISABLE",
+  "CSMASETUP",
+  "CSMATRIGGER",
+  "NOCSMATRIGGER",
+  "NOACK",
+  "DROPFRAME",
+  "TXTRYAGAIN",
+};
+
+/* Trace data */
+
+static volatile size_t g_radio_trace_cntr = 0;
+static volatile struct radio_trace_s
+g_radio_trace[CONFIG_NRF52_RADIO_IEEE802154_TRACE_BUFSIZE];
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_radioi8_trace_init
+ *
+ * Description:
+ *   Initialize trace interface.
+ *
+ ****************************************************************************/
+
+void nrf52_radioi8_trace_init(void)
+{
+  g_radio_trace_cntr = 0;
+  memset((void *)g_radio_trace, 0, sizeof(g_radio_trace));
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_trace_put
+ *
+ * Description:
+ *   Put trace event.
+ *
+ ****************************************************************************/
+
+void nrf52_radioi8_trace_put(uint8_t type, uint32_t arg)
+{
+  if (g_radio_trace_cntr >= CONFIG_NRF52_RADIO_IEEE802154_TRACE_BUFSIZE)
+    {
+      g_radio_trace_cntr = 0;
+    }
+
+  g_radio_trace[g_radio_trace_cntr].time = perf_gettime();
+  g_radio_trace[g_radio_trace_cntr].str  = g_radio_trace_str[type];
+  g_radio_trace[g_radio_trace_cntr].arg  = arg;
+  g_radio_trace_cntr += 1;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_trace_dump
+ *
+ * Description:
+ *   Dump radio trace.
+ *
+ ****************************************************************************/
+
+void nrf52_radioi8_trace_dump(void)
+{
+  int i = 0;
+
+  printf("NRF52 Radio IEEE 802.15.4 Trace dump:\n");
+  printf("CPU freq: %d\n\n", BOARD_SYSTICK_CLOCK);
+
+  for (i = 0; i < g_radio_trace_cntr; i += 1)
+    {
+      printf("[%lu]: %s %lu\n\n",
+             g_radio_trace[i].time,
+             g_radio_trace[i].str,
+             g_radio_trace[i].arg);
+    }
+
+  /* Reset trace buffer */
+
+  g_radio_trace_cntr = 0;
+  memset((void *)g_radio_trace, 0, sizeof(g_radio_trace));
+}
diff --git a/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h b/arch/arm/src/nrf52/nrf52_ieee802154_trace.h
similarity index 51%
copy from boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
copy to arch/arm/src/nrf52/nrf52_ieee802154_trace.h
index e2f688fb5a..a43daa8c10 100644
--- a/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_trace.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
+ * arch/arm/src/nrf52/nrf52_ieee802154_trace.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,69 +18,89 @@
  *
  ****************************************************************************/
 
-#ifndef __BOARDS_ARM_NRF52_NRF52840_DONGLE_SRC_NRF52840_DONGLE_H
-#define __BOARDS_ARM_NRF52_NRF52840_DONGLE_SRC_NRF52840_DONGLE_H
+#ifndef __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TRACE_H
+#define __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TRACE_H
 
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
-#include <nuttx/compiler.h>
-
-#include "nrf52_gpio.h"
 
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
-/* LED definitions **********************************************************/
-
-/* Definitions to configure LED GPIO as outputs */
-
-#define GPIO_LED1  (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT0 | GPIO_PIN(6))
-
-/* RGB LED - LD2:
- *   RGB_RED   - P0-8
- *   RGB_GREEN - P1-9
- *   RGB_BLUE  - P0-12
- */
-
-/* Button definitions *******************************************************/
-
-/* Board supports four buttons. */
-
-#define GPIO_BUTTON1 (GPIO_INPUT | GPIO_PULLUP | GPIO_PORT1 | GPIO_PIN(6))
-
 /****************************************************************************
  * Public Types
  ****************************************************************************/
 
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-#ifndef __ASSEMBLY__
-
-/****************************************************************************
- * Public Functions Prototypes
- ****************************************************************************/
+/* Trace item */
+
+struct radio_trace_s
+{
+  clock_t     time;     /* Event timestamp */
+  const char *str;      /* Event string */
+  uint32_t    arg;      /* Optional data */
+};
+
+/* This must match char *g_radio_trace_str[] */
+
+enum radio_trace_type_e
+{
+  /* Radio interupts */
+
+  RADIO_TRACE_IRQ_RADIO,
+  RADIO_TRACE_IRQ_RXDONE,
+  RADIO_TRACE_IRQ_TXDONE,
+  RADIO_TRACE_IRQ_ACKTX,
+  RADIO_TRACE_IRQ_WAITACK,
+  RADIO_TRACE_IRQ_RXACKDONE,
+  RADIO_TRACE_IRQ_TXCCABUSY,
+
+  /* Timer interrupts */
+
+  RADIO_TRACE_IRQ_TIMACKTX,
+  RADIO_TRACE_IRQ_TIMTXDELAY,
+  RADIO_TRACE_IRQ_TIMWAITACK,
+  RADIO_TRACE_IRQ_TIMCSMADELAY,
+  RADIO_TRACE_IRQ_RTCSD,
+  RADIO_TRACE_IRQ_RTCCAP,
+  RADIO_TRACE_IRQ_RTCTIMESLOT,
+  RADIO_TRACE_IRQ_RTCBI,
+
+  /* Works */
+
+  RADIO_TRACE_WORK_RX,
+  RADIO_TRACE_WORK_TX,
+  RADIO_TRACE_WORK_BUSY,
+  RADIO_TRACE_WORK_ED,
+  RADIO_TRACE_WORK_NOACK,
+
+  /* Various events */
+
+  RADIO_TRACE_ACKTX,
+  RADIO_TRACE_TIMSTART,
+  RADIO_TRACE_RXENABLE,
+  RADIO_TRACE_RXDISABLE,
+  RADIO_TRACE_CSMASETUP,
+  RADIO_TRACE_CSMATRIGGER,
+  RADIO_TRACE_NOCSMATRIGGER,
+  RADIO_TRACE_NOACK,
+  RADIO_TRACE_DROPFRAME,
+  RADIO_TRACE_TXRETRY,
+};
 
 /****************************************************************************
- * Name: nrf52_bringup
- *
- * Description:
- *   Perform architecture-specific initialization
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=y :
- *     Called from board_late_initialize().
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y :
- *     Called from the NSH library
- *
+ * Public Function Prototypes
  ****************************************************************************/
 
-int nrf52_bringup(void);
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_TRACE
+void nrf52_radioi8_trace_init(void);
+void nrf52_radioi8_trace_put(uint8_t type, uint32_t arg);
+void nrf52_radioi8_trace_dump(void);
+#else
+#  define nrf52_radioi8_trace_put(...)
+#endif
 
-#endif /* __ASSEMBLY__ */
-#endif /* __BOARDS_ARM_NRF52_NRF52840_DONGLE_SRC_NRF52840_DONGLE_H */
+#endif  /* __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TRACE_H */
diff --git a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c b/arch/arm/src/nrf52/nrf52_radio_ieee802154.h
similarity index 69%
copy from boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c
copy to arch/arm/src/nrf52/nrf52_radio_ieee802154.h
index d5bb51e644..7160378a50 100644
--- a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c
+++ b/arch/arm/src/nrf52/nrf52_radio_ieee802154.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c
+ * arch/arm/src/nrf52/nrf52_radio_ieee802154.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,37 +18,36 @@
  *
  ****************************************************************************/
 
+#ifndef __ARCH_ARM_SRC_NRF52_NRF52_RADIO_IEEE802154_H
+#define __ARCH_ARM_SRC_NRF52_NRF52_RADIO_IEEE802154_H
+
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
 
-#include <sys/types.h>
-#include <syslog.h>
+#include <nuttx/wireless/ieee802154/ieee802154_radio.h>
+
+#include "nrf52_radio.h"
 
 /****************************************************************************
- * Public Functions
+ * Public Types
  ****************************************************************************/
 
 /****************************************************************************
- * Name: nrf52_bringup
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_radioi8_register
  *
  * Description:
- *   Perform architecture-specific initialization
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=y :
- *     Called from board_late_initialize().
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y :
- *     Called from the NSH library
+ *   Register NRF52 radio in IEEE802154 mode
  *
  ****************************************************************************/
 
-int nrf52_bringup(void)
-{
-  int ret;
+struct ieee802154_radio_s *
+nrf52_radioi8_register(struct nrf52_radio_board_s *board);
 
-  UNUSED(ret);
-  return OK;
-}
+#endif /* __ARCH_ARM_SRC_NRF52_NRF52_RADIO_IEEE802154_H */
diff --git a/boards/Kconfig b/boards/Kconfig
index 5fed6ec4c0..fe94e4ba1a 100644
--- a/boards/Kconfig
+++ b/boards/Kconfig
@@ -3650,6 +3650,15 @@ endif
 if ARCH_BOARD_NRF52840_DK
 source "boards/arm/nrf52/nrf52840-dk/Kconfig"
 endif
+if ARCH_BOARD_THINGY52
+source "boards/arm/nrf52/thingy52/Kconfig"
+endif
+if ARCH_BOARD_THINGY91_NRF52
+source "boards/arm/nrf52/thingy91-nrf52/Kconfig"
+endif
+if ARCH_BOARD_NRF9160_DK_NRF52
+source "boards/arm/nrf52/nrf9160-dk-nrf52/Kconfig"
+endif
 if ARCH_BOARD_NUTINY_NUC120
 source "boards/arm/nuc1xx/nutiny-nuc120/Kconfig"
 endif
diff --git a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c b/boards/arm/nrf52/common/include/nrf52_ieee802154.h
similarity index 72%
copy from boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c
copy to boards/arm/nrf52/common/include/nrf52_ieee802154.h
index d5bb51e644..187348bf9e 100644
--- a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c
+++ b/boards/arm/nrf52/common/include/nrf52_ieee802154.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c
+ * boards/arm/nrf52/common/include/nrf52_ieee802154.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,37 +18,33 @@
  *
  ****************************************************************************/
 
+#ifndef __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_IEEE802154_H
+#define __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_IEEE802154_H
+
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
 
-#include <sys/types.h>
-#include <syslog.h>
-
 /****************************************************************************
- * Public Functions
+ * Public Functions Prototypes
  ****************************************************************************/
 
 /****************************************************************************
- * Name: nrf52_bringup
+ * Name:  nrf52_ieee802154_initialize
  *
  * Description:
- *   Perform architecture-specific initialization
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=y :
- *     Called from board_late_initialize().
+ *   Initialize IEEE802154 network.
  *
- *   CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y :
- *     Called from the NSH library
+ * Returned Value:
+ *   Zero is returned on success.  Otherwise, a negated errno value is
+ *   returned to indicate the nature of the failure.
  *
  ****************************************************************************/
 
-int nrf52_bringup(void)
-{
-  int ret;
+#ifdef CONFIG_NRF52_RADIO_IEEE802154
+int nrf52_ieee802154_initialize(void);
+#endif
 
-  UNUSED(ret);
-  return OK;
-}
+#endif /* __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_IEEE802154_H */
diff --git a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h b/boards/arm/nrf52/common/include/nrf52_mrf24j40.h
similarity index 63%
copy from boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h
copy to boards/arm/nrf52/common/include/nrf52_mrf24j40.h
index 82fe34c862..cde0af3688 100644
--- a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h
+++ b/boards/arm/nrf52/common/include/nrf52_mrf24j40.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h
+ * boards/arm/nrf52/common/include/nrf52_mrf24j40.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,51 +18,50 @@
  *
  ****************************************************************************/
 
-#ifndef __BOARDS_ARM_NRF52_NRF9160_DK_NRF52_SRC_NRF9160_DK_NRF52_H
-#define __BOARDS_ARM_NRF52_NRF9160_DK_NRF52_SRC_NRF9160_DK_NRF52_H
+#ifndef __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_MRF24J40_H
+#define __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_MRF24J40_H
 
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
-#include <nuttx/compiler.h>
 
-#include "nrf52_gpio.h"
+#include <stdint.h>
 
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
+#include <nuttx/wireless/ieee802154/mrf24j40.h>
 
 /****************************************************************************
  * Public Types
  ****************************************************************************/
 
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-#ifndef __ASSEMBLY__
+struct nrf52_mrf24j40_s
+{
+  struct mrf24j40_lower_s  dev;
+  xcpt_t                   handler;
+  void                    *arg;
+  uint32_t                 intcfg;
+  uint8_t                  spidev;
+};
 
 /****************************************************************************
  * Public Functions Prototypes
  ****************************************************************************/
 
 /****************************************************************************
- * Name: nrf52_bringup
+ * Name: nrf52_mrf24j40_devsetup
  *
  * Description:
- *   Perform architecture-specific initialization
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=y :
- *     Called from board_late_initialize().
+ *   Initialize one the MRF24J40 device in one mikroBUS slot
  *
- *   CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y :
- *     Called from the NSH library
+ * Returned Value:
+ *   Zero is returned on success.  Otherwise, a negated errno value is
+ *   returned to indicate the nature of the failure.
  *
  ****************************************************************************/
 
-int nrf52_bringup(void);
+#ifdef CONFIG_IEEE802154_MRF24J40
+int nrf52_mrf24j40_devsetup(struct nrf52_mrf24j40_s *priv);
+#endif
 
-#endif /* __ASSEMBLY__ */
-#endif /* __BOARDS_ARM_NRF52_NRF9160_DK_NRF52_SRC_NRF9160_DK_NRF52_H */
+#endif /* __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_MRF24J40_H */
diff --git a/boards/arm/nrf52/common/src/CMakeLists.txt b/boards/arm/nrf52/common/src/CMakeLists.txt
index fa869af2fd..ade42fdd19 100644
--- a/boards/arm/nrf52/common/src/CMakeLists.txt
+++ b/boards/arm/nrf52/common/src/CMakeLists.txt
@@ -40,6 +40,14 @@ if(CONFIG_ARCH_BOARD_COMMON)
     list(APPEND SRCS nrf52_reset.c)
   endif()
 
+  if(CONFIG_NRF52_RADIO_IEEE802154)
+    list(APPEND SRCS nrf52_ieee802154.c)
+  endif()
+
+  if(CONFIG_IEEE802154_MRF24J40)
+    list(APPEND SRCS nrf52_mrf24j40.c)
+  endif()
+
   target_sources(board PRIVATE ${SRCS})
 
 endif()
diff --git a/boards/arm/nrf52/common/src/Make.defs b/boards/arm/nrf52/common/src/Make.defs
index f7870690a7..90031c5cf2 100644
--- a/boards/arm/nrf52/common/src/Make.defs
+++ b/boards/arm/nrf52/common/src/Make.defs
@@ -40,6 +40,14 @@ ifeq ($(CONFIG_BOARDCTL_RESET),y)
 CSRCS += nrf52_reset.c
 endif
 
+ifeq ($(CONFIG_NRF52_RADIO_IEEE802154),y)
+CSRCS += nrf52_ieee802154.c
+endif
+
+ifeq ($(CONFIG_IEEE802154_MRF24J40),y)
+CSRCS += nrf52_mrf24j40.c
+endif
+
 DEPPATH += --dep-path src
 VPATH += :src
 CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
diff --git a/boards/arm/nrf52/common/src/nrf52_ieee802154.c b/boards/arm/nrf52/common/src/nrf52_ieee802154.c
new file mode 100644
index 0000000000..d2dcedd086
--- /dev/null
+++ b/boards/arm/nrf52/common/src/nrf52_ieee802154.c
@@ -0,0 +1,106 @@
+/****************************************************************************
+ * boards/arm/nrf52/common/src/nrf52_ieee802154.c
+ *
+ * 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 <nuttx/config.h>
+
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
+
+#include "nrf52_radio_ieee802154.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_ieee802154_initialize
+ *
+ * Description:
+ *   Initialize the IEEE 802.15.4 network.
+ *
+ * Returned Value:
+ *   Zero is returned on success.  Otherwise, a negated errno value is
+ *   returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+int nrf52_ieee802154_initialize(void)
+{
+  struct ieee802154_radio_s *radio;
+  MACHANDLE                  mac;
+  int                        ret;
+
+  /* Initialize and register the SPI MRF24J40 device */
+
+  radio = nrf52_radioi8_register(NULL);
+  if (radio == NULL)
+    {
+      wlerr("ERROR: Failed to initialize radio\n");
+      return -ENODEV;
+    }
+
+  /* Create a 802.15.4 MAC device from a 802.15.4 compatible radio device. */
+
+  mac = mac802154_create(radio);
+  if (mac == NULL)
+    {
+      wlerr("ERROR: Failed to initialize IEEE802.15.4 MAC\n");
+      return -ENODEV;
+    }
+
+#ifdef CONFIG_IEEE802154_NETDEV
+  /* Use the IEEE802.15.4 MAC interface instance to create a 6LoWPAN
+   * network interface by wrapping the MAC intrface instance in a
+   * network device driver via mac802154dev_register().
+   */
+
+  ret = mac802154netdev_register(mac);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Failed to register the MAC network driver wpan%d: %d\n",
+            0, ret);
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_IEEE802154_MACDEV
+  /* If want to call these APIs from userspace, you have to wrap the MAC
+   * interface in a character device viamac802154dev_register().
+   */
+
+  ret = mac802154dev_register(mac, 0);
+  if (ret < 0)
+    {
+      wlerr("ERROR:");
+      wlerr(" Failed to register the MAC character driver /dev/ieee%d: %d\n",
+            0, ret);
+      return ret;
+    }
+#endif
+
+  UNUSED(ret);
+  return OK;
+}
diff --git a/boards/arm/nrf52/common/src/nrf52_mrf24j40.c b/boards/arm/nrf52/common/src/nrf52_mrf24j40.c
new file mode 100644
index 0000000000..dcfbf40840
--- /dev/null
+++ b/boards/arm/nrf52/common/src/nrf52_mrf24j40.c
@@ -0,0 +1,136 @@
+/****************************************************************************
+ * boards/arm/nrf52/common/src/nrf52_mrf24j40.c
+ *
+ * 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 <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
+#include <nuttx/wireless/ieee802154/mrf24j40.h>
+
+#include "nrf52_gpio.h"
+#include "nrf52_spi.h"
+
+#include "nrf52_mrf24j40.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_DRIVERS_WIRELESS
+#  error Wireless support requires CONFIG_DRIVERS_WIRELESS
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_mrf24j40_devsetup
+ *
+ * Description:
+ *   Initialize one the MRF24J40 device in one mikroBUS slot
+ *
+ * Returned Value:
+ *   Zero is returned on success.  Otherwise, a negated errno value is
+ *   returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+int nrf52_mrf24j40_devsetup(struct nrf52_mrf24j40_s *priv)
+{
+  struct ieee802154_radio_s *radio;
+  MACHANDLE                  mac;
+  struct spi_dev_s          *spi;
+  int                        ret;
+
+  /* Configure pins */
+
+  nrf52_gpio_config(priv->intcfg);
+
+  /* Initialize the SPI bus and get an instance of the SPI interface */
+
+  spi = nrf52_spibus_initialize(priv->spidev);
+  if (spi == NULL)
+    {
+      wlerr("Failed to initialize SPI bus %d\n", priv->spidev);
+      return -ENODEV;
+    }
+
+  /* Initialize and register the SPI MRF24J40 device */
+
+  radio = mrf24j40_init(spi, &priv->dev);
+  if (radio == NULL)
+    {
+      wlerr("Failed to initialize SPI bus %d\n", priv->spidev);
+      return -ENODEV;
+    }
+
+  /* Create a 802.15.4 MAC device from a 802.15.4 compatible radio device. */
+
+  mac = mac802154_create(radio);
+  if (mac == NULL)
+    {
+      wlerr("Failed to initialize IEEE802.15.4 MAC\n");
+      return -ENODEV;
+    }
+
+#ifdef CONFIG_IEEE802154_NETDEV
+  /* Use the IEEE802.15.4 MAC interface instance to create a 6LoWPAN
+   * network interface by wrapping the MAC intrface instance in a
+   * network device driver via mac802154dev_register().
+   */
+
+  ret = mac802154netdev_register(mac);
+  if (ret < 0)
+    {
+      wlerr("Failed to register the MAC network driver wpan%d: %d\n",
+            0, ret);
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_IEEE802154_MACDEV
+  /* If want to call these APIs from userspace, you have to wrap the MAC
+   * interface in a character device viamac802154dev_register().
+   */
+
+  ret = mac802154dev_register(mac, 0);
+  if (ret < 0)
+    {
+      wlerr("Failed to register the MAC character driver /dev/ieee%d: %d\n",
+            0, ret);
+      return ret;
+    }
+#endif
+
+  UNUSED(ret);
+  return OK;
+}
diff --git a/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_6lowpan/defconfig b/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_6lowpan/defconfig
new file mode 100644
index 0000000000..f0c31e2a45
--- /dev/null
+++ b/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_6lowpan/defconfig
@@ -0,0 +1,81 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_ARCH_FPU is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="nrf52832-dk"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_NRF52832_DK=y
+CONFIG_ARCH_CHIP="nrf52"
+CONFIG_ARCH_CHIP_NRF52832=y
+CONFIG_ARCH_CHIP_NRF52=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_STDARG_H=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=5500
+CONFIG_BUILTIN=y
+CONFIG_DRIVERS_IEEE802154=y
+CONFIG_DRIVERS_WIRELESS=y
+CONFIG_EXAMPLES_NETTEST=y
+CONFIG_EXAMPLES_NETTEST_DEVNAME="wpan0"
+CONFIG_EXAMPLES_NETTEST_SERVER_PORTNO=61616
+CONFIG_EXAMPLES_NETTEST_TARGET2=y
+CONFIG_EXAMPLES_UDP=y
+CONFIG_EXAMPLES_UDP_CLIENT_PORTNO=61617
+CONFIG_EXAMPLES_UDP_DEVNAME="wpan0"
+CONFIG_EXAMPLES_UDP_IPv6=y
+CONFIG_EXAMPLES_UDP_SERVER_PORTNO=61616
+CONFIG_EXAMPLES_UDP_TARGET2=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_FS_PROCFS=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_IEEE802154_I8SAK=y
+CONFIG_IEEE802154_MAC=y
+CONFIG_IEEE802154_MACDEV=y
+CONFIG_IEEE802154_MRF24J40=y
+CONFIG_IEEE802154_NETDEV=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_MAC802154_NTXDESC=36
+CONFIG_MM_REGIONS=2
+CONFIG_NET=y
+CONFIG_NETDEV_HPWORK_THREAD=y
+CONFIG_NETDEV_LATEINIT=y
+CONFIG_NETDEV_STATISTICS=y
+CONFIG_NETDEV_WIRELESS_IOCTL=y
+CONFIG_NETINIT_NETLOCAL=y
+CONFIG_NETINIT_NOMAC=y
+CONFIG_NETUTILS_TELNETD=y
+CONFIG_NET_6LOWPAN=y
+CONFIG_NET_BROADCAST=y
+CONFIG_NET_IPv6=y
+CONFIG_NET_SOCKOPTS=y
+CONFIG_NET_STATISTICS=y
+CONFIG_NET_TCP=y
+CONFIG_NET_TCPBACKLOG=y
+CONFIG_NET_TCP_WRITE_BUFFERS=y
+CONFIG_NET_UDP=y
+CONFIG_NRF52_GPIOTE=y
+CONFIG_NRF52_SPI0_MASTER=y
+CONFIG_NRF52_UART0=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_PROMPT_STRING="nsh-mrf> "
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=65535
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_SPI=y
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_TELNET_CLIENT=y
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_IEEE802154=y
diff --git a/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_mac/defconfig b/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_mac/defconfig
new file mode 100644
index 0000000000..0b3a93261d
--- /dev/null
+++ b/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_mac/defconfig
@@ -0,0 +1,60 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_ARCH_FPU is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="nrf52832-dk"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_NRF52832_DK=y
+CONFIG_ARCH_CHIP="nrf52"
+CONFIG_ARCH_CHIP_NRF52832=y
+CONFIG_ARCH_CHIP_NRF52=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_STDARG_H=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=5500
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DRIVERS_IEEE802154=y
+CONFIG_DRIVERS_WIRELESS=y
+CONFIG_FS_PROCFS=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_IEEE802154_I8SAK=y
+CONFIG_IEEE802154_MAC=y
+CONFIG_IEEE802154_MACDEV=y
+CONFIG_IEEE802154_MRF24J40=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_MM_REGIONS=2
+CONFIG_NRF52_GPIOTE=y
+CONFIG_NRF52_SPI0_MASTER=y
+CONFIG_NRF52_UART0=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_LINELEN=64
+CONFIG_NSH_PROMPT_STRING="nsh-mrf> "
+CONFIG_NSH_READLINE=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=65535
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_SPI=y
+CONFIG_STACK_COLORATION=y
+CONFIG_STACK_USAGE=y
+CONFIG_START_DAY=26
+CONFIG_START_MONTH=3
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TASK_NAME_SIZE=0
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_IEEE802154=y
diff --git a/boards/arm/nrf52/nrf52832-dk/include/board.h b/boards/arm/nrf52/nrf52832-dk/include/board.h
index b776889582..092a3a0e10 100644
--- a/boards/arm/nrf52/nrf52832-dk/include/board.h
+++ b/boards/arm/nrf52/nrf52832-dk/include/board.h
@@ -107,4 +107,16 @@
 #define BOARD_UART0_RX_PIN  (GPIO_INPUT  | GPIO_PORT0 | GPIO_PIN(8))
 #define BOARD_UART0_TX_PIN  (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT0 | GPIO_PIN(6))
 
+/* SPI Pins *****************************************************************/
+
+/* SPI0 - Arduino PINs
+ *   SPI0_SCK  - P0.25 (P13)
+ *   SPI0_MISO - P0.24 (D12)
+ *   SPI0_MOSI - P0.23 (D11)
+ */
+
+#define BOARD_SPI0_SCK_PIN  (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT0 | GPIO_PIN(25))
+#define BOARD_SPI0_MISO_PIN (GPIO_INPUT  | GPIO_PORT0 | GPIO_PIN(24))
+#define BOARD_SPI0_MOSI_PIN (GPIO_OUTPUT | GPIO_PORT0 | GPIO_PIN(23))
+
 #endif /* __BOARDS_ARM_NRF52_NRF52832_DK_INCLUDE_BOARD_H */
diff --git a/boards/arm/nrf52/nrf52832-dk/src/CMakeLists.txt b/boards/arm/nrf52/nrf52832-dk/src/CMakeLists.txt
index 7e61a0d0a9..d09591c71e 100644
--- a/boards/arm/nrf52/nrf52832-dk/src/CMakeLists.txt
+++ b/boards/arm/nrf52/nrf52832-dk/src/CMakeLists.txt
@@ -34,6 +34,14 @@ if(CONFIG_ARCH_BUTTONS)
   list(APPEND SRCS nrf52_buttons.c)
 endif()
 
+if(CONFIG_NRF52_SPI_MASTER)
+  list(APPEND SRCS nrf52_spi.c)
+endif()
+
+if(CONFIG_IEEE802154_MRF24J40)
+  list(APPEND SRCS nrf52_ieee802154_mrf24j40.c)
+endif()
+
 target_sources(board PRIVATE ${SRCS})
 
 if(CONFIG_ARCH_BOARD_COMMON)
diff --git a/boards/arm/nrf52/nrf52832-dk/src/Make.defs b/boards/arm/nrf52/nrf52832-dk/src/Make.defs
index 7e4e6508fa..7b6364940c 100644
--- a/boards/arm/nrf52/nrf52832-dk/src/Make.defs
+++ b/boards/arm/nrf52/nrf52832-dk/src/Make.defs
@@ -36,6 +36,14 @@ ifeq ($(CONFIG_ARCH_BUTTONS),y)
 CSRCS += nrf52_buttons.c
 endif
 
+ifeq ($(CONFIG_NRF52_SPI_MASTER),y)
+CSRCS += nrf52_spi.c
+endif
+
+ifeq ($(CONFIG_IEEE802154_MRF24J40),y)
+CSRCS += nrf52_ieee802154_mrf24j40.c
+endif
+
 DEPPATH += --dep-path board
 VPATH += :board
 CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board
diff --git a/boards/arm/nrf52/nrf52832-dk/src/nrf52832-dk.h b/boards/arm/nrf52/nrf52832-dk/src/nrf52832-dk.h
index bdf5c8f0ad..c857ac3e5d 100644
--- a/boards/arm/nrf52/nrf52832-dk/src/nrf52832-dk.h
+++ b/boards/arm/nrf52/nrf52832-dk/src/nrf52832-dk.h
@@ -64,6 +64,16 @@
 #define GPIO_BUTTON3 (GPIO_INPUT | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN(15))
 #define GPIO_BUTTON4 (GPIO_INPUT | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN(16))
 
+/* GPIO definitions *********************************************************/
+
+/* MRF24J40 pins
+ * CS   - P0.11
+ * INT  - P0.12
+ */
+
+#define GPIO_MRF24J40_CS    (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT0 | GPIO_PIN(11))
+#define GPIO_MRF24J40_INT   (GPIO_INPUT  | GPIO_PORT0 | GPIO_PIN(12))
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
@@ -94,5 +104,33 @@
 
 int nrf52_bringup(void);
 
+/****************************************************************************
+ * Name: nrf52_spidev_initialize
+ *
+ * Description:
+ *   Called to configure SPI chip select GPIO pins for the nrf52840-dk board.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NRF52_SPI_MASTER
+void nrf52_spidev_initialize(void);
+#endif
+
+/****************************************************************************
+ * Name: nrf52_mrf24j40_initialize
+ *
+ * Description:
+ *   Initialize the MRF24J40 device.
+ *
+ * Returned Value:
+ *   Zero is returned on success.  Otherwise, a negated errno value is
+ *   returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IEEE802154_MRF24J40
+int nrf52_mrf24j40_initialize(void);
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __BOARDS_ARM_NRF52_NRF52832_DK_SRC_NRF52832_DK_H */
diff --git a/boards/arm/nrf52/nrf52832-dk/src/nrf52_boot.c b/boards/arm/nrf52/nrf52832-dk/src/nrf52_boot.c
index a23cf76ca9..aeaf57d630 100644
--- a/boards/arm/nrf52/nrf52832-dk/src/nrf52_boot.c
+++ b/boards/arm/nrf52/nrf52832-dk/src/nrf52_boot.c
@@ -54,6 +54,12 @@ void nrf52_board_initialize(void)
 #ifdef CONFIG_ARCH_LEDS
   board_autoled_initialize();
 #endif
+
+#ifdef CONFIG_NRF52_SPI_MASTER
+  /* Configure SPI chip selects */
+
+  nrf52_spidev_initialize();
+#endif
 }
 
 /****************************************************************************
diff --git a/boards/arm/nrf52/nrf52832-dk/src/nrf52_bringup.c b/boards/arm/nrf52/nrf52832-dk/src/nrf52_bringup.c
index 3526a9f930..aca8f50019 100644
--- a/boards/arm/nrf52/nrf52832-dk/src/nrf52_bringup.c
+++ b/boards/arm/nrf52/nrf52832-dk/src/nrf52_bringup.c
@@ -53,6 +53,10 @@
 #  include "nrf52_sdc.h"
 #endif
 
+#ifdef CONFIG_IEEE802154_MRF24J40
+#  include "nrf52_mrf24j40.h"
+#endif
+
 #include "nrf52832-dk.h"
 
 /****************************************************************************
@@ -152,6 +156,17 @@ int nrf52_bringup(void)
     }
 #endif /* CONFIG_MTD */
 
+#ifdef CONFIG_IEEE802154_MRF24J40
+  /* Configure MRF24J40 wireless */
+
+  ret = nrf52_mrf24j40_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: nrf52_mrf24j40_initialize() failed: %d\n",
+             ret);
+    }
+#endif
+
   UNUSED(ret);
   return OK;
 }
diff --git a/boards/arm/nrf52/nrf52832-dk/src/nrf52_ieee802154_mrf24j40.c b/boards/arm/nrf52/nrf52832-dk/src/nrf52_ieee802154_mrf24j40.c
new file mode 100644
index 0000000000..13986ab94f
--- /dev/null
+++ b/boards/arm/nrf52/nrf52832-dk/src/nrf52_ieee802154_mrf24j40.c
@@ -0,0 +1,177 @@
+/****************************************************************************
+ * boards/arm/nrf52/nrf52832-dk/src/nrf52_ieee802154_mrf24j40.c
+ *
+ * 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 <nuttx/config.h>
+
+#include <debug.h>
+
+#include "nrf52_gpio.h"
+#include "nrf52_gpiote.h"
+#include "nrf52_spi.h"
+
+#include "nrf52_mrf24j40.h"
+
+#include "nrf52832-dk.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_NRF52_SPI0_MASTER
+#  error this driver requires CONFIG_NRF52_SPI0_MASTER
+#endif
+
+#define NRF52_MRF24J40_SPI (0)
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* IRQ/GPIO access callbacks.  These operations all hidden behind callbacks
+ * to isolate the MRF24J40 driver from differences in GPIO interrupt handling
+ * varying boards and MCUs.
+ *
+ *   irq_attach - Attach the MRF24J40 interrupt handler to the GPIO
+ *                interrupt
+ *   irq_enable - Enable or disable the GPIO interrupt
+ */
+
+static int  nrf52_attach_irq(const struct mrf24j40_lower_s *lower,
+                             xcpt_t handler, void *arg);
+static void nrf52_enable_irq(const struct mrf24j40_lower_s *lower,
+                             bool state);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* A reference to a structure of this type must be passed to the MRF24J40
+ * driver.  This structure provides information about the configuration
+ * of the MRF24J40 and provides some board-specific hooks.
+ *
+ * Memory for this structure is provided by the caller.  It is not copied
+ * by the driver and is presumed to persist while the driver is active. The
+ * memory must be writable because, under certain circumstances, the driver
+ * may modify frequency or X plate resistance values.
+ */
+
+static struct nrf52_mrf24j40_s g_mrf24j40_priv =
+{
+  .dev.attach  = nrf52_attach_irq,
+  .dev.enable  = nrf52_enable_irq,
+  .handler     = NULL,
+  .arg         = NULL,
+  .intcfg      = GPIO_MRF24J40_INT,
+  .spidev      = NRF52_MRF24J40_SPI,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_attach_irq
+ *
+ * Description:
+ *   Attach the MRF24J40 interrupt handler to the GPIO interrupt.
+ *
+ ****************************************************************************/
+
+static int nrf52_attach_irq(const struct mrf24j40_lower_s *lower,
+                            xcpt_t handler, void *arg)
+{
+  struct nrf52_mrf24j40_s *priv = (struct nrf52_mrf24j40_s *)lower;
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Just save the handler for use when the interrupt is enabled */
+
+  priv->handler = handler;
+  priv->arg     = arg;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_enable_irq
+ *
+ * Description:
+ *   Enable or disable the GPIO interrupt
+ *
+ ****************************************************************************/
+
+static void nrf52_enable_irq(const struct mrf24j40_lower_s *lower,
+                             bool state)
+{
+  struct nrf52_mrf24j40_s *priv = (struct nrf52_mrf24j40_s *)lower;
+
+  /* The caller should not attempt to enable interrupts if the handler
+   * has not yet been 'attached'
+   */
+
+  DEBUGASSERT(priv != NULL && (priv->handler != NULL || !state));
+
+  wlinfo("state:%d\n", (int)state);
+
+  /* Attach and enable, or detach and disable */
+
+  if (state)
+    {
+      nrf52_gpiote_set_event(priv->intcfg, false, true,
+                             priv->handler, priv->arg);
+    }
+  else
+    {
+      nrf52_gpiote_set_event(priv->intcfg, false, false,
+                             priv->handler, priv->arg);
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_mrf24j40_initialize
+ *
+ * Description:
+ *   Initialize the MRF24J40 device.
+ *
+ * Returned Value:
+ *   Zero is returned on success.  Otherwise, a negated errno value is
+ *   returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+int nrf52_mrf24j40_initialize(void)
+{
+  int ret;
+
+  ret = nrf52_mrf24j40_devsetup(&g_mrf24j40_priv);
+  if (ret < 0)
+    {
+      wlerr("Failed to initialize mrf24j40: %d\n", ret);
+    }
+
+  return ret;
+}
diff --git a/boards/arm/nrf52/nrf52832-dk/src/nrf52_spi.c b/boards/arm/nrf52/nrf52832-dk/src/nrf52_spi.c
new file mode 100644
index 0000000000..7e8e6d3adf
--- /dev/null
+++ b/boards/arm/nrf52/nrf52832-dk/src/nrf52_spi.c
@@ -0,0 +1,177 @@
+/****************************************************************************
+ * boards/arm/nrf52/nrf52832-dk/src/nrf52_spi.c
+ *
+ * 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 <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/spi/spi.h>
+
+#include "arm_internal.h"
+#include "chip.h"
+#include "nrf52_gpio.h"
+#include "nrf52_spi.h"
+
+#include "nrf52832-dk.h"
+#include <arch/board/board.h>
+
+#ifdef CONFIG_NRF52_SPI_MASTER
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_spidev_initialize
+ *
+ * Description:
+ *   Called to configure SPI chip select GPIO pins for the Nucleo-144 board.
+ *
+ ****************************************************************************/
+
+void nrf52_spidev_initialize(void)
+{
+#ifdef CONFIG_NRF52_SPI0_MASTER
+#  ifdef CONFIG_IEEE802154_MRF24J40
+  /* Configure the SPI-based MRF24J40 chip select GPIO */
+
+  spiinfo("Configure GPIO for MRF24J40 SPI1/CS\n");
+
+  nrf52_gpio_config(GPIO_MRF24J40_CS);
+  nrf52_gpio_write(GPIO_MRF24J40_CS, true);
+#  endif
+#endif
+}
+
+/****************************************************************************
+ * Name:  nrf52_spi0/1/2/3/select and nrf52_spi0/1/2/3/status
+ *
+ * Description:
+ *   The external functions, nrf52_spi0/1/2/3select and
+ *   nrf52_spi0/1/2/3status must be provided by board-specific logic.
+ *   They are implementations of the select and status methods of the SPI
+ *   interface defined by struct spi_ops_s (see include/nuttx/spi/spi.h).
+ *   All other methods (including nrf52_spibus_initialize()) are provided
+ *   by common NRF52 logic.  To use this common SPI logic on your board:
+ *
+ *   1. Provide logic in nrf52_boardinitialize() to configure SPI chip select
+ *      pins.
+ *   2. Provide nrf52_spi0/1/2/3select() and nrf52_spi0/1/2/3status()
+ *      functions in your board-specific logic. These functions will perform
+ *      chip selection and status operations using GPIOs in the way your
+ *      board is configured.
+ *   3. Add a calls to nrf52_spibus_initialize() in your low level
+ *      application initialization logic
+ *   4. The handle returned by nrf52_spibus_initialize() may then be used to
+ *      bind the SPI driver to higher level logic (e.g., calling
+ *      mmcsd_spislotinitialize(), for example, will bind the SPI driver to
+ *      the SPI MMC/SD driver).
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NRF52_SPI0_MASTER
+void nrf52_spi0select(struct spi_dev_s *dev, uint32_t devid,
+                      bool selected)
+{
+  spiinfo("devid: %08lx CS: %s\n",
+          (unsigned long)devid, selected ? "assert" : "de-assert");
+
+  switch (devid)
+    {
+#ifdef CONFIG_IEEE802154_MRF24J40
+    case SPIDEV_IEEE802154(0):
+        {
+          spiinfo("MRF24J40 device %s\n",
+                  selected ? "asserted" : "de-asserted");
+
+          /* Set the GPIO low to select and high to de-select */
+
+          nrf52_gpio_write(GPIO_MRF24J40_CS, !selected);
+          break;
+        }
+#endif
+
+      default:
+        {
+          break;
+        }
+    }
+}
+
+uint8_t nrf52_spi0status(struct spi_dev_s *dev, uint32_t devid)
+{
+  uint8_t status = 0;
+
+  switch (devid)
+    {
+#ifdef CONFIG_IEEE802154_MRF24J40
+      case SPIDEV_IEEE802154(0):
+        {
+          status |= SPI_STATUS_PRESENT;
+          break;
+        }
+#endif
+
+      default:
+        {
+          break;
+        }
+    }
+
+  return status;
+}
+#endif
+
+#ifdef CONFIG_NRF52_SPI1_MASTER
+void nrf52_spi1select(struct spi_dev_s *dev, uint32_t devid,
+                      bool selected)
+{
+  spiinfo("devid: %08lx CS: %s\n",
+          (unsigned long)devid, selected ? "assert" : "de-assert");
+}
+
+uint8_t nrf52_spi1status(struct spi_dev_s *dev, uint32_t devid)
+{
+  return 0;
+}
+#endif
+
+#ifdef CONFIG_nrf52_SPI2_MASTER
+void nrf52_spi2select(struct spi_dev_s *dev, uint32_t devid,
+                      bool selected)
+{
+  spiinfo("devid: %08lx CS: %s\n",
+          (unsigned long)devid, selected ? "assert" : "de-assert");
+}
+
+uint8_t nrf52_spi2status(struct spi_dev_s *dev, uint32_t devid)
+{
+  return 0;
+}
+#endif
+
+#endif /* CONFIG_NRF52_SPI_MASTER */
diff --git a/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_6lowpan/defconfig b/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_6lowpan/defconfig
new file mode 100644
index 0000000000..6afe61de12
--- /dev/null
+++ b/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_6lowpan/defconfig
@@ -0,0 +1,81 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_ARCH_FPU is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="nrf52840-dk"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_NRF52840_DK=y
+CONFIG_ARCH_CHIP="nrf52"
+CONFIG_ARCH_CHIP_NRF52840=y
+CONFIG_ARCH_CHIP_NRF52=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_STDARG_H=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=5500
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DRIVERS_IEEE802154=y
+CONFIG_DRIVERS_WIRELESS=y
+CONFIG_EXAMPLES_NETTEST=y
+CONFIG_EXAMPLES_NETTEST_DEVNAME="wpan0"
+CONFIG_EXAMPLES_NETTEST_SERVER_PORTNO=61616
+CONFIG_EXAMPLES_NETTEST_TARGET2=y
+CONFIG_EXAMPLES_UDP=y
+CONFIG_EXAMPLES_UDP_CLIENT_PORTNO=61617
+CONFIG_EXAMPLES_UDP_DEVNAME="wpan0"
+CONFIG_EXAMPLES_UDP_IPv6=y
+CONFIG_EXAMPLES_UDP_SERVER_PORTNO=61616
+CONFIG_EXAMPLES_UDP_TARGET2=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_FS_PROCFS=y
+CONFIG_IEEE802154_I8SAK=y
+CONFIG_IEEE802154_MAC=y
+CONFIG_IEEE802154_MACDEV=y
+CONFIG_IEEE802154_NETDEV=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_MAC802154_NTXDESC=36
+CONFIG_MM_REGIONS=2
+CONFIG_NET=y
+CONFIG_NETDEV_HPWORK_THREAD=y
+CONFIG_NETDEV_LATEINIT=y
+CONFIG_NETDEV_STATISTICS=y
+CONFIG_NETDEV_WIRELESS_IOCTL=y
+CONFIG_NETINIT_NETLOCAL=y
+CONFIG_NETINIT_NOMAC=y
+CONFIG_NETUTILS_TELNETD=y
+CONFIG_NET_6LOWPAN=y
+CONFIG_NET_BROADCAST=y
+CONFIG_NET_IPv6=y
+CONFIG_NET_SOCKOPTS=y
+CONFIG_NET_STATISTICS=y
+CONFIG_NET_TCP=y
+CONFIG_NET_TCPBACKLOG=y
+CONFIG_NET_TCP_WRITE_BUFFERS=y
+CONFIG_NET_UDP=y
+CONFIG_NRF52_HFCLK_XTAL=y
+CONFIG_NRF52_RADIO=y
+CONFIG_NRF52_RADIO_IEEE802154=y
+CONFIG_NRF52_UART0=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_PROMPT_STRING="nsh-nrf52> "
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=262144
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_TELNET_CLIENT=y
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_IEEE802154=y
diff --git a/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_mac/defconfig b/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_mac/defconfig
new file mode 100644
index 0000000000..4d9a842623
--- /dev/null
+++ b/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_mac/defconfig
@@ -0,0 +1,61 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_ARCH_FPU is not set
+# CONFIG_NSH_DISABLE_IFCONFIG is not set
+# CONFIG_NSH_DISABLE_PS is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="nrf52840-dk"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_NRF52840_DK=y
+CONFIG_ARCH_CHIP="nrf52"
+CONFIG_ARCH_CHIP_NRF52840=y
+CONFIG_ARCH_CHIP_NRF52=y
+CONFIG_ARCH_PERF_EVENTS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_STDARG_H=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=5500
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DRIVERS_IEEE802154=y
+CONFIG_DRIVERS_WIRELESS=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_IDLETHREAD_STACKSIZE=4096
+CONFIG_IEEE802154_I8SAK=y
+CONFIG_IEEE802154_MAC=y
+CONFIG_IEEE802154_MACDEV=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_MM_REGIONS=2
+CONFIG_NRF52_HFCLK_XTAL=y
+CONFIG_NRF52_RADIO=y
+CONFIG_NRF52_RADIO_IEEE802154=y
+CONFIG_NRF52_TIMER1=y
+CONFIG_NRF52_UART0=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_PROMPT_STRING="nsh-nrf52> "
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=262144
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_BACKTRACE=y
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_HPWORKSTACKSIZE=4096
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_LPWORKSTACKSIZE=4096
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_CANARIES=y
+CONFIG_STACK_COLORATION=y
+CONFIG_STACK_USAGE=y
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_IEEE802154=y
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
index 4bc740ff01..26e8ea89ae 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
@@ -61,13 +61,17 @@
 #  include "nrf52_lsm9ds1.h"
 #endif
 
+#ifdef CONFIG_NRF52_RADIO_IEEE802154
+#  include "nrf52_ieee802154.h"
+#endif
+
 #include "nrf52840-dk.h"
 
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
-#define NRF52_TIMER    (1)
+#define NRF52_TIMER    (2)
 #define LMS9DS1_I2CBUS (0)
 
 /****************************************************************************
@@ -309,6 +313,15 @@ int nrf52_bringup(void)
     }
 #endif /* CONFIG_SENSORS_LSM6DSL */
 
+#ifdef CONFIG_NRF52_RADIO_IEEE802154
+  ret = nrf52_ieee802154_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize IEE802154 radio: %d\n",
+             ret);
+    }
+#endif
+
   UNUSED(ret);
   return OK;
 }
diff --git a/boards/arm/nrf52/nrf52840-dongle/configs/ieee802154_mac/defconfig b/boards/arm/nrf52/nrf52840-dongle/configs/ieee802154_mac/defconfig
new file mode 100644
index 0000000000..3e3a0a98d2
--- /dev/null
+++ b/boards/arm/nrf52/nrf52840-dongle/configs/ieee802154_mac/defconfig
@@ -0,0 +1,65 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_ARCH_FPU is not set
+# CONFIG_DEV_CONSOLE is not set
+# CONFIG_NSH_DISABLE_IFCONFIG is not set
+# CONFIG_NSH_DISABLE_PS is not set
+# CONFIG_SYSLOG_DEFAULT is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="nrf52840-dongle"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_NRF52840_DONGLE=y
+CONFIG_ARCH_CHIP="nrf52"
+CONFIG_ARCH_CHIP_NRF52840=y
+CONFIG_ARCH_CHIP_NRF52=y
+CONFIG_ARCH_PERF_EVENTS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_STDARG_H=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARDCTL_USBDEVCTRL=y
+CONFIG_BOARD_LOOPSPERMSEC=5500
+CONFIG_BUILTIN=y
+CONFIG_CDCACM=y
+CONFIG_CDCACM_CONSOLE=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DRIVERS_IEEE802154=y
+CONFIG_DRIVERS_WIRELESS=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_IDLETHREAD_STACKSIZE=4096
+CONFIG_IEEE802154_I8SAK=y
+CONFIG_IEEE802154_MAC=y
+CONFIG_IEEE802154_MACDEV=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_MM_REGIONS=2
+CONFIG_NRF52_HFCLK_XTAL=y
+CONFIG_NRF52_RADIO=y
+CONFIG_NRF52_RADIO_IEEE802154=y
+CONFIG_NRF52_TIMER1=y
+CONFIG_NRF52_USBDEV=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_PROMPT_STRING="nsh-dongle> "
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=262144
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_BACKTRACE=y
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_HPWORKSTACKSIZE=4096
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_LPWORKSTACKSIZE=4096
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_CANARIES=y
+CONFIG_STACK_COLORATION=y
+CONFIG_STACK_USAGE=y
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_IEEE802154=y
diff --git a/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h b/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
index e2f688fb5a..6c17917383 100644
--- a/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
+++ b/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h
@@ -34,6 +34,18 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+/* Configuration ************************************************************/
+
+/* procfs File System */
+
+#ifdef CONFIG_FS_PROCFS
+#  ifdef CONFIG_NSH_PROC_MOUNTPOINT
+#    define NRF52_PROCFS_MOUNTPOINT CONFIG_NSH_PROC_MOUNTPOINT
+#  else
+#    define NRF52_PROCFS_MOUNTPOINT "/proc"
+#  endif
+#endif
+
 /* LED definitions **********************************************************/
 
 /* Definitions to configure LED GPIO as outputs */
diff --git a/boards/arm/nrf52/nrf52840-dongle/src/nrf52_bringup.c b/boards/arm/nrf52/nrf52840-dongle/src/nrf52_bringup.c
index 1ad015a417..fbcf6b4475 100644
--- a/boards/arm/nrf52/nrf52840-dongle/src/nrf52_bringup.c
+++ b/boards/arm/nrf52/nrf52840-dongle/src/nrf52_bringup.c
@@ -31,6 +31,10 @@
 #  include <nuttx/leds/userled.h>
 #endif
 
+#ifdef CONFIG_NRF52_RADIO_IEEE802154
+#  include "nrf52_ieee802154.h"
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -53,6 +57,17 @@ int nrf52_bringup(void)
 {
   int ret;
 
+#ifdef CONFIG_FS_PROCFS
+  /* Mount the procfs file system */
+
+  ret = nx_mount(NULL, NRF52_PROCFS_MOUNTPOINT, "procfs", 0, NULL);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: Failed to mount the PROC filesystem: %d\n",  ret);
+    }
+#endif /* CONFIG_FS_PROCFS */
+
 #ifdef CONFIG_USERLED
   /* Register the LED driver */
 
@@ -63,6 +78,15 @@ int nrf52_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_NRF52_RADIO_IEEE802154
+  ret = nrf52_ieee802154_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize IEE802154 radio: %d\n",
+             ret);
+    }
+#endif
+
   UNUSED(ret);
   return OK;
 }
diff --git a/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_6lowpan/defconfig b/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_6lowpan/defconfig
new file mode 100644
index 0000000000..473979b070
--- /dev/null
+++ b/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_6lowpan/defconfig
@@ -0,0 +1,81 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_ARCH_FPU is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="nrf9160-dk-nrf52"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_NRF9160_DK_NRF52=y
+CONFIG_ARCH_CHIP="nrf52"
+CONFIG_ARCH_CHIP_NRF52840=y
+CONFIG_ARCH_CHIP_NRF52=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_STDARG_H=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=5500
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DRIVERS_IEEE802154=y
+CONFIG_DRIVERS_WIRELESS=y
+CONFIG_EXAMPLES_NETTEST=y
+CONFIG_EXAMPLES_NETTEST_DEVNAME="wpan0"
+CONFIG_EXAMPLES_NETTEST_SERVER_PORTNO=61616
+CONFIG_EXAMPLES_NETTEST_TARGET2=y
+CONFIG_EXAMPLES_UDP=y
+CONFIG_EXAMPLES_UDP_CLIENT_PORTNO=61617
+CONFIG_EXAMPLES_UDP_DEVNAME="wpan0"
+CONFIG_EXAMPLES_UDP_IPv6=y
+CONFIG_EXAMPLES_UDP_SERVER_PORTNO=61616
+CONFIG_EXAMPLES_UDP_TARGET2=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_FS_PROCFS=y
+CONFIG_IEEE802154_I8SAK=y
+CONFIG_IEEE802154_MAC=y
+CONFIG_IEEE802154_MACDEV=y
+CONFIG_IEEE802154_NETDEV=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_MAC802154_NTXDESC=36
+CONFIG_MM_REGIONS=2
+CONFIG_NET=y
+CONFIG_NETDEV_HPWORK_THREAD=y
+CONFIG_NETDEV_LATEINIT=y
+CONFIG_NETDEV_STATISTICS=y
+CONFIG_NETDEV_WIRELESS_IOCTL=y
+CONFIG_NETINIT_NETLOCAL=y
+CONFIG_NETINIT_NOMAC=y
+CONFIG_NETUTILS_TELNETD=y
+CONFIG_NET_6LOWPAN=y
+CONFIG_NET_BROADCAST=y
+CONFIG_NET_IPv6=y
+CONFIG_NET_SOCKOPTS=y
+CONFIG_NET_STATISTICS=y
+CONFIG_NET_TCP=y
+CONFIG_NET_TCPBACKLOG=y
+CONFIG_NET_TCP_WRITE_BUFFERS=y
+CONFIG_NET_UDP=y
+CONFIG_NRF52_HFCLK_XTAL=y
+CONFIG_NRF52_RADIO=y
+CONFIG_NRF52_RADIO_IEEE802154=y
+CONFIG_NRF52_UART0=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_PROMPT_STRING="nsh-nrf91> "
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=262144
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_TELNET_CLIENT=y
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_IEEE802154=y
diff --git a/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_mac/defconfig b/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_mac/defconfig
new file mode 100644
index 0000000000..1725e9d4d4
--- /dev/null
+++ b/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_mac/defconfig
@@ -0,0 +1,56 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_ARCH_FPU is not set
+# CONFIG_NSH_DISABLE_IFCONFIG is not set
+# CONFIG_NSH_DISABLE_PS is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="nrf9160-dk-nrf52"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_NRF9160_DK_NRF52=y
+CONFIG_ARCH_CHIP="nrf52"
+CONFIG_ARCH_CHIP_NRF52840=y
+CONFIG_ARCH_CHIP_NRF52=y
+CONFIG_ARCH_PERF_EVENTS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_STDARG_H=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=5500
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DRIVERS_IEEE802154=y
+CONFIG_DRIVERS_WIRELESS=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_IEEE802154_I8SAK=y
+CONFIG_IEEE802154_MAC=y
+CONFIG_IEEE802154_MACDEV=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_MM_REGIONS=2
+CONFIG_NRF52_HFCLK_XTAL=y
+CONFIG_NRF52_RADIO=y
+CONFIG_NRF52_RADIO_IEEE802154=y
+CONFIG_NRF52_UART0=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_PROMPT_STRING="nsh-nrf91> "
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=262144
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_COLORATION=y
+CONFIG_STACK_USAGE=y
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_IEEE802154=y
diff --git a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c b/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c
index d5bb51e644..095fb9d496 100644
--- a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c
+++ b/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c
@@ -27,6 +27,14 @@
 #include <sys/types.h>
 #include <syslog.h>
 
+#include <nuttx/fs/fs.h>
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154
+#  include "nrf52_ieee802154.h"
+#endif
+
+#include "nrf9160-dk-nrf52.h"
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -49,6 +57,26 @@ int nrf52_bringup(void)
 {
   int ret;
 
+#ifdef CONFIG_FS_PROCFS
+  /* Mount the procfs file system */
+
+  ret = nx_mount(NULL, NRF52_PROCFS_MOUNTPOINT, "procfs", 0, NULL);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR,
+             "ERROR: Failed to mount the PROC filesystem: %d\n",  ret);
+    }
+#endif /* CONFIG_FS_PROCFS */
+
+#ifdef CONFIG_NRF52_RADIO_IEEE802154
+  ret = nrf52_ieee802154_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize IEE802154 radio: %d\n",
+             ret);
+    }
+#endif
+
   UNUSED(ret);
   return OK;
 }
diff --git a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h b/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h
index 82fe34c862..95744c9424 100644
--- a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h
+++ b/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h
@@ -34,6 +34,18 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+/* Configuration ************************************************************/
+
+/* procfs File System */
+
+#ifdef CONFIG_FS_PROCFS
+#  ifdef CONFIG_NSH_PROC_MOUNTPOINT
+#    define NRF52_PROCFS_MOUNTPOINT CONFIG_NSH_PROC_MOUNTPOINT
+#  else
+#    define NRF52_PROCFS_MOUNTPOINT "/proc"
+#  endif
+#endif
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h
index 2a998d035c..35f345ab23 100644
--- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h
+++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h
@@ -219,6 +219,7 @@
 
 #define IEEE802154_MAX_PHY_PACKET_SIZE        127
 #define IEEE802154_TURN_AROUND_TIME           12 /* symbol periods*/
+#define IEEE802154_SYMBOL_US                  16 /* 16us */
 
 /* IEEE 802.15.4 MAC constants */
 
@@ -251,6 +252,11 @@
 #define IEEE802154_MAX_SIFS_FRAME_SIZE        18
 #define IEEE802154_MIN_CAP_LENGTH             440
 #define IEEE802154_UNIT_BACKOFF_PERIOD        20
+#define IEEE802154_LIFS_SYMBOLS               40
+#define IEEE802154_SIFS_SYMBOLS               12
+#define IEEE802154_ACKIFS_SYMBOLS             12
+#define IEEE802154_TIMESLOT_US                (16 * 60)
+#define IEEE802154_ACK_FRAME_SIZE             5  /* ACK length (FCF + Seq + FCS) */
 
 /* IEEE 802.15.4 MAC PIB Attribute Defaults */