You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/06/15 14:07:29 UTC

[incubator-nuttx] branch master updated (a607e62 -> b5c5948)

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

gnutt pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git.


    from a607e62  Include malloc.h instead of stdlib.h for mallinfo()
     new 55d9e5f  net: Add SocketCAN support
     new ff76ef0  s32k1xx: Added FlexCAN driver with SocketCAN support
     new 5f73dc8  Kinetis: Added FlexCAN driver with SocketCAN support
     new b5c5948  NXStyle fixes

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 arch/arm/src/kinetis/Kconfig                       |   94 +-
 arch/arm/src/kinetis/Make.defs                     |    7 +
 arch/arm/src/kinetis/hardware/kinetis_flexcan.h    |   79 +-
 arch/arm/src/kinetis/kinetis.h                     |   91 +-
 arch/arm/src/kinetis/kinetis_flexcan.c             | 1907 ++++++++++++++++++++
 arch/arm/src/s32k1xx/Kconfig                       |  164 ++
 arch/arm/src/s32k1xx/Make.defs                     |    8 +
 arch/arm/src/s32k1xx/hardware/s32k1xx_flexcan.h    |  103 +-
 arch/arm/src/s32k1xx/hardware/s32k1xx_ftfc.h       |  143 ++
 arch/arm/src/s32k1xx/s32k1xx_flexcan.c             | 1901 +++++++++++++++++++
 .../s32k1xx/{s32k1xx_rtc.h => s32k1xx_flexcan.h}   |   88 +-
 arch/arm/src/s32k1xx/s32k1xx_progmem.c             |  424 +++++
 .../arm/src/s32k1xx/s32k1xx_progmem.h              |  102 +-
 arch/arm/src/s32k1xx/s32k1xx_rtc.c                 |   85 +-
 arch/arm/src/s32k1xx/s32k1xx_rtc.h                 |    8 -
 arch/arm/src/s32k1xx/s32k1xx_start.c               |    8 +
 .../rddrone-uavcan144/src/s32k1xx_bringup.c        |   11 +
 .../rddrone-uavcan144/src/s32k1xx_clockconfig.c    |    2 +-
 .../rddrone-uavcan146/configs/nsh/defconfig        |   29 +
 .../arm/s32k1xx/rddrone-uavcan146/include/board.h  |   12 +-
 .../rddrone-uavcan146/src/rddrone-uavcan146.h      |   10 +-
 .../rddrone-uavcan146/src/s32k1xx_bringup.c        |   11 +
 .../rddrone-uavcan146/src/s32k1xx_buttons.c        |   17 +-
 .../rddrone-uavcan146/src/s32k1xx_clockconfig.c    |    2 +-
 .../rddrone-uavcan146/src/s32k1xx_periphclocks.c   |   12 +-
 .../arm/s32k1xx/s32k118evb/src/s32k1xx_bringup.c   |   11 +
 .../arm/s32k1xx/s32k144evb/src/s32k1xx_bringup.c   |   11 +
 .../s32k1xx/s32k144evb/src/s32k1xx_clockconfig.c   |    2 +-
 .../arm/s32k1xx/s32k146evb/src/s32k1xx_bringup.c   |   11 +
 .../s32k1xx/s32k146evb/src/s32k1xx_clockconfig.c   |    2 +-
 boards/arm/s32k1xx/s32k148evb/include/board.h      |    8 +
 .../s32k1xx/s32k148evb/src/s32k1xx_clockconfig.c   |    2 +-
 fs/vfs/fs_write.c                                  |    9 +-
 include/net/if.h                                   |   51 +-
 include/netpacket/can.h                            |  140 ++
 include/nuttx/can.h                                |  319 ++++
 include/nuttx/can/error.h                          |  129 ++
 include/nuttx/mm/iob.h                             |   10 +-
 include/nuttx/net/can.h                            |  122 ++
 include/nuttx/net/ioctl.h                          |    8 +
 include/nuttx/net/net.h                            |   31 +-
 include/nuttx/wqueue.h                             |    3 +-
 include/sys/socket.h                               |   13 +
 libs/libc/net/lib_recvmsg.c                        |    7 +-
 libs/libc/net/lib_sendmsg.c                        |    4 +-
 net/Kconfig                                        |    1 +
 net/Makefile                                       |    1 +
 net/bluetooth/bluetooth_sockif.c                   |   38 +-
 net/can/Kconfig                                    |   97 +
 net/can/Make.defs                                  |   48 +
 net/can/can.h                                      |  385 ++++
 net/can/can_callback.c                             |  242 +++
 net/can/can_conn.c                                 |  223 +++
 net/can/can_getsockopt.c                           |  220 +++
 net/can/can_input.c                                |  204 +++
 .../net/lib_recvmsg.c => net/can/can_notifier.c    |   56 +-
 net/can/can_poll.c                                 |   88 +
 net/can/can_recvfrom.c                             |  838 +++++++++
 net/can/can_send.c                                 |  441 +++++
 net/can/can_setsockopt.c                           |  177 ++
 net/{netlink/netlink_sockif.c => can/can_sockif.c} |  723 ++++----
 net/devif/Make.defs                                |    4 +
 net/devif/devif.h                                  |  112 +-
 .../devif/devif_cansend.c                          |  112 +-
 net/devif/devif_poll.c                             |   48 +
 net/icmp/icmp_sockif.c                             |   18 +-
 net/icmpv6/icmpv6_sockif.c                         |   32 +-
 net/ieee802154/ieee802154_sockif.c                 |   49 +-
 net/inet/inet_sockif.c                             |    4 +
 net/local/local_sendpacket.c                       |    1 +
 net/local/local_sockif.c                           |   14 +-
 net/net_initialize.c                               |    7 +
 net/netdev/Kconfig                                 |    8 +
 net/netdev/netdev_ioctl.c                          |   48 +
 net/netdev/netdev_register.c                       |   12 +
 net/netlink/netlink_sockif.c                       |    4 +
 net/pkt/pkt_sockif.c                               |    4 +
 net/socket/Kconfig                                 |   24 +
 net/socket/Make.defs                               |    6 +
 net/socket/getsockopt.c                            |   19 +
 net/socket/net_sockif.c                            |    7 +
 net/socket/recvmsg.c                               |  244 +++
 net/socket/sendmsg.c                               |  243 +++
 net/socket/setsockopt.c                            |   29 +
 net/socket/socket.h                                |    2 +-
 net/utils/net_lock.c                               |   51 +
 86 files changed, 10248 insertions(+), 847 deletions(-)
 create mode 100644 arch/arm/src/kinetis/kinetis_flexcan.c
 create mode 100644 arch/arm/src/s32k1xx/hardware/s32k1xx_ftfc.h
 create mode 100644 arch/arm/src/s32k1xx/s32k1xx_flexcan.c
 copy arch/arm/src/s32k1xx/{s32k1xx_rtc.h => s32k1xx_flexcan.h} (63%)
 create mode 100644 arch/arm/src/s32k1xx/s32k1xx_progmem.c
 copy boards/arm/s32k1xx/s32k118evb/src/s32k1xx_bringup.c => arch/arm/src/s32k1xx/s32k1xx_progmem.h (59%)
 create mode 100644 include/netpacket/can.h
 create mode 100644 include/nuttx/can.h
 create mode 100644 include/nuttx/can/error.h
 create mode 100644 include/nuttx/net/can.h
 create mode 100644 net/can/Kconfig
 create mode 100644 net/can/Make.defs
 create mode 100644 net/can/can.h
 create mode 100644 net/can/can_callback.c
 create mode 100644 net/can/can_conn.c
 create mode 100644 net/can/can_getsockopt.c
 create mode 100644 net/can/can_input.c
 copy libs/libc/net/lib_recvmsg.c => net/can/can_notifier.c (70%)
 create mode 100644 net/can/can_poll.c
 create mode 100644 net/can/can_recvfrom.c
 create mode 100644 net/can/can_send.c
 create mode 100644 net/can/can_setsockopt.c
 copy net/{netlink/netlink_sockif.c => can/can_sockif.c} (52%)
 copy boards/arm/s32k1xx/rddrone-uavcan146/src/rddrone-uavcan146.h => net/devif/devif_cansend.c (58%)
 create mode 100644 net/socket/recvmsg.c
 create mode 100644 net/socket/sendmsg.c


[incubator-nuttx] 04/04: NXStyle fixes

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit b5c5948e1c4635388e1b47811a1d9789a70c4c7f
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Mon Jun 15 14:09:26 2020 +0200

    NXStyle fixes
---
 arch/arm/src/kinetis/hardware/kinetis_flexcan.h    | 49 ++++++++++++----------
 arch/arm/src/kinetis/kinetis_flexcan.c             | 28 ++++++-------
 arch/arm/src/s32k1xx/s32k1xx_flexcan.c             | 28 ++++++-------
 .../arm/s32k1xx/rddrone-uavcan146/include/board.h  |  2 +-
 include/net/if.h                                   | 32 +++++++-------
 net/ieee802154/ieee802154_sockif.c                 |  2 +-
 net/local/local_sockif.c                           |  2 +-
 net/netdev/netdev_ioctl.c                          |  4 +-
 8 files changed, 75 insertions(+), 72 deletions(-)

diff --git a/arch/arm/src/kinetis/hardware/kinetis_flexcan.h b/arch/arm/src/kinetis/hardware/kinetis_flexcan.h
index a7b198e..c47daf7 100644
--- a/arch/arm/src/kinetis/hardware/kinetis_flexcan.h
+++ b/arch/arm/src/kinetis/hardware/kinetis_flexcan.h
@@ -71,22 +71,22 @@
 #define KINETIS_CAN_MB_OFFSET       0x0080 /* CAN MB register */
 
 #define KINETIS_CAN_RXIMR_OFFSET(n) (0x0880+((n)<<2)) /* Rn Individual Mask Registers */
-#define KINETIS_CAN_RXIMR0_OFFSET   0x0880 /* R0 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR1_OFFSET   0x0884 /* R1 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR2_OFFSET   0x0888 /* R2 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR3_OFFSET   0x088c /* R3 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR4_OFFSET   0x0890 /* R4 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR5_OFFSET   0x0894 /* R5 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR6_OFFSET   0x0898 /* R6 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR7_OFFSET   0x089c /* R7 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR8_OFFSET   0x08a0 /* R8 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR9_OFFSET   0x08a4 /* R9 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR10_OFFSET  0x08a8 /* R10 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR11_OFFSET  0x08ac /* R11 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR12_OFFSET  0x08b0 /* R12 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR13_OFFSET  0x08b4 /* R13 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR14_OFFSET  0x08b8 /* R14 Individual Mask Registers */
-#define KINETIS_CAN_RXIMR15_OFFSET  0x08bc /* R15 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR0_OFFSET   0x0880            /* R0 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR1_OFFSET   0x0884            /* R1 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR2_OFFSET   0x0888            /* R2 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR3_OFFSET   0x088c            /* R3 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR4_OFFSET   0x0890            /* R4 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR5_OFFSET   0x0894            /* R5 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR6_OFFSET   0x0898            /* R6 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR7_OFFSET   0x089c            /* R7 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR8_OFFSET   0x08a0            /* R8 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR9_OFFSET   0x08a4            /* R9 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR10_OFFSET  0x08a8            /* R10 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR11_OFFSET  0x08ac            /* R11 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR12_OFFSET  0x08b0            /* R12 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR13_OFFSET  0x08b4            /* R13 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR14_OFFSET  0x08b8            /* R14 Individual Mask Registers */
+#define KINETIS_CAN_RXIMR15_OFFSET  0x08bc            /* R15 Individual Mask Registers */
 
 /* Register Addresses *******************************************************************************/
 
@@ -178,16 +178,16 @@
 #define CAN_CTRL1_CLKSRC           (1 << 13) /* Bit 13: CAN Engine Clock Source */
 #define CAN_CTRL1_ERRMSK           (1 << 14) /* Bit 14: Error Mask */
 #define CAN_CTRL1_BOFFMSK          (1 << 15) /* Bit 15: Bus Off Mask */
-#define CAN_CTRL1_PSEG2_SHIFT      (16)       /* Bits 16-18: Phase Segment 2 */
+#define CAN_CTRL1_PSEG2_SHIFT      (16)      /* Bits 16-18: Phase Segment 2 */
 #define CAN_CTRL1_PSEG2_MASK       (7 << CAN_CTRL1_PSEG2_SHIFT)
 #define CAN_CTRL1_PSEG2(x)         (((uint32_t)(((uint32_t)(x)) << 16)) & 0x70000)
-#define CAN_CTRL1_PSEG1_SHIFT      (19)       /* Bits 19-21: Phase Segment 1 */
+#define CAN_CTRL1_PSEG1_SHIFT      (19)      /* Bits 19-21: Phase Segment 1 */
 #define CAN_CTRL1_PSEG1_MASK       (7 << CAN_CTRL1_PSEG1_SHIFT)
 #define CAN_CTRL1_PSEG1(x)         (((uint32_t)(((uint32_t)(x)) << 19)) & 0x380000)
-#define CAN_CTRL1_RJW_SHIFT        (22)       /* Bits 22-23: Resync Jump Width */
+#define CAN_CTRL1_RJW_SHIFT        (22)      /* Bits 22-23: Resync Jump Width */
 #define CAN_CTRL1_RJW_MASK         (3 << CAN_CTRL1_RJW_SHIFT)
 #define CAN_CTRL1_RJW(x)           (((uint32_t)(((uint32_t)(x)) << 22)) & 0xC00000)
-#define CAN_CTRL1_PRESDIV_SHIFT    (24)       /* Bits 24-31: Prescaler Division Factor */
+#define CAN_CTRL1_PRESDIV_SHIFT    (24)      /* Bits 24-31: Prescaler Division Factor */
 #define CAN_CTRL1_PRESDIV_MASK     (0xff << CAN_CTRL1_PRESDIV_SHIFT)
 #define CAN_CTRL1_PRESDIV(x)       (((uint32_t)(((uint32_t)(x)) << 24)) & 0xFF000000)
 
@@ -225,9 +225,12 @@
 #define CAN_ESR1_RX                (1 << 3)  /* Bit 3:  FlexCAN in Reception */
 #define CAN_ESR1_FLTCONF_SHIFT     (4)       /* Bits 4-5: Fault Confinement State */
 #define CAN_ESR1_FLTCONF_MASK      (3 << CAN_ESR1_FLTCONF_SHIFT)
-#  define CAN_ESR1_FLTCONF_ACTV    (0 << CAN_ESR1_FLTCONF_SHIFT) /* Error Active */
-#  define CAN_ESR1_FLTCONF_PASV    (1 << CAN_ESR1_FLTCONF_SHIFT) /* Error Passive */
-#  define CAN_ESR1_FLTCONF_OFF     (2 << CAN_ESR1_FLTCONF_SHIFT) /* Bus Off */
+#  define CAN_ESR1_FLTCONF_ACTV    (0 << CAN_ESR1_FLTCONF_SHIFT)
+                                             /* Error Active */
+#  define CAN_ESR1_FLTCONF_PASV    (1 << CAN_ESR1_FLTCONF_SHIFT)
+                                             /* Error Passive */
+#  define CAN_ESR1_FLTCONF_OFF     (2 << CAN_ESR1_FLTCONF_SHIFT)
+                                             /* Bus Off */
 #define CAN_ESR1_TX                (1 << 6)  /* Bit 6:  FlexCAN in Transmission */
 #define CAN_ESR1_IDLE              (1 << 7)  /* Bit 7:  CAN bus is in IDLE state */
 #define CAN_ESR1_RXWRN             (1 << 8)  /* Bit 8:  Rx Error Warning */
diff --git a/arch/arm/src/kinetis/kinetis_flexcan.c b/arch/arm/src/kinetis/kinetis_flexcan.c
index 1256f54..9e4eaa7 100644
--- a/arch/arm/src/kinetis/kinetis_flexcan.c
+++ b/arch/arm/src/kinetis/kinetis_flexcan.c
@@ -1517,21 +1517,21 @@ static int kinetis_initialize(struct kinetis_driver_s *priv)
   regval  = getreg32(priv->base + KINETIS_CAN_CTRL1_OFFSET);
   regval |= CAN_CTRL1_PRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
             CAN_CTRL1_PROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
-            CAN_CTRL1_PSEG1(priv->arbi_timing.pseg1) |   /* Phase buffer segment 1 */
-            CAN_CTRL1_PSEG2(priv->arbi_timing.pseg2) |   /* Phase buffer segment 2 */
-            CAN_CTRL1_RJW(1);      /* Resynchronization jump width */
+            CAN_CTRL1_PSEG1(priv->arbi_timing.pseg1) |     /* Phase buffer segment 1 */
+            CAN_CTRL1_PSEG2(priv->arbi_timing.pseg2) |     /* Phase buffer segment 2 */
+            CAN_CTRL1_RJW(1);                              /* Resynchronization jump width */
   putreg32(regval, priv->base + KINETIS_CAN_CTRL1_OFFSET);
 
 #else
   regval  = getreg32(priv->base + KINETIS_CAN_CBT_OFFSET);
-  regval |= CAN_CBT_BTF |         /* Enable extended bit timing
-                                   * configurations for CAN-FD for setting up
-                                   * separately nominal and data phase */
+            regval |= CAN_CBT_BTF |                       /* Enable extended bit timing
+                                                           * configurations for CAN-FD for setting up
+                                                           * separately nominal and data phase */
             CAN_CBT_EPRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
             CAN_CBT_EPROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
-            CAN_CBT_EPSEG1(priv->arbi_timing.pseg1) |   /* Phase buffer segment 1 */
-            CAN_CBT_EPSEG2(priv->arbi_timing.pseg2) |   /* Phase buffer segment 2 */
-            CAN_CBT_ERJW(1);      /* Resynchronization jump width */
+            CAN_CBT_EPSEG1(priv->arbi_timing.pseg1) |     /* Phase buffer segment 1 */
+            CAN_CBT_EPSEG2(priv->arbi_timing.pseg2) |     /* Phase buffer segment 2 */
+            CAN_CBT_ERJW(1);                              /* Resynchronization jump width */
   putreg32(regval, priv->base + KINETIS_CAN_CBT_OFFSET);
 
   /* Enable CAN FD feature */
@@ -1542,11 +1542,11 @@ static int kinetis_initialize(struct kinetis_driver_s *priv)
 
   regval  = getreg32(priv->base + KINETIS_CAN_FDCBT_OFFSET);
   regval |= CAN_FDCBT_FPRESDIV(priv->data_timing.presdiv) |  /* Prescaler divisor factor of 1 */
-            CAN_FDCBT_FPROPSEG(priv->data_timing.propseg) | /* Propagation
-                                                             * segment (only register that doesn't add 1) */
-            CAN_FDCBT_FPSEG1(priv->data_timing.pseg1) |    /* Phase buffer segment 1 */
-            CAN_FDCBT_FPSEG2(priv->data_timing.pseg2) |    /* Phase buffer segment 2 */
-            CAN_FDCBT_FRJW(priv->data_timing.pseg2);       /* Resynchorinzation jump width same as PSEG2 */
+            CAN_FDCBT_FPROPSEG(priv->data_timing.propseg) |  /* Propagation
+                                                              * segment (only register that doesn't add 1) */
+            CAN_FDCBT_FPSEG1(priv->data_timing.pseg1) |      /* Phase buffer segment 1 */
+            CAN_FDCBT_FPSEG2(priv->data_timing.pseg2) |      /* Phase buffer segment 2 */
+            CAN_FDCBT_FRJW(priv->data_timing.pseg2);         /* Resynchorinzation jump width same as PSEG2 */
   putreg32(regval, priv->base + KINETIS_CAN_FDCBT_OFFSET);
 
   /* Additional CAN-FD configurations */
diff --git a/arch/arm/src/s32k1xx/s32k1xx_flexcan.c b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
index d09dceb..cec80ae 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
+++ b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
@@ -1518,21 +1518,21 @@ static int s32k1xx_initialize(struct s32k1xx_driver_s *priv)
   regval  = getreg32(priv->base + S32K1XX_CAN_CTRL1_OFFSET);
   regval |= CAN_CTRL1_PRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
             CAN_CTRL1_PROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
-            CAN_CTRL1_PSEG1(priv->arbi_timing.pseg1) |   /* Phase buffer segment 1 */
-            CAN_CTRL1_PSEG2(priv->arbi_timing.pseg2) |   /* Phase buffer segment 2 */
-            CAN_CTRL1_RJW(1);      /* Resynchronization jump width */
+            CAN_CTRL1_PSEG1(priv->arbi_timing.pseg1) |     /* Phase buffer segment 1 */
+            CAN_CTRL1_PSEG2(priv->arbi_timing.pseg2) |     /* Phase buffer segment 2 */
+            CAN_CTRL1_RJW(1);                              /* Resynchronization jump width */
   putreg32(regval, priv->base + S32K1XX_CAN_CTRL1_OFFSET);
 
 #else
   regval  = getreg32(priv->base + S32K1XX_CAN_CBT_OFFSET);
-  regval |= CAN_CBT_BTF |         /* Enable extended bit timing
-                                   * configurations for CAN-FD for setting up
-                                   * separately nominal and data phase */
+            regval |= CAN_CBT_BTF |                       /* Enable extended bit timing
+                                                           * configurations for CAN-FD for setting up
+                                                           * separately nominal and data phase */
             CAN_CBT_EPRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
             CAN_CBT_EPROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
-            CAN_CBT_EPSEG1(priv->arbi_timing.pseg1) |   /* Phase buffer segment 1 */
-            CAN_CBT_EPSEG2(priv->arbi_timing.pseg2) |   /* Phase buffer segment 2 */
-            CAN_CBT_ERJW(1);      /* Resynchronization jump width */
+            CAN_CBT_EPSEG1(priv->arbi_timing.pseg1) |     /* Phase buffer segment 1 */
+            CAN_CBT_EPSEG2(priv->arbi_timing.pseg2) |     /* Phase buffer segment 2 */
+            CAN_CBT_ERJW(1);                              /* Resynchronization jump width */
   putreg32(regval, priv->base + S32K1XX_CAN_CBT_OFFSET);
 
   /* Enable CAN FD feature */
@@ -1543,11 +1543,11 @@ static int s32k1xx_initialize(struct s32k1xx_driver_s *priv)
 
   regval  = getreg32(priv->base + S32K1XX_CAN_FDCBT_OFFSET);
   regval |= CAN_FDCBT_FPRESDIV(priv->data_timing.presdiv) |  /* Prescaler divisor factor of 1 */
-            CAN_FDCBT_FPROPSEG(priv->data_timing.propseg) | /* Propagation
-                                                             * segment (only register that doesn't add 1) */
-            CAN_FDCBT_FPSEG1(priv->data_timing.pseg1) |    /* Phase buffer segment 1 */
-            CAN_FDCBT_FPSEG2(priv->data_timing.pseg2) |    /* Phase buffer segment 2 */
-            CAN_FDCBT_FRJW(priv->data_timing.pseg2);       /* Resynchorinzation jump width same as PSEG2 */
+            CAN_FDCBT_FPROPSEG(priv->data_timing.propseg) |  /* Propagation
+                                                              * segment (only register that doesn't add 1) */
+            CAN_FDCBT_FPSEG1(priv->data_timing.pseg1) |      /* Phase buffer segment 1 */
+            CAN_FDCBT_FPSEG2(priv->data_timing.pseg2) |      /* Phase buffer segment 2 */
+            CAN_FDCBT_FRJW(priv->data_timing.pseg2);         /* Resynchorinzation jump width same as PSEG2 */
   putreg32(regval, priv->base + S32K1XX_CAN_FDCBT_OFFSET);
 
   /* Additional CAN-FD configurations */
diff --git a/boards/arm/s32k1xx/rddrone-uavcan146/include/board.h b/boards/arm/s32k1xx/rddrone-uavcan146/include/board.h
index fbe1f79..38d177a 100644
--- a/boards/arm/s32k1xx/rddrone-uavcan146/include/board.h
+++ b/boards/arm/s32k1xx/rddrone-uavcan146/include/board.h
@@ -148,7 +148,7 @@
 /* I2C selections ***********************************************************/
 
 #define PIN_LPI2C0_SCL   PIN_LPI2C0_SCL_2   /* PTA3 */
-#define PIN_LPI2C0_SDA	 PIN_LPI2C0_SDA_2   /* PTA2 */
+#define PIN_LPI2C0_SDA   PIN_LPI2C0_SDA_2   /* PTA2 */
 
 /* CAN selections ***********************************************************/
 #define PIN_CAN0_TX      PIN_CAN0_TX_4      /* PTE5 */
diff --git a/include/net/if.h b/include/net/if.h
index 0332ab7..cdca2d3 100644
--- a/include/net/if.h
+++ b/include/net/if.h
@@ -174,14 +174,14 @@ struct lifreq
   } lifr_ifru;
 };
 
-#define lifr_addr             lifr_ifru.lifru_addr      /* IP address */
-#define lifr_dstaddr          lifr_ifru.lifru_dstaddr   /* P-to-P Address */
-#define lifr_broadaddr        lifr_ifru.lifru_broadaddr /* Broadcast address */
-#define lifr_netmask          lifr_ifru.lifru_netmask   /* Interface net mask */
-#define lifr_hwaddr           lifr_ifru.lifru_hwaddr    /* MAC address */
-#define lifr_mtu              lifr_ifru.lifru_mtu       /* MTU */
-#define lifr_count            lifr_ifru.lifru_count     /* Number of devices */
-#define lifr_flags            lifr_ifru.lifru_flags     /* interface flags */
+#define lifr_addr             lifr_ifru.lifru_addr             /* IP address */
+#define lifr_dstaddr          lifr_ifru.lifru_dstaddr          /* P-to-P Address */
+#define lifr_broadaddr        lifr_ifru.lifru_broadaddr        /* Broadcast address */
+#define lifr_netmask          lifr_ifru.lifru_netmask          /* Interface net mask */
+#define lifr_hwaddr           lifr_ifru.lifru_hwaddr           /* MAC address */
+#define lifr_mtu              lifr_ifru.lifru_mtu              /* MTU */
+#define lifr_count            lifr_ifru.lifru_count            /* Number of devices */
+#define lifr_flags            lifr_ifru.lifru_flags            /* interface flags */
 #define lifr_mii_notify_pid   lifr_ifru.llfru_mii_notify.pid   /* PID to be notified */
 #define lifr_mii_notify_event lifr_ifru.llfru_mii_notify.event /* Describes notification */
 #define lifr_mii_phy_id       lifr_ifru.lifru_mii_data.phy_id  /* PHY device address */
@@ -228,14 +228,14 @@ struct ifreq
   } ifr_ifru;
 };
 
-#define ifr_addr              ifr_ifru.ifru_addr        /* IP address */
-#define ifr_dstaddr           ifr_ifru.ifru_dstaddr     /* P-to-P Address */
-#define ifr_broadaddr         ifr_ifru.ifru_broadaddr   /* Broadcast address */
-#define ifr_netmask           ifr_ifru.ifru_netmask     /* Interface net mask */
-#define ifr_hwaddr            ifr_ifru.ifru_hwaddr      /* MAC address */
-#define ifr_mtu               ifr_ifru.ifru_mtu         /* MTU */
-#define ifr_count             ifr_ifru.ifru_count       /* Number of devices */
-#define ifr_flags             ifr_ifru.ifru_flags       /* interface flags */
+#define ifr_addr              ifr_ifru.ifru_addr             /* IP address */
+#define ifr_dstaddr           ifr_ifru.ifru_dstaddr          /* P-to-P Address */
+#define ifr_broadaddr         ifr_ifru.ifru_broadaddr        /* Broadcast address */
+#define ifr_netmask           ifr_ifru.ifru_netmask          /* Interface net mask */
+#define ifr_hwaddr            ifr_ifru.ifru_hwaddr           /* MAC address */
+#define ifr_mtu               ifr_ifru.ifru_mtu              /* MTU */
+#define ifr_count             ifr_ifru.ifru_count            /* Number of devices */
+#define ifr_flags             ifr_ifru.ifru_flags            /* interface flags */
 #define ifr_mii_notify_pid    ifr_ifru.ifru_mii_notify.pid   /* PID to be notified */
 #define ifr_mii_notify_event  ifr_ifru.ifru_mii_notify.event /* Describes notification */
 #define ifr_mii_phy_id        ifr_ifru.ifru_mii_data.phy_id  /* PHY device address */
diff --git a/net/ieee802154/ieee802154_sockif.c b/net/ieee802154/ieee802154_sockif.c
index eb5d6e5..1ca6f0b 100644
--- a/net/ieee802154/ieee802154_sockif.c
+++ b/net/ieee802154/ieee802154_sockif.c
@@ -782,7 +782,7 @@ static int ieee802154_close(FAR struct socket *psock)
             {
               /* Yes... free the connection structure */
 
-              conn->crefs = 0;          /* No more references on the connection */
+              conn->crefs = 0;                      /* No more references on the connection */
               ieee802154_conn_free(psock->s_conn);  /* Free network resources */
             }
           else
diff --git a/net/local/local_sockif.c b/net/local/local_sockif.c
index c4f7531..6e9c7fa 100644
--- a/net/local/local_sockif.c
+++ b/net/local/local_sockif.c
@@ -390,7 +390,7 @@ static int local_getsockname(FAR struct socket *psock,
         }
       else /* conn->lctype = LOCAL_TYPE_PATHNAME */
         {
-          /* Get the full length of the socket name (including null terminator) */
+          /* Get the full length of the socket name (incl. null terminator) */
 
           int namelen = strlen(conn->lc_path) + 1;
 
diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c
index c169503..1ec51db 100644
--- a/net/netdev/netdev_ioctl.c
+++ b/net/netdev/netdev_ioctl.c
@@ -1109,7 +1109,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd,
 #ifdef CONFIG_NETDEV_IFINDEX
       case SIOCGIFNAME:  /* Get interface name */
         {
-          struct net_driver_s *dev = netdev_findbyindex(req->ifr_ifindex);
+          dev = netdev_findbyindex(req->ifr_ifindex);
           if (dev != NULL)
             {
               strncpy(req->ifr_name, dev->d_ifname, IFNAMSIZ);
@@ -1124,7 +1124,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd,
 
       case SIOCGIFINDEX:  /* Index to name mapping */
         {
-          struct net_driver_s *dev = netdev_findbyname(req->ifr_name);
+          dev = netdev_findbyname(req->ifr_name);
           if (dev != NULL)
             {
               req->ifr_ifindex = dev->d_ifindex;


[incubator-nuttx] 02/04: s32k1xx: Added FlexCAN driver with SocketCAN support

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit ff76ef0725fad91338831329a06fa4ff612ec856
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Mon Jun 15 10:24:23 2020 +0200

    s32k1xx: Added FlexCAN driver with SocketCAN support
---
 arch/arm/src/s32k1xx/Kconfig                       |  164 ++
 arch/arm/src/s32k1xx/Make.defs                     |    8 +
 arch/arm/src/s32k1xx/hardware/s32k1xx_flexcan.h    |  103 +-
 arch/arm/src/s32k1xx/hardware/s32k1xx_ftfc.h       |  143 ++
 arch/arm/src/s32k1xx/s32k1xx_flexcan.c             | 1901 ++++++++++++++++++++
 .../s32k1xx/{s32k1xx_rtc.h => s32k1xx_flexcan.h}   |   88 +-
 arch/arm/src/s32k1xx/s32k1xx_progmem.c             |  424 +++++
 .../arm/src/s32k1xx/s32k1xx_progmem.h              |  102 +-
 arch/arm/src/s32k1xx/s32k1xx_rtc.c                 |   85 +-
 arch/arm/src/s32k1xx/s32k1xx_rtc.h                 |    8 -
 arch/arm/src/s32k1xx/s32k1xx_start.c               |    8 +
 .../rddrone-uavcan144/src/s32k1xx_bringup.c        |   11 +
 .../rddrone-uavcan144/src/s32k1xx_clockconfig.c    |    2 +-
 .../rddrone-uavcan146/configs/nsh/defconfig        |   29 +
 .../arm/s32k1xx/rddrone-uavcan146/include/board.h  |   10 +
 .../rddrone-uavcan146/src/rddrone-uavcan146.h      |   10 +-
 .../rddrone-uavcan146/src/s32k1xx_bringup.c        |   11 +
 .../rddrone-uavcan146/src/s32k1xx_buttons.c        |   17 +-
 .../rddrone-uavcan146/src/s32k1xx_clockconfig.c    |    2 +-
 .../rddrone-uavcan146/src/s32k1xx_periphclocks.c   |   12 +-
 .../arm/s32k1xx/s32k118evb/src/s32k1xx_bringup.c   |   11 +
 .../arm/s32k1xx/s32k144evb/src/s32k1xx_bringup.c   |   11 +
 .../s32k1xx/s32k144evb/src/s32k1xx_clockconfig.c   |    2 +-
 .../arm/s32k1xx/s32k146evb/src/s32k1xx_bringup.c   |   11 +
 .../s32k1xx/s32k146evb/src/s32k1xx_clockconfig.c   |    2 +-
 boards/arm/s32k1xx/s32k148evb/include/board.h      |    8 +
 .../s32k1xx/s32k148evb/src/s32k1xx_clockconfig.c   |    2 +-
 27 files changed, 3011 insertions(+), 174 deletions(-)

diff --git a/arch/arm/src/s32k1xx/Kconfig b/arch/arm/src/s32k1xx/Kconfig
index 63e0cd9..e3ef9bd 100644
--- a/arch/arm/src/s32k1xx/Kconfig
+++ b/arch/arm/src/s32k1xx/Kconfig
@@ -27,6 +27,7 @@ config ARCH_CHIP_S32K118
 config ARCH_CHIP_S32K142
 	bool "S32K142"
 	select ARCH_CHIP_S32K14X
+	select S32K1XX_HAVE_FLEXCAN1
 	---help---
 		Cortex-M4F, 256Kb FLASH, 32Kb RAM incl. 4Kb FlexRAM
 
@@ -34,6 +35,8 @@ config ARCH_CHIP_S32K144
 	bool "S32K144"
 	select ARCH_CHIP_S32K14X
 	select S32K1XX_HAVE_LPSPI2
+	select S32K1XX_HAVE_FLEXCAN1
+	select S32K1XX_HAVE_FLEXCAN2
 	---help---
 		Cortex-M4F, 512Kb FLASH, 64Kb RAM incl. 4Kb FlexRAM
 
@@ -41,6 +44,8 @@ config ARCH_CHIP_S32K146
 	bool "S32K146"
 	select ARCH_CHIP_S32K14X
 	select S32K1XX_HAVE_LPSPI2
+	select S32K1XX_HAVE_FLEXCAN1
+	select S32K1XX_HAVE_FLEXCAN2
 	---help---
 		Cortex-M4F, 1Mb FLASH, 128Kb RAM incl. 4Kb FlexRAM
 
@@ -51,6 +56,8 @@ config ARCH_CHIP_S32K148
 	select S32K1XX_HAVE_LPI2C1
 	select S32K1XX_HAVE_LPSPI2
 	select S32K1XX_HAVE_SAI
+	select S32K1XX_HAVE_FLEXCAN1
+	select S32K1XX_HAVE_FLEXCAN2
 	---help---
 		Cortex-M4F, 2Mb FLASH, 256Kb RAM incl. 4Kb FlexRAM
 
@@ -110,6 +117,14 @@ config S32K1XX_HAVE_LPSPI1
 config S32K1XX_HAVE_LPSPI2
 	bool
 	default n
+	
+config S32K1XX_HAVE_FLEXCAN1
+	bool
+	default n
+	
+config S32K1XX_HAVE_FLEXCAN2
+	bool
+	default n
 
 config S32K1XX_HAVE_QSPI
 	bool
@@ -137,6 +152,11 @@ config S32K1XX_LPSPI
 	bool
 	default n
 
+config S32K1XX_FLEXCAN
+	bool
+	select NET_CAN_HAVE_CANFD
+	default n
+	
 # Peripheral Selection
 
 menu "S32K1XX Peripheral Selection"
@@ -150,6 +170,26 @@ config S32K1XX_ENET
 	default n
 	depends on S32K1XX_HAVE_ENET
 
+config S32K1XX_FLEXCAN0
+	bool "FLEXCAN0"
+	select S32K1XX_FLEXCAN
+	select NET_CAN_HAVE_TX_DEADLINE
+	default n
+	
+config S32K1XX_FLEXCAN1
+	bool "FLEXCAN1"
+	select S32K1XX_FLEXCAN
+	select NET_CAN_HAVE_TX_DEADLINE
+	default n
+	depends on S32K1XX_HAVE_FLEXCAN1
+	
+config S32K1XX_FLEXCAN2
+	bool "FLEXCAN2"
+	select S32K1XX_FLEXCAN
+	select NET_CAN_HAVE_TX_DEADLINE
+	default n
+	depends on S32K1XX_HAVE_FLEXCAN2
+
 menuconfig S32K1XX_LPI2C0
 	bool "LPI2C0"
 	default n
@@ -205,6 +245,15 @@ config S32K1XX_LPUART2
 config S32K1XX_RTC
 	bool "RTC"
 	default n
+	
+config S32K1XX_PROGMEM
+    bool PROGMEM
+    default n
+    select ARCH_HAVE_PROGMEM
+    depends on (ARCH_CHIP_S32K11X || (ARCH_CHIP_S32K14X && !ARCH_CHIP_S32K148) )
+    ---help---
+        Use the FlexNVM 32/64 KB of d-flash memory as a
+		Memory-Technology-Device (MTD).
 
 
 endmenu # S32K1XX Peripheral Selection
@@ -453,4 +502,119 @@ config S32K1XX_ENET_PHYINIT
 
 endmenu # S32K1XX_ENET
 
+menu "FLEXCAN0 Configuration"
+	depends on S32K1XX_FLEXCAN0
+
+config FLEXCAN0_BITRATE
+	int "CAN bitrate"
+	depends on !NET_CAN_CANFD
+	default 1000000
+	
+config FLEXCAN0_SAMPLEP
+	int "CAN sample point"
+	depends on !NET_CAN_CANFD
+	default 80
+	
+config FLEXCAN0_ARBI_BITRATE
+	int "CAN FD Arbitration phase bitrate"
+	depends on NET_CAN_CANFD
+	default 1000000
+	
+config FLEXCAN0_ARBI_SAMPLEP
+	int "CAN FD Arbitration phase sample point"
+	depends on NET_CAN_CANFD
+	default 80
+	
+config FLEXCAN0_DATA_BITRATE
+	int "CAN FD Arbitration phase bitrate"
+	depends on NET_CAN_CANFD
+	default 4000000
+	
+config FLEXCAN0_DATA_SAMPLEP
+	int "CAN FD Arbitration phase sample point"
+	depends on NET_CAN_CANFD
+	default 90
+	
+endmenu # S32K1XX_FLEXCAN0
+
+menu "FLEXCAN1 Configuration"
+	depends on S32K1XX_FLEXCAN1
+
+config FLEXCAN1_BITRATE
+	int "CAN bitrate"
+	depends on !NET_CAN_CANFD
+	default 1000000
+	
+config FLEXCAN1_SAMPLEP
+	int "CAN sample point"
+	depends on !NET_CAN_CANFD
+	default 80
+	
+config FLEXCAN1_ARBI_BITRATE
+	int "CAN FD Arbitration phase bitrate"
+	depends on NET_CAN_CANFD
+	default 1000000
+	
+config FLEXCAN1_ARBI_SAMPLEP
+	int "CAN FD Arbitration phase sample point"
+	depends on NET_CAN_CANFD
+	default 80
+	
+config FLEXCAN1_DATA_BITRATE
+	int "CAN FD Arbitration phase bitrate"
+	depends on NET_CAN_CANFD
+	default 4000000
+	
+config FLEXCAN1_DATA_SAMPLEP
+	int "CAN FD Arbitration phase sample point"
+	depends on NET_CAN_CANFD
+	default 90
+	
+endmenu # S32K1XX_FLEXCAN1
+
+menu "FLEXCAN2 Configuration"
+	depends on S32K1XX_FLEXCAN2
+
+config FLEXCAN2_BITRATE
+	int "CAN bitrate"
+	depends on !NET_CAN_CANFD
+	default 1000000
+	
+config FLEXCAN2_SAMPLEP
+	int "CAN sample point"
+	depends on !NET_CAN_CANFD
+	default 80
+	
+config FLEXCAN2_ARBI_BITRATE
+	int "CAN FD Arbitration phase bitrate"
+	depends on NET_CAN_CANFD
+	default 1000000
+	
+config FLEXCAN2_ARBI_SAMPLEP
+	int "CAN FD Arbitration phase sample point"
+	depends on NET_CAN_CANFD
+	default 80
+	
+config FLEXCAN2_DATA_BITRATE
+	int "CAN FD Arbitration phase bitrate"
+	depends on NET_CAN_CANFD
+	default 4000000
+	
+config FLEXCAN2_DATA_SAMPLEP
+	int "CAN FD Arbitration phase sample point"
+	depends on NET_CAN_CANFD
+	default 90
+	
+endmenu # S32K1XX_FLEXCAN0
+
+menu "PROGMEM Configuration"
+	depends on S32K1XX_PROGMEM
+	
+config PROGMEM_SIZE
+	int "Progmem size (KB)"
+	default 64 if ARCH_CHIP_S32K14X
+	default 32 if ARCH_CHIP_S32K11X
+
+endmenu
+
 endif # ARCH_CHIP_S32K1XX
diff --git a/arch/arm/src/s32k1xx/Make.defs b/arch/arm/src/s32k1xx/Make.defs
index a06fa86..05ac9dd 100644
--- a/arch/arm/src/s32k1xx/Make.defs
+++ b/arch/arm/src/s32k1xx/Make.defs
@@ -87,10 +87,18 @@ ifeq ($(CONFIG_S32K1XX_ENET),y)
 CHIP_CSRCS += s32k1xx_enet.c
 endif
 
+ifeq ($(CONFIG_S32K1XX_FLEXCAN),y)
+CHIP_CSRCS += s32k1xx_flexcan.c
+endif
+
 ifeq ($(CONFIG_S32K1XX_RTC),y)
 CHIP_CSRCS += s32k1xx_rtc.c
 endif
 
+ifeq ($(CONFIG_S32K1XX_PROGMEM),y)
+CHIP_CSRCS += s32k1xx_progmem.c
+endif
+
 # Source files specific to the ARM CPU family and to the S32K1xx chip family
 
 ifeq ($(CONFIG_ARCH_CHIP_S32K11X),y)
diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_flexcan.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_flexcan.h
index fa9c36f..aba9b7f 100644
--- a/arch/arm/src/s32k1xx/hardware/s32k1xx_flexcan.h
+++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_flexcan.h
@@ -66,8 +66,11 @@
 #define S32K1XX_CAN_CRCR_OFFSET       0x0044  /* CRC Register */
 #define S32K1XX_CAN_RXFGMASK_OFFSET   0x0048  /* Rx FIFO Global Mask Register */
 #define S32K1XX_CAN_RXFIR_OFFSET      0x004c  /* Rx FIFO Information Register */
+#define S32K1XX_CAN_CBT_OFFSET        0x0050  /* CAN Bit Timing register */
 
-#define S32K1XX_CAN_RXIMR_OFFSET(n)   (0x0880 + ((n) << 2)) /* Rn Individual Mask Registers */
+#define S32K1XX_CAN_MB_OFFSET         0x0080  /* CAN MB register */
+
+#define S32K1XX_CAN_RXIMR_OFFSET(n)   (0x0880 + ((n) << 2))
 #  define S32K1XX_CAN_RXIMR0_OFFSET   0x0880  /* R0 Individual Mask Registers */
 #  define S32K1XX_CAN_RXIMR1_OFFSET   0x0884  /* R1 Individual Mask Registers */
 #  define S32K1XX_CAN_RXIMR2_OFFSET   0x0888  /* R2 Individual Mask Registers */
@@ -141,7 +144,7 @@
 
 #define S32K1XX_CAN_FDCTRL_OFFSET     0x0c00  /* CAN FD Control register */
 #define S32K1XX_CAN_FDCBT_OFFSET      0x0c04  /* CAN FD Bit Timing register */
-#define S32K1XX_CAN_FDCRC_OFFSET      0x0c08 /* CAN FD CRC register */
+#define S32K1XX_CAN_FDCRC_OFFSET      0x0c08  /* CAN FD CRC register */
 
 /* Register Addresses ***************************************************************************************/
 
@@ -162,6 +165,11 @@
 #define S32K1XX_CAN0_CRCR             (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_CRCR_OFFSET)
 #define S32K1XX_CAN0_RXFGMASK         (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_RXFGMASK_OFFSET)
 #define S32K1XX_CAN0_RXFIR            (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_RXFIR_OFFSET)
+#define S32K1XX_CAN0_CBT              (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_CBT_OFFSET)
+#define S32K1XX_CAN0_MB               (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_MB_OFFSET)
+#define S32K1XX_CAN0_FDCTRL           (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_FDCTRL_OFFSET)
+#define S32K1XX_CAN0_FDCBT            (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_FDCBT_OFFSET)
+#define S32K1XX_CAN0_FDCRC            (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_FDCRC_OFFSET)
 
 #define S32K1XX_CAN0_RXIMR(n)         (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_RXIMR_OFFSET(n))
 #  define S32K1XX_CAN0_RXIMR0         (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_RXIMR0_OFFSET)
@@ -335,12 +343,15 @@
 #define CAN_MCR_MAXMB_MASK            (0x7f << CAN_MCR_MAXMB_SHIFT)
                                                 /* Bit 7:  Reserved */
 #define CAN_MCR_IDAM_SHIFT            (8)       /* Bits 8-9: ID Acceptance Mode */
+
 #define CAN_MCR_IDAM_MASK             (3 << CAN_MCR_IDAM_SHIFT)
 #  define CAN_MCR_IDAM_FMTA           (0 << CAN_MCR_IDAM_SHIFT) /* Format A: One full ID  */
 #  define CAN_MCR_IDAM_FMTB           (1 << CAN_MCR_IDAM_SHIFT) /* Format B: Two full (or partial) IDs */
 #  define CAN_MCR_IDAM_FMTC           (2 << CAN_MCR_IDAM_SHIFT) /* Format C: Four partial IDs */
 #  define CAN_MCR_IDAM_FMTD           (3 << CAN_MCR_IDAM_SHIFT) /* Format D: All frames rejected */
-                                                /* Bits 10-11: Reserved */
+
+                                                /* Bit 10: Reserved */
+#define CAN_MCR_FDEN                  (1 << 11) /* Bit 11: CAN FD operation enable */
 #define CAN_MCR_AEN                   (1 << 12) /* Bit 12: Abort Enable */
 #define CAN_MCR_LPRIOEN               (1 << 13) /* Bit 13: Local Priority Enable */
                                                 /* Bits 14-15: Reserved */
@@ -363,8 +374,7 @@
 
 /* Control 1 Register */
 
-#define CAN_CTRL1_ROPSEG_SHIFT        (0)       /* Bits 0-2: Propagation Segment */
-#define CAN_CTRL1_ROPSEG_MASK         (7 << CAN_CTRL1_ROPSEG_SHIFT)
+#define CAN_CTRL1_PROPSEG(x)          (((uint32_t)(((uint32_t)(x)) << 0)) & 0x7)
 #define CAN_CTRL1_LOM                 (1 << 3)  /* Bit 3:  Listen-Only Mode */
 #define CAN_CTRL1_LBUF                (1 << 4)  /* Bit 4:  Lowest Buffer Transmitted First */
 #define CAN_CTRL1_TSYN                (1 << 5)  /* Bit 5:  Timer Sync */
@@ -377,14 +387,10 @@
 #define CAN_CTRL1_CLKSRC              (1 << 13) /* Bit 13: CAN Engine Clock Source */
 #define CAN_CTRL1_ERRMSK              (1 << 14) /* Bit 14: Error Mask */
 #define CAN_CTRL1_BOFFMSK             (1 << 15) /* Bit 15: Bus Off Mask */
-#define CAN_CTRL1_PSEG2_SHIFT         (16)       /* Bits 16-18: Phase Segment 2 */
-#define CAN_CTRL1_PSEG2_MASK          (7 << CAN_CTRL1_PSEG2_SHIFT)
-#define CAN_CTRL1_PSEG1_SHIFT         (19)       /* Bits 19-21: Phase Segment 1 */
-#define CAN_CTRL1_PSEG1_MASK          (7 << CAN_CTRL1_PSEG1_SHIFT)
-#define CAN_CTRL1_RJW_SHIFT           (22)       /* Bits 22-23: Resync Jump Width */
-#define CAN_CTRL1_RJW_MASK            (3 << CAN_CTRL1_RJW_SHIFT)
-#define CAN_CTRL1_PRESDIV_SHIFT       (24)       /* Bits 24-31: Prescaler Division Factor */
-#define CAN_CTRL1_PRESDIV_MASK        (0xff << CAN_CTRL1_PRESDIV_SHIFT)
+#define CAN_CTRL1_PSEG2(x)            (((uint32_t)(((uint32_t)(x)) << 16)) & 0x70000)
+#define CAN_CTRL1_PSEG1(x)            (((uint32_t)(((uint32_t)(x)) << 19)) & 0x380000)
+#define CAN_CTRL1_RJW(x)              (((uint32_t)(((uint32_t)(x)) << 22)) & 0xC00000)
+#define CAN_CTRL1_PRESDIV(x)          (((uint32_t)(((uint32_t)(x)) << 24)) & 0xFF000000)
 
 /* Free Running Timer */
 
@@ -409,8 +415,8 @@
 #define CAN_ECR_TXERRCNT_SHIFT        (0)       /* Bits 0-7: Transmit Error Counter */
 #define CAN_ECR_TXERRCNT_MASK         (0xff << CAN_ECR_TXERRCNT_SHIFT)
 #define CAN_ECR_RXERRCNT_SHIFT        (8)       /* Bits 8-15: Receive Error Counter */
-#define CAN_ECR_RXERRCNT_MASK        (0xff << CAN_ECR_RXERRCNT_SHIFT)
-                                               /* Bits 16-31: Reserved */
+#define CAN_ECR_RXERRCNT_MASK         (0xff << CAN_ECR_RXERRCNT_SHIFT)
+                                                /* Bits 16-31: Reserved */
 
 /* Error and Status 1 Register */
 
@@ -419,13 +425,15 @@
 #define CAN_ESR1_BOFFINT              (1 << 2)  /* Bit 2:  'Bus Off' Interrupt */
 #define CAN_ESR1_RX                   (1 << 3)  /* Bit 3:  FlexCAN in Reception */
 #define CAN_ESR1_FLTCONF_SHIFT        (4)       /* Bits 4-5: Fault Confinement State */
+
 #define CAN_ESR1_FLTCONF_MASK         (3 << CAN_ESR1_FLTCONF_SHIFT)
 #  define CAN_ESR1_FLTCONF_ACTV       (0 << CAN_ESR1_FLTCONF_SHIFT) /* Error Active */
 #  define CAN_ESR1_FLTCONF_PASV       (1 << CAN_ESR1_FLTCONF_SHIFT) /* Error Passive */
 #  define CAN_ESR1_FLTCONF_OFF        (2 << CAN_ESR1_FLTCONF_SHIFT) /* Bus Off */
+
 #define CAN_ESR1_TX                   (1 << 6)  /* Bit 6:  FlexCAN in Transmission */
 #define CAN_ESR1_IDLE                 (1 << 7)  /* Bit 7:  CAN bus is in IDLE state */
-#define CAN_ESR1_RXWRN                  (1 << 8)  /* Bit 8:  Rx Error Warning */
+#define CAN_ESR1_RXWRN                (1 << 8)  /* Bit 8:  Rx Error Warning */
 #define CAN_ESR1_TXWRN                (1 << 9)  /* Bit 9:  TX Error Warning */
 #define CAN_ESR1_STFERR               (1 << 10) /* Bit 10: Stuffing Error */
 #define CAN_ESR1_FRMERR               (1 << 11) /* Bit 11: Form Error */
@@ -437,6 +445,7 @@
 #define CAN_ESR1_TWRNINT              (1 << 17) /* Bit 17: Tx Warning Interrupt Flag */
 #define CAN_ESR1_SYNCH                (1 << 18) /* Bit 18: CAN Synchronization Status */
                                                 /* Bits 19-31: Reserved */
+
 /* Interrupt Masks 2 Register */
 
 #define CAN_IMASK2(n)                 (1 << (n)) /* Bit n: Buffer MBn Mask */
@@ -454,7 +463,13 @@
 #define CAN_IFLAG1(n)                 (1 << (n)) /* Bit n: Buffer MBn Interrupt, n=0..4,8..31 */
 
 /* Control 2 Register */
-                                                /* Bits 0-15: Reserved */
+
+                                                /* Bits 0-10: Reserved */
+#define CAN_CTRL2_EDFLTDIS            (1 << 11) /* Bit 11:  Edge Filter Disable */
+#define CAN_CTRL2_ISOCANFDEN          (1 << 12) /* Bit 12:  ISO CAN FD Enable */
+                                                /* Bit 13:  Reserved */
+#define CAN_CTRL2_PREXCEN             (1 << 14) /* Bit 14:  Protocol Exception Enable */
+#define CAN_CTRL2_TIMER_SRC           (1 << 15) /* Bit 15:  Timer Source */
 #define CAN_CTRL2_EACEN               (1 << 16) /* Bit 16:  Entire Frame Arbitration Field Comparison Enable (Rx) */
 #define CAN_CTRL2_RRS                 (1 << 17) /* Bit 17:  Remote Request Storing */
 #define CAN_CTRL2_MRP                 (1 << 18) /* Bit 18:  Mailboxes Reception Priority */
@@ -482,6 +497,7 @@
                                                 /* Bits 29-31: Reserved */
 
 /* Error and Status 2 Register */
+
                                                 /* Bits 0-12: Reserved */
 #define CAN_ESR2_IMB                  (1 << 13) /* Bit 13: Inactive Mailbox */
 #define CAN_ESR2_VPS                  (1 << 14) /* Bit 14: Valid Priority Status */
@@ -502,15 +518,54 @@
 /* Rx FIFO Global Mask Register (32 Rx FIFO Global Mask Bits) */
 
 /* Rx FIFO Information Register */
+
                                                 /* Bits 9-31: Reserved */
 #define CAN_RXFIR_IDHIT_SHIFT         (0)       /* Bits 0-8: Identifier Acceptance Filter Hit Indicator */
 #define CAN_RXFIR_IDHIT_MASK          (0x1ff << CAN_RXFIR_IDHIT_SHIFT)
 
+/* CAN Bit Timing register (CBT) */
+
+/* CBT Bit Fields */
+#define CAN_CBT_EPSEG2(x)             (((uint32_t)(((uint32_t)(x)) << 0))  & 0x1F)
+#define CAN_CBT_EPSEG1(x)             (((uint32_t)(((uint32_t)(x)) << 5))  & 0x3E0)
+#define CAN_CBT_EPROPSEG(x)           (((uint32_t)(((uint32_t)(x)) << 10)) & 0xFC00)
+#define CAN_CBT_ERJW(x)               (((uint32_t)(((uint32_t)(x)) << 16)) & 0x1F0000)
+#define CAN_CBT_EPRESDIV(x)           (((uint32_t)(((uint32_t)(x)) << 21)) & 0x7FE00000)
+#define CAN_CBT_BTF                   (1 << 31) /* Bit 31: Bit Timing Format Enable */
+
+/* CAN MB TX codes */
+#define CAN_TXMB_INACTIVE             0x8       /* MB is not active. */
+#define CAN_TXMB_ABORT                0x9       /* MB is aborted. */
+#define CAN_TXMB_DATAORREMOTE         0xC       /* MB is a TX Data Frame(when MB RTR = 0) or */
+                                                /* MB is a TX Remote Request Frame (when MB RTR = 1). */
+#define CAN_TXMB_TANSWER              0xE       /* MB is a TX Response Request Frame from */
+                                                /* an incoming Remote Request Frame. */
+#define CAN_TXMB_NOTUSED              0xF       /* Not used.*/
+
+/* CAN FD Control register (FDCTRL) */
+#define CAN_FDCTRL_TDCVAL(x)          (((uint32_t)(((uint32_t)(x)) << 0))  & 0x3F)
+#define CAN_FDCTRL_TDCOFF(x)          (((uint32_t)(((uint32_t)(x)) << 8))  & 0x1F00)
+#define CAN_FDCTRL_TDCF               (1 << 14) /* Bit 14: TDC fail */
+#define CAN_FDCTRL_TDCEN              (1 << 15) /* Bit 15: TDC enable */
+#define CAN_FDCTRL_MBDSR0(x)          (((uint32_t)(((uint32_t)(x)) << 16)) & 0x30000)
+#define CAN_FDCTRL_FDRATE             (1 << 31) /* Bit 31: FD rate */
+
+/* FDCBT Bit Fields */
+#define CAN_FDCBT_FPSEG2(x)           (((uint32_t)(((uint32_t)(x)) << 0))  & 0x7)
+#define CAN_FDCBT_FPSEG1(x)           (((uint32_t)(((uint32_t)(x)) << 5))  & 0xE0)
+#define CAN_FDCBT_FPROPSEG(x)         (((uint32_t)(((uint32_t)(x)) << 10)) & 0x7C00)
+#define CAN_FDCBT_FRJW(x)             (((uint32_t)(((uint32_t)(x)) << 16)) & 0x70000)
+#define CAN_FDCBT_FPRESDIV(x)         (((uint32_t)(((uint32_t)(x)) << 20)) & 0x3FF00000)
+
+/* FDCRC Bit Fields */
+#define CAN_FDCRC_FD_TXCRC(x)         (((uint32_t)(((uint32_t)(x)) << 0))  & 0x1FFFFF)
+#define CAN_FDCRC_FD_MBCRC(x)         (((uint32_t)(((uint32_t)(x)) << 24)) & 0x7F000000)
+
 /* Rn Individual Mask Registers */
 
 #define CAN_RXIMR(n)                  (1 << (n)) /* Bit n: Individual Mask Bits */
 
- /* Pretended Networking Control 1 register */
+/* Pretended Networking Control 1 register */
 #define CAN_CTRL1_PN_
 
 /* Pretended Networking Control 2 register */
@@ -561,16 +616,4 @@
 /* CAN FD CRC register */
 #define CAN_FDCRC_
 
-/****************************************************************************************************
- * Public Types
- ****************************************************************************************************/
-
-/****************************************************************************************************
- * Public Data
- ****************************************************************************************************/
-
-/****************************************************************************************************
- * Public Functions
- ****************************************************************************************************/
-
 #endif /* __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_FLEXCAN_H */
diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_ftfc.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_ftfc.h
new file mode 100644
index 0000000..59f576a
--- /dev/null
+++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_ftfc.h
@@ -0,0 +1,143 @@
+/*****************************************************************************************************
+ * arch/arm/src/s32k1xx/chip/s32k1xx_ftfc.h
+ *
+ *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_FTFC_H
+#define __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_FTFC_H
+
+/*****************************************************************************************************
+ * Included Files
+ *****************************************************************************************************/
+
+#include <nuttx/config.h>
+#include <hardware/s32k1xx_memorymap.h>
+
+/*****************************************************************************************************
+ * Pre-processor Definitions
+ *****************************************************************************************************/
+
+/* FTFC Register Offsets *****************************************************************************/
+
+/* FTFC Register Offsets *****************************************************************************/
+
+#define S32K1XX_FTFC_FSTAT_OFFSET	                     0x0000
+#define S32K1XX_FTFC_FCNFG_OFFSET	                     0x0001
+#define S32K1XX_FTFC_FSEC_OFFSET	                     0x0002
+#define S32K1XX_FTFC_FOPT_OFFSET	                     0x0003
+#define S32K1XX_FTFC_FCCOB3_OFFSET	                     0x0004
+#define S32K1XX_FTFC_FCCOB2_OFFSET	                     0x0005
+#define S32K1XX_FTFC_FCCOB1_OFFSET	                     0x0006
+#define S32K1XX_FTFC_FCCOB0_OFFSET	                     0x0007
+#define S32K1XX_FTFC_FCCOB7_OFFSET	                     0x0008
+#define S32K1XX_FTFC_FCCOB6_OFFSET	                     0x0009
+#define S32K1XX_FTFC_FCCOB5_OFFSET	                     0x000a
+#define S32K1XX_FTFC_FCCOB4_OFFSET	                     0x000b
+#define S32K1XX_FTFC_FCCOBB_OFFSET	                     0x000c
+#define S32K1XX_FTFC_FCCOBA_OFFSET	                     0x000d
+#define S32K1XX_FTFC_FCCOB9_OFFSET	                     0x000e
+#define S32K1XX_FTFC_FCCOB8_OFFSET	                     0x000f
+#define S32K1XX_FTFC_FPROT3_OFFSET	                     0x0010
+#define S32K1XX_FTFC_FPROT2_OFFSET	                     0x0011
+#define S32K1XX_FTFC_FPROT1_OFFSET	                     0x0012
+#define S32K1XX_FTFC_FPROT0_OFFSET	                     0x0013
+#define S32K1XX_FTFC_FEPROT_OFFSET	                     0x0016
+#define S32K1XX_FTFC_FDPROT_OFFSET	                     0x0017
+#define S32K1XX_FTFC_FCSESTAT_OFFSET                     0x002c
+#define S32K1XX_FTFC_FERSTAT_OFFSET	                     0x002e
+#define S32K1XX_FTFC_FERCNFG_OFFSET	                     0x002f
+
+/* FTFC Register Addresses ***************************************************************************/
+
+#define S32K1XX_FTFC_FSTAT                               (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FSTAT_OFFSET)
+#define S32K1XX_FTFC_FCNFG                               (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCNFG_OFFSET)
+#define S32K1XX_FTFC_FSEC                                (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FSEC_OFFSET)
+#define S32K1XX_FTFC_FOPT                                (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FOPT_OFFSET)
+#define S32K1XX_FTFC_FCCOB3                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOB3_OFFSET)
+#define S32K1XX_FTFC_FCCOB2                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOB2_OFFSET)
+#define S32K1XX_FTFC_FCCOB1                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOB1_OFFSET)
+#define S32K1XX_FTFC_FCCOB0                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOB0_OFFSET)
+#define S32K1XX_FTFC_FCCOB7                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOB7_OFFSET)
+#define S32K1XX_FTFC_FCCOB6                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOB6_OFFSET)
+#define S32K1XX_FTFC_FCCOB5                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOB5_OFFSET)
+#define S32K1XX_FTFC_FCCOB4                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOB4_OFFSET)
+#define S32K1XX_FTFC_FCCOBB                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOBB_OFFSET)
+#define S32K1XX_FTFC_FCCOBA                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOBA_OFFSET)
+#define S32K1XX_FTFC_FCCOB9                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOB9_OFFSET)
+#define S32K1XX_FTFC_FCCOB8                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCCOB8_OFFSET)
+#define S32K1XX_FTFC_FPROT3                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FPROT3_OFFSET)
+#define S32K1XX_FTFC_FPROT2                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FPROT2_OFFSET)
+#define S32K1XX_FTFC_FPROT1                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FPROT1_OFFSET)
+#define S32K1XX_FTFC_FPROT0                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FPROT0_OFFSET)
+#define S32K1XX_FTFC_FEPROT                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FEPROT_OFFSET)
+#define S32K1XX_FTFC_FDPROT                              (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FDPROT_OFFSET)
+#define S32K1XX_FTFC_FCSESTAT                            (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FCSESTAT_OFFSET)
+#define S32K1XX_FTFC_FERSTAT                             (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FERSTAT_OFFSET)
+#define S32K1XX_FTFC_FERCNFG                             (S32K1XX_FTFC_BASE + S32K1XX_FTFC_FERCNFG_OFFSET)
+
+/* FTFC Register Bitfield Definitions ****************************************************************/
+
+#define FTTC_FSTAT_MGSTAT0                               (1 << 0)
+#define FTTC_FSTAT_FPVIOL                                (1 << 4)
+#define FTTC_FSTAT_ACCERR                                (1 << 5)
+#define FTTC_FSTAT_RDCOLERR                              (1 << 6)
+#define FTTC_FSTAT_CCIF                                  (1 << 7)
+
+#define FTTC_FCNFG_EEERDY                                (1 << 0)
+#define FTTC_FCNFG_RAMRDY                                (1 << 1)
+
+/* Flash controller command numbers ******************************************************************/
+
+#define S32K1XX_FTFC_VERIFY_BLOCK                        0x00 /* RD1BLK*/
+#define S32K1XX_FTFC_VERIFY_SECTION                      0x01 /* RD1SEC*/
+#define S32K1XX_FTFC_PROGRAM_CHECK                       0x02 /* PGMCHK*/
+#define S32K1XX_FTFC_READ_RESOURCE                       0x03 /* RDRSRC*/
+#define S32K1XX_FTFC_PROGRAM_LONGWORD                    0x06 /* PGM4*/
+#define S32K1XX_FTFC_PROGRAM_PHRASE                      0x07 /* PGM8*/
+#define S32K1XX_FTFC_ERASE_BLOCK                         0x08 /* ERSBLK*/
+#define S32K1XX_FTFC_ERASE_SECTOR                        0x09 /* ERSSCR*/
+#define S32K1XX_FTFC_PROGRAM_SECTION                     0x0B /* PGMSEC*/
+#define S32K1XX_FTFC_GENERATE_CRC                        0x0C /* CRCGEN*/
+#define S32K1XX_FTFC_VERIFY_ALL_BLOCK                    0x40 /* RD1ALL*/
+#define S32K1XX_FTFC_READ_ONCE                           0x41 /* RDONCE or RDINDEX*/
+#define S32K1XX_FTFC_PROGRAM_ONCE                        0x43 /* PGMONCE or PGMINDEX*/
+#define S32K1XX_FTFC_ERASE_ALL_BLOCK                     0x44 /* ERSALL*/
+#define S32K1XX_FTFC_SECURITY_BY_PASS                    0x45 /* VFYKEY*/
+#define S32K1XX_FTFC_SWAP_CONTROL                        0x46 /* SWAP*/
+#define S32K1XX_FTFC_ERASE_ALL_BLOCK_UNSECURE            0x49 /* ERSALLU*/
+#define S32K1XX_FTFC_VERIFY_ALL_EXECUTE_ONLY_SEGMENT     0x4A /* RD1XA*/
+#define S32K1XX_FTFC_ERASE_ALL_EXECUTE_ONLY_SEGMENT      0x4B /* ERSXA*/
+#define S32K1XX_FTFC_PROGRAM_PARTITION                   0x80 /* PGMPART */
+#define S32K1XX_FTFC_SET_FLEXRAM_FUNCTION                0x81 /* SETRAM */
+
+#endif /* __ARCH_ARM_SRC_S32K1XX_HARDWARE_S32K1XX_FTFC_H */
diff --git a/arch/arm/src/s32k1xx/s32k1xx_flexcan.c b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
new file mode 100644
index 0000000..d09dceb
--- /dev/null
+++ b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
@@ -0,0 +1,1901 @@
+/****************************************************************************
+ * arch/arm/src/s32k1xx/s32k1xx_flexcan.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 <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/can.h>
+#include <nuttx/wdog.h>
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/signal.h>
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/can.h>
+
+#include "arm_arch.h"
+#include "chip.h"
+#include "s32k1xx_config.h"
+#include "hardware/s32k1xx_flexcan.h"
+#include "hardware/s32k1xx_pinmux.h"
+#include "s32k1xx_periphclocks.h"
+#include "s32k1xx_pin.h"
+#include "s32k1xx_flexcan.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_NET_CMSG
+#include <sys/time.h>
+#endif
+
+#ifdef CONFIG_S32K1XX_FLEXCAN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* If processing is not done at the interrupt level, then work queue support
+ * is required.
+ */
+
+#define CANWORK LPWORK
+
+/* CONFIG_S32K1XX_FLEXCAN_NETHIFS determines the number of physical
+ * interfaces that will be supported.
+ */
+
+#define MASKSTDID                   0x000007ff
+#define MASKEXTID                   0x1fffffff
+#define FLAGEFF                     (1 << 31) /* Extended frame format */
+#define FLAGRTR                     (1 << 30) /* Remote transmission request */
+
+#define RXMBCOUNT                   5
+#define TXMBCOUNT                   2
+#define TOTALMBCOUNT                RXMBCOUNT + TXMBCOUNT
+
+#define IFLAG1_RX                   ((1 << RXMBCOUNT)-1)
+#define IFLAG1_TX                   (((1 << TXMBCOUNT)-1) << RXMBCOUNT)
+
+#define CAN_FIFO_NE                 (1 << 5)
+#define CAN_FIFO_OV                 (1 << 6)
+#define CAN_FIFO_WARN               (1 << 7)
+#define CAN_EFF_FLAG                0x80000000 /* EFF/SFF is set in the MSB */
+
+#define POOL_SIZE                   1
+
+#ifdef CONFIG_NET_CMSG
+#define MSG_DATA                    sizeof(struct timeval)
+#else
+#define MSG_DATA                    0
+#endif
+
+/* CAN bit timing values  */
+#define CLK_FREQ                    80000000
+#define PRESDIV_MAX                 256
+
+#define SEG_MAX                     8
+#define SEG_MIN                     1
+#define TSEG_MIN                    2
+#define TSEG1_MAX                   17
+#define TSEG2_MAX                   9
+#define NUMTQ_MAX                   26
+
+#define SEG_FD_MAX                  32
+#define SEG_FD_MIN                  1
+#define TSEG_FD_MIN                 2
+#define TSEG1_FD_MAX                39
+#define TSEG2_FD_MAX                9
+#define NUMTQ_FD_MAX                49
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+
+#  if !defined(CONFIG_SCHED_WORKQUEUE)
+#    error Work queue support is required
+#  endif
+
+#define TX_TIMEOUT_WQ
+#endif
+
+/* Interrupt flags for RX fifo */
+#define IFLAG1_RXFIFO               (CAN_FIFO_NE | CAN_FIFO_WARN | CAN_FIFO_OV)
+
+static int peak_tx_mailbox_index_ = 0;
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+union cs_e
+{
+  volatile uint32_t cs;
+  struct
+  {
+    volatile uint32_t time_stamp : 16;
+    volatile uint32_t dlc : 4;
+    volatile uint32_t rtr : 1;
+    volatile uint32_t ide : 1;
+    volatile uint32_t srr : 1;
+    volatile uint32_t res : 1;
+    volatile uint32_t code : 4;
+    volatile uint32_t res2 : 1;
+    volatile uint32_t esi : 1;
+    volatile uint32_t brs : 1;
+    volatile uint32_t edl : 1;
+  };
+};
+
+union id_e
+{
+  volatile uint32_t w;
+  struct
+  {
+    volatile uint32_t ext : 29;
+    volatile uint32_t resex : 3;
+  };
+  struct
+  {
+    volatile uint32_t res : 18;
+    volatile uint32_t std : 11;
+    volatile uint32_t resstd : 3;
+  };
+};
+
+union data_e
+{
+  volatile uint32_t w00;
+  struct
+  {
+    volatile uint32_t b03 : 8;
+    volatile uint32_t b02 : 8;
+    volatile uint32_t b01 : 8;
+    volatile uint32_t b00 : 8;
+  };
+};
+
+struct mb_s
+{
+  union cs_e cs;
+  union id_e id;
+#ifdef CONFIG_NET_CAN_CANFD
+  union data_e data[16];
+#else
+  union data_e data[2];
+#endif
+};
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+#define TX_ABORT -1
+#define TX_FREE 0
+#define TX_BUSY 1
+
+struct txmbstats
+{
+  struct timeval deadline;
+  uint32_t pending; /* -1 = abort, 0 = free, 1 = busy  */
+};
+#endif
+
+/* FlexCAN Device hardware configuration */
+
+struct flexcan_config_s
+{
+  uint32_t tx_pin;           /* GPIO configuration for TX */
+  uint32_t rx_pin;           /* GPIO configuration for RX */
+  uint32_t enable_pin;       /* Optional enable pin */
+  uint32_t enable_high;      /* Optional enable high/low */
+  uint32_t bus_irq;          /* BUS IRQ */
+  uint32_t error_irq;        /* ERROR IRQ */
+  uint32_t lprx_irq;         /* LPRX IRQ */
+  uint32_t mb_irq;           /* MB 0-15 IRQ */
+};
+
+struct flexcan_timeseg
+{
+  uint32_t bitrate;
+  int32_t samplep;
+  uint8_t propseg;
+  uint8_t pseg1;
+  uint8_t pseg2;
+  uint8_t presdiv;
+};
+
+/* FlexCAN device structures */
+
+#ifdef CONFIG_S32K1XX_FLEXCAN0
+static const struct flexcan_config_s s32k1xx_flexcan0_config =
+{
+  .tx_pin      = PIN_CAN0_TX,
+  .rx_pin      = PIN_CAN0_RX,
+#ifdef PIN_CAN0_ENABLE
+  .enable_pin  = PIN_CAN0_ENABLE,
+  .enable_high = CAN0_ENABLE_OUT,
+#else
+  .enable_pin  = 0,
+  .enable_high = 0,
+#endif
+  .bus_irq     = S32K1XX_IRQ_CAN0_BUS,
+  .error_irq   = S32K1XX_IRQ_CAN0_ERROR,
+  .lprx_irq    = S32K1XX_IRQ_CAN0_LPRX,
+  .mb_irq      = S32K1XX_IRQ_CAN0_0_15,
+};
+#endif
+
+#ifdef CONFIG_S32K1XX_FLEXCAN1
+static const struct flexcan_config_s s32k1xx_flexcan1_config =
+{
+  .tx_pin      = PIN_CAN1_TX,
+  .rx_pin      = PIN_CAN1_RX,
+#ifdef PIN_CAN1_ENABLE
+  .enable_pin  = PIN_CAN1_ENABLE,
+  .enable_high = CAN1_ENABLE_OUT,
+#else
+  .enable_pin  = 0,
+  .enable_high = 0,
+#endif
+  .bus_irq     = S32K1XX_IRQ_CAN1_BUS,
+  .error_irq   = S32K1XX_IRQ_CAN1_ERROR,
+  .lprx_irq    = 0,
+  .mb_irq      = S32K1XX_IRQ_CAN1_0_15,
+};
+#endif
+
+#ifdef CONFIG_S32K1XX_FLEXCAN2
+static const struct flexcan_config_s s32k1xx_flexcan2_config =
+{
+  .tx_pin    = PIN_CAN2_TX,
+  .rx_pin    = PIN_CAN2_RX,
+#ifdef PIN_CAN2_ENABLE
+  .enable_pin = PIN_CAN2_ENABLE,
+  .rx_pin     = CAN2_ENABLE_HIGH,
+#else
+  .enable_pin = 0,
+  .rx_pin     = 0,
+#endif
+  .bus_irq   = S32K1XX_IRQ_CAN2_BUS,
+  .error_irq = S32K1XX_IRQ_CAN2_ERROR,
+  .lprx_irq  = 0,
+  .mb_irq    = S32K1XX_IRQ_CAN2_0_15,
+};
+#endif
+
+/* The s32k1xx_driver_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct s32k1xx_driver_s
+{
+  uint32_t base;                /* FLEXCAN base address */
+  bool bifup;                   /* true:ifup false:ifdown */
+#ifdef TX_TIMEOUT_WQ
+  WDOG_ID txtimeout[TXMBCOUNT]; /* TX timeout timer */
+#endif
+  struct work_s irqwork;        /* For deferring interrupt work to the wq */
+  struct work_s pollwork;       /* For deferring poll work to the work wq */
+#ifdef CONFIG_NET_CAN_CANFD
+  struct canfd_frame *txdesc;   /* A pointer to the list of TX descriptor */
+  struct canfd_frame *rxdesc;   /* A pointer to the list of RX descriptors */
+#else
+  struct can_frame *txdesc;     /* A pointer to the list of TX descriptor */
+  struct can_frame *rxdesc;     /* A pointer to the list of RX descriptors */
+#endif
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s dev;      /* Interface understood by the network */
+
+  struct mb_s *rx;
+  struct mb_s *tx;
+
+  struct flexcan_timeseg arbi_timing; /* Timing for arbitration phase */
+#ifdef CONFIG_NET_CAN_CANFD
+  struct flexcan_timeseg data_timing; /* Timing for data phase */
+#endif
+
+  const struct flexcan_config_s *config;
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+  struct txmbstats txmb[TXMBCOUNT];
+#endif
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_S32K1XX_FLEXCAN0
+static struct s32k1xx_driver_s g_flexcan0;
+#endif
+
+#ifdef CONFIG_S32K1XX_FLEXCAN1
+static struct s32k1xx_driver_s g_flexcan1;
+#endif
+
+#ifdef CONFIG_S32K1XX_FLEXCAN2
+static struct s32k1xx_driver_s g_flexcan2;
+#endif
+
+#ifdef CONFIG_NET_CAN_CANFD
+static uint8_t g_tx_pool[(sizeof(struct canfd_frame)+MSG_DATA)*POOL_SIZE];
+static uint8_t g_rx_pool[(sizeof(struct canfd_frame)+MSG_DATA)*POOL_SIZE];
+#else
+static uint8_t g_tx_pool[sizeof(struct can_frame)*POOL_SIZE];
+static uint8_t g_rx_pool[sizeof(struct can_frame)*POOL_SIZE];
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_lsb
+ *
+ * Description:
+ *   Calculate position of lsb that's equal to 1
+ *
+ * Input Parameters:
+ *   value - The value to perform the operation on
+ *
+ * Returned Value:
+ *   location of lsb which is equal to 1, returns 32 when value is 0
+ *
+ ****************************************************************************/
+
+static inline uint32_t arm_lsb(unsigned int value)
+{
+  uint32_t ret;
+  volatile uint32_t rvalue = value;
+  __asm__ __volatile__ ("rbit %1,%0" : "=r" (rvalue) : "r" (rvalue));
+  __asm__ __volatile__ ("clz %0, %1" : "=r"(ret) : "r"(rvalue));
+  return ret;
+}
+
+/****************************************************************************
+ * Name: s32k1xx_bitratetotimeseg
+ *
+ * Description:
+ *   Convert bitrate to timeseg
+ *
+ * Input Parameters:
+ *   timeseg - structure to store bit timing
+ *   sp_tolerance - allowed difference in sample point from calculated
+ *                  bit timings (recommended value: 1)
+ *   can_fd - if set to calculate CAN FD bit timings, otherwise calculate
+ *            classical can timings
+ *
+ * Returned Value:
+ *   return 1 on succes, return 0 on failure
+ *
+ ****************************************************************************/
+
+uint32_t s32k1xx_bitratetotimeseg(struct flexcan_timeseg *timeseg,
+                                                int32_t sp_tolerance,
+                                                uint32_t can_fd)
+{
+  int32_t tmppresdiv;
+  int32_t numtq;
+  int32_t tmpsample;
+  int32_t tseg1;
+  int32_t tseg2;
+  int32_t tmppseg1;
+  int32_t tmppseg2;
+  int32_t tmppropseg;
+
+  const int32_t TSEG1MAX = (can_fd ? TSEG1_FD_MAX : TSEG1_MAX);
+  const int32_t TSEG2MAX = (can_fd ? TSEG2_FD_MAX : TSEG2_MAX);
+  const int32_t SEGMAX = (can_fd ? SEG_FD_MAX : SEG_MAX);
+  const int32_t NUMTQMAX = (can_fd ? NUMTQ_FD_MAX : NUMTQ_MAX);
+
+  for (tmppresdiv = 0; tmppresdiv < PRESDIV_MAX; tmppresdiv++)
+    {
+      numtq = (CLK_FREQ / ((tmppresdiv + 1) * timeseg->bitrate));
+
+      if (numtq == 0)
+        {
+          continue;
+        }
+
+      /* The number of time quanta in 1 bit time must be
+       * lower than the one supported
+       */
+
+      if ((CLK_FREQ / ((tmppresdiv + 1) * numtq) == timeseg->bitrate)
+          && (numtq >= 8) && (numtq < NUMTQMAX))
+        {
+          /* Compute time segments based on the value of the sampling point */
+
+          tseg1 = (numtq * timeseg->samplep / 100) - 1;
+          tseg2 = numtq - 1 - tseg1;
+
+          /* Adjust time segment 1 and time segment 2 */
+
+          while (tseg1 >= TSEG1MAX || tseg2 < TSEG_MIN)
+            {
+              tseg2++;
+              tseg1--;
+            }
+
+          tmppseg2 = tseg2 - 1;
+
+          /* Start from pseg1 = pseg2 and adjust until propseg is valid */
+
+          tmppseg1 = tmppseg2;
+          tmppropseg = tseg1 - tmppseg1 - 2;
+
+          while (tmppropseg <= 0)
+            {
+              tmppropseg++;
+              tmppseg1--;
+            }
+
+          while (tmppropseg >= SEGMAX)
+            {
+              tmppropseg--;
+              tmppseg1++;
+            }
+
+          if (((tseg1 >= TSEG1MAX) || (tseg2 >= TSEG2MAX) ||
+              (tseg2 < TSEG_MIN) || (tseg1 < TSEG_MIN)) ||
+              ((tmppropseg >= SEGMAX) || (tmppseg1 >= SEGMAX) ||
+                  (tmppseg2 < SEG_MIN) || (tmppseg2 >= SEGMAX)))
+            {
+              continue;
+            }
+
+          tmpsample = ((tseg1 + 1) * 100) / numtq;
+
+          if ((tmpsample - timeseg->samplep) <= sp_tolerance &&
+              (timeseg->samplep - tmpsample) <= sp_tolerance)
+            {
+              if (can_fd == 1)
+                {
+                  timeseg->propseg = tmppropseg + 1;
+                }
+              else
+                {
+                  timeseg->propseg = tmppropseg;
+                }
+              timeseg->pseg1 = tmppseg1;
+              timeseg->pseg2 = tmppseg2;
+              timeseg->presdiv = tmppresdiv;
+              timeseg->samplep = tmpsample;
+              return 1;
+            }
+        }
+    }
+
+  return 0;
+}
+
+/* Common TX logic */
+
+static bool s32k1xx_txringfull(FAR struct s32k1xx_driver_s *priv);
+static int  s32k1xx_transmit(FAR struct s32k1xx_driver_s *priv);
+static int  s32k1xx_txpoll(struct net_driver_s *dev);
+
+/* Helper functions */
+
+static void s32k1xx_setenable(uint32_t base, uint32_t enable);
+static void s32k1xx_setfreeze(uint32_t base, uint32_t freeze);
+static uint32_t s32k1xx_waitmcr_change(uint32_t base,
+                                       uint32_t mask,
+                                       uint32_t target_state);
+
+/* Interrupt handling */
+
+static void s32k1xx_receive(FAR struct s32k1xx_driver_s *priv,
+                            uint32_t flags);
+static void s32k1xx_txdone(FAR void *arg);
+
+static int  s32k1xx_flexcan_interrupt(int irq, FAR void *context,
+                                      FAR void *arg);
+
+/* Watchdog timer expirations */
+#ifdef TX_TIMEOUT_WQ
+static void s32k1xx_txtimeout_work(FAR void *arg);
+static void s32k1xx_txtimeout_expiry(int argc, uint32_t arg, ...);
+#endif
+
+/* NuttX callback functions */
+
+static int  s32k1xx_ifup(struct net_driver_s *dev);
+static int  s32k1xx_ifdown(struct net_driver_s *dev);
+
+static void s32k1xx_txavail_work(FAR void *arg);
+static int  s32k1xx_txavail(struct net_driver_s *dev);
+
+#ifdef CONFIG_NETDEV_IOCTL
+static int  s32k1xx_ioctl(struct net_driver_s *dev, int cmd,
+                          unsigned long arg);
+#endif
+
+/* Initialization */
+
+static int  s32k1xx_initialize(struct s32k1xx_driver_s *priv);
+static void s32k1xx_reset(struct s32k1xx_driver_s *priv);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: s32k1xx_txringfull
+ *
+ * Description:
+ *   Check if all of the TX descriptors are in use.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   true is the TX ring is full; false if there are free slots at the
+ *   head index.
+ *
+ ****************************************************************************/
+
+static bool s32k1xx_txringfull(FAR struct s32k1xx_driver_s *priv)
+{
+  uint32_t mbi = 0;
+
+  while (mbi < TXMBCOUNT)
+    {
+      if (priv->tx[mbi].cs.code != CAN_TXMB_DATAORREMOTE)
+        {
+          return 0;
+        }
+
+      mbi++;
+    }
+
+  return 1;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int s32k1xx_transmit(FAR struct s32k1xx_driver_s *priv)
+{
+  /* Attempt to write frame */
+
+  uint32_t mbi = 0;
+  if ((getreg32(priv->base + S32K1XX_CAN_ESR2_OFFSET) &
+      (CAN_ESR2_IMB | CAN_ESR2_VPS)) ==
+      (CAN_ESR2_IMB | CAN_ESR2_VPS))
+    {
+      mbi  = ((getreg32(priv->base + S32K1XX_CAN_ESR2_OFFSET) &
+        CAN_ESR2_LPTM_MASK) >> CAN_ESR2_LPTM_SHIFT);
+      mbi -= RXMBCOUNT;
+    }
+
+  uint32_t mb_bit = 1 << (RXMBCOUNT + mbi);
+
+  while (mbi < TXMBCOUNT)
+    {
+      if (priv->tx[mbi].cs.code != CAN_TXMB_DATAORREMOTE)
+        {
+          putreg32(mb_bit, priv->base + S32K1XX_CAN_IFLAG1_OFFSET);
+          break;
+        }
+
+      mb_bit <<= 1;
+      mbi++;
+    }
+
+  if (mbi == TXMBCOUNT)
+    {
+      nwarn("No TX MB available mbi %i\r\n", mbi);
+      return 0;       /* No transmission for you! */
+    }
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+  int32_t timeout = 0;
+  struct timespec ts;
+  clock_systimespec(&ts);
+
+  if (priv->dev.d_sndlen > priv->dev.d_len)
+    {
+      struct timeval *tv =
+             (struct timeval *)(priv->dev.d_buf + priv->dev.d_len);
+      priv->txmb[mbi].deadline = *tv;
+      timeout  = (tv->tv_sec - ts.tv_sec)*CLK_TCK
+                 + ((tv->tv_usec - ts.tv_nsec / 1000)*CLK_TCK) / 1000000;
+      if (timeout < 0)
+        {
+          return 0;       /* No transmission for you! */
+        }
+    }
+  else
+    {
+      /* Default TX deadline defined in NET_CAN_RAW_DEFAULT_TX_DEADLINE */
+
+      if (CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE > 0)
+        {
+          timeout = ((CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE / 1000000)
+              *CLK_TCK);
+          priv->txmb[mbi].deadline.tv_sec = ts.tv_sec +
+              CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE / 1000000;
+          priv->txmb[mbi].deadline.tv_usec = (ts.tv_nsec / 1000) +
+              CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE % 1000000;
+        }
+      else
+        {
+          priv->txmb[mbi].deadline.tv_sec = 0;
+          priv->txmb[mbi].deadline.tv_usec = 0;
+        }
+    }
+#endif
+
+  peak_tx_mailbox_index_ =
+    (peak_tx_mailbox_index_ > mbi ? peak_tx_mailbox_index_ : mbi);
+
+  union cs_e cs;
+  cs.code = CAN_TXMB_DATAORREMOTE;
+  struct mb_s *mb = &priv->tx[mbi];
+  mb->cs.code = CAN_TXMB_INACTIVE;
+
+  if (priv->dev.d_len <= sizeof(struct can_frame))
+    {
+      struct can_frame *frame = (struct can_frame *)priv->dev.d_buf;
+
+      if (frame->can_id & CAN_EFF_FLAG)
+        {
+          cs.ide = 1;
+          mb->id.ext = frame->can_id & MASKEXTID;
+        }
+      else
+        {
+          mb->id.std = frame->can_id & MASKSTDID;
+        }
+
+      cs.rtr = frame->can_id & FLAGRTR ? 1 : 0;
+      cs.dlc = frame->can_dlc;
+
+      mb->data[0].w00 = __builtin_bswap32(*(uint32_t *)&frame->data[0]);
+      mb->data[1].w00 = __builtin_bswap32(*(uint32_t *)&frame->data[4]);
+    }
+#ifdef CONFIG_NET_CAN_CANFD
+  else /* CAN FD frame */
+    {
+      struct canfd_frame *frame = (struct canfd_frame *)priv->dev.d_buf;
+
+      cs.edl = 1; /* CAN FD Frame */
+
+      if (frame->can_id & CAN_EFF_FLAG)
+        {
+          cs.ide = 1;
+          mb->id.ext = frame->can_id & MASKEXTID;
+        }
+      else
+        {
+          mb->id.std = frame->can_id & MASKSTDID;
+        }
+
+      cs.rtr = frame->can_id & FLAGRTR ? 1 : 0;
+
+      cs.dlc = len_to_can_dlc[frame->len];
+
+      uint32_t *frame_data_word = (uint32_t *)&frame->data[0];
+
+      for (int i = 0; i < (frame->len + 4 - 1) / 4; i++)
+        {
+          mb->data[i].w00 = __builtin_bswap32(frame_data_word[i]);
+        }
+    }
+#endif
+
+  mb->cs = cs; /* Go. */
+
+  uint32_t regval;
+  regval = getreg32(priv->base + S32K1XX_CAN_IMASK1_OFFSET);
+  regval |= mb_bit;
+  putreg32(regval, priv->base + S32K1XX_CAN_IMASK1_OFFSET);
+
+  /* Increment statistics */
+
+  NETDEV_TXPACKETS(&priv->dev);
+
+#ifdef TX_TIMEOUT_WQ
+  /* Setup the TX timeout watchdog (perhaps restarting the timer) */
+
+  if (timeout >= 0)
+    {
+      wd_start(priv->txtimeout[mbi], timeout + 1, s32k1xx_txtimeout_expiry,
+                1, (wdparm_t)priv);
+    }
+#endif
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send timesout and the interface is reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int s32k1xx_txpoll(struct net_driver_s *dev)
+{
+  FAR struct s32k1xx_driver_s *priv =
+    (FAR struct s32k1xx_driver_s *)dev->d_private;
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->dev.d_len > 0)
+    {
+      if (!devif_loopback(&priv->dev))
+        {
+          /* Send the packet */
+
+          s32k1xx_transmit(priv);
+
+          /* Check if there is room in the device to hold another packet. If
+           * not, return a non-zero value to terminate the poll.
+           */
+
+          if (s32k1xx_txringfull(priv))
+            {
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until all connections
+   * have been examined.
+   */
+
+  return 0;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void s32k1xx_receive(FAR struct s32k1xx_driver_s *priv,
+                            uint32_t flags)
+{
+  uint32_t mb_index;
+  struct mb_s *rf;
+
+  while ((mb_index = arm_lsb(flags)) != 32)
+    {
+      rf = &priv->rx[mb_index];
+
+      /* Read the frame contents */
+
+#ifdef CONFIG_NET_CAN_CANFD
+      if (rf->cs.edl) /* CAN FD frame */
+        {
+        struct canfd_frame *frame = (struct canfd_frame *)priv->rxdesc;
+
+          if (rf->cs.ide)
+            {
+              frame->can_id = MASKEXTID & rf->id.ext;
+              frame->can_id |= FLAGEFF;
+            }
+          else
+            {
+              frame->can_id = MASKSTDID & rf->id.std;
+            }
+
+          if (rf->cs.rtr)
+            {
+              frame->can_id |= FLAGRTR;
+            }
+
+          frame->len = can_dlc_to_len[rf->cs.dlc];
+
+          uint32_t *frame_data_word = (uint32_t *)&frame->data[0];
+
+          for (int i = 0; i < (frame->len + 4 - 1) / 4; i++)
+            {
+              frame_data_word[i] = __builtin_bswap32(rf->data[i].w00);
+            }
+
+          /* Clear MB interrupt flag */
+
+          putreg32(1 << mb_index,
+                   priv->base + S32K1XX_CAN_IFLAG1_OFFSET);
+
+          /* Copy the buffer pointer to priv->dev..  Set amount of data
+           * in priv->dev.d_len
+           */
+
+          priv->dev.d_len = sizeof(struct canfd_frame);
+          priv->dev.d_buf = (uint8_t *)frame;
+        }
+      else /* CAN 2.0 Frame */
+#endif
+        {
+        struct can_frame *frame = (struct can_frame *)priv->rxdesc;
+
+          if (rf->cs.ide)
+            {
+              frame->can_id = MASKEXTID & rf->id.ext;
+              frame->can_id |= FLAGEFF;
+            }
+          else
+            {
+              frame->can_id = MASKSTDID & rf->id.std;
+            }
+
+          if (rf->cs.rtr)
+            {
+              frame->can_id |= FLAGRTR;
+            }
+
+          frame->can_dlc = rf->cs.dlc;
+
+          *(uint32_t *)&frame->data[0] = __builtin_bswap32(rf->data[0].w00);
+          *(uint32_t *)&frame->data[4] = __builtin_bswap32(rf->data[1].w00);
+
+          /* Clear MB interrupt flag */
+
+          putreg32(1 << mb_index,
+                   priv->base + S32K1XX_CAN_IFLAG1_OFFSET);
+
+          /* Copy the buffer pointer to priv->dev..  Set amount of data
+           * in priv->dev.d_len
+           */
+
+          priv->dev.d_len = sizeof(struct can_frame);
+          priv->dev.d_buf = (uint8_t *)frame;
+        }
+
+      /* Send to socket interface */
+
+      NETDEV_RXPACKETS(&priv->dev);
+
+      can_input(&priv->dev);
+
+      /* Point the packet buffer back to the next Tx buffer that will be
+       * used during the next write.  If the write queue is full, then
+       * this will point at an active buffer, which must not be written
+       * to.  This is OK because devif_poll won't be called unless the
+       * queue is not full.
+       */
+
+      priv->dev.d_buf = (uint8_t *)priv->txdesc;
+
+      flags &= ~(1 << mb_index);
+
+      /* Reread interrupt flags and process them in this loop */
+
+      if (flags == 0)
+        {
+          flags  = getreg32(priv->base + S32K1XX_CAN_IFLAG1_OFFSET);
+          flags &= IFLAG1_RX;
+        }
+    }
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txdone
+ *
+ * Description:
+ *   An interrupt was received indicating that the last TX packet(s) is done
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by the watchdog logic.
+ *   We are not in an interrupt context so that we can lock the network.
+ *
+ ****************************************************************************/
+
+static void s32k1xx_txdone(FAR void *arg)
+{
+  FAR struct s32k1xx_driver_s *priv = (FAR struct s32k1xx_driver_s *)arg;
+  uint32_t flags;
+
+  flags  = getreg32(priv->base + S32K1XX_CAN_IFLAG1_OFFSET);
+  flags &= IFLAG1_TX;
+
+  #warning Missing logic
+
+  /* FIXME First Process Error aborts */
+
+  /* Process TX completions */
+
+  uint32_t mb_bit = 1 << RXMBCOUNT;
+  for (uint32_t mbi = 0; flags && mbi < TXMBCOUNT; mbi++)
+    {
+      if (flags & mb_bit)
+        {
+          putreg32(mb_bit, priv->base + S32K1XX_CAN_IFLAG1_OFFSET);
+          flags &= ~mb_bit;
+          NETDEV_TXDONE(&priv->dev);
+#ifdef TX_TIMEOUT_WQ
+          /* We are here because a transmission completed, so the
+           * corresponding watchdog can be canceled.
+           */
+
+          wd_cancel(priv->txtimeout[mbi]);
+#endif
+        }
+
+      mb_bit <<= 1;
+    }
+
+  /* There should be space for a new TX in any event.  Poll the network for
+   * new XMIT data
+   */
+
+  net_lock();
+  devif_poll(&priv->dev, s32k1xx_txpoll);
+  net_unlock();
+  up_enable_irq(priv->config->mb_irq);
+}
+
+/****************************************************************************
+ * Function: s32k1xx_flexcan_interrupt
+ *
+ * Description:
+ *   Three interrupt sources will vector this this function:
+ *   1. CAN MB transmit interrupt handler
+ *   2. CAN MB receive interrupt handler
+ *   3.
+ *
+ * Input Parameters:
+ *   irq     - Number of the IRQ that generated the interrupt
+ *   context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int s32k1xx_flexcan_interrupt(int irq, FAR void *context,
+                                     FAR void *arg)
+{
+  FAR struct s32k1xx_driver_s *priv = (struct s32k1xx_driver_s *)arg;
+
+  if (irq == priv->config->mb_irq)
+    {
+      uint32_t flags;
+      flags  = getreg32(priv->base + S32K1XX_CAN_IFLAG1_OFFSET);
+      flags &= IFLAG1_RX;
+
+      if (flags)
+        {
+          /* Process immediately since scheduling a workqueue is too slow
+           * which causes us to drop CAN frames
+           */
+
+          s32k1xx_receive(priv, flags);
+        }
+
+      flags  = getreg32(priv->base + S32K1XX_CAN_IFLAG1_OFFSET);
+      flags &= IFLAG1_TX;
+
+      if (flags)
+        {
+          /* Disable further CAN interrupts. here can be no race
+           * condition here.
+           */
+
+          up_disable_irq(priv->config->mb_irq);
+          work_queue(CANWORK, &priv->irqwork, s32k1xx_txdone, priv, 0);
+        }
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txtimeout_work
+ *
+ * Description:
+ *   Perform TX timeout related work from the worker thread
+ *
+ * Input Parameters:
+ *   arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+#ifdef TX_TIMEOUT_WQ
+
+static void s32k1xx_txtimeout_work(FAR void *arg)
+{
+  FAR struct s32k1xx_driver_s *priv = (FAR struct s32k1xx_driver_s *)arg;
+
+  struct timespec ts;
+  struct timeval *now = (struct timeval *)&ts;
+  clock_systimespec(&ts);
+  now->tv_usec = ts.tv_nsec / 1000; /* timespec to timeval conversion */
+
+  /* The watchdog timed out, yet we still check mailboxes in case the
+   * transmit function transmitted a new frame
+   */
+
+  for (int mbi = 0; mbi < TXMBCOUNT; mbi++)
+    {
+      if (priv->txmb[mbi].deadline.tv_sec != 0
+          && (now->tv_sec > priv->txmb[mbi].deadline.tv_sec
+          || now->tv_usec > priv->txmb[mbi].deadline.tv_usec))
+        {
+          NETDEV_TXTIMEOUTS(&priv->dev);
+          struct mb_s *mb = &priv->tx[mbi];
+          mb->cs.code = CAN_TXMB_ABORT;
+          priv->txmb[mbi].pending = TX_ABORT;
+        }
+    }
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txtimeout_expiry
+ *
+ * Description:
+ *   Our TX watchdog timed out.  Called from the timer interrupt handler.
+ *   The last TX never completed.  Reset the hardware and start again.
+ *
+ * Input Parameters:
+ *   argc - The number of available arguments
+ *   arg  - The first argument
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by the watchdog logic.
+ *
+ ****************************************************************************/
+
+static void s32k1xx_txtimeout_expiry(int argc, uint32_t arg, ...)
+{
+  FAR struct s32k1xx_driver_s *priv = (FAR struct s32k1xx_driver_s *)arg;
+
+  /* Schedule to perform the TX timeout processing on the worker thread
+   */
+
+  work_queue(CANWORK, &priv->irqwork, s32k1xx_txtimeout_work, priv, 0);
+}
+
+#endif
+
+static void s32k1xx_setenable(uint32_t base, uint32_t enable)
+{
+  uint32_t regval;
+
+  if (enable)
+    {
+      regval  = getreg32(base + S32K1XX_CAN_MCR_OFFSET);
+      regval &= ~(CAN_MCR_MDIS);
+      putreg32(regval, base + S32K1XX_CAN_MCR_OFFSET);
+    }
+  else
+    {
+      regval  = getreg32(base + S32K1XX_CAN_MCR_OFFSET);
+      regval |= CAN_MCR_MDIS;
+      putreg32(regval, base + S32K1XX_CAN_MCR_OFFSET);
+    }
+
+  s32k1xx_waitmcr_change(base, CAN_MCR_LPMACK, 1);
+}
+
+static void s32k1xx_setfreeze(uint32_t base, uint32_t freeze)
+{
+  uint32_t regval;
+  if (freeze)
+    {
+      /* Enter freeze mode */
+
+      regval  = getreg32(base + S32K1XX_CAN_MCR_OFFSET);
+      regval |= (CAN_MCR_HALT | CAN_MCR_FRZ);
+      putreg32(regval, base + S32K1XX_CAN_MCR_OFFSET);
+    }
+  else
+    {
+      /* Exit freeze mode */
+
+      regval  = getreg32(base + S32K1XX_CAN_MCR_OFFSET);
+      regval &= ~(CAN_MCR_HALT | CAN_MCR_FRZ);
+      putreg32(regval, base + S32K1XX_CAN_MCR_OFFSET);
+    }
+}
+
+static uint32_t s32k1xx_waitmcr_change(uint32_t base, uint32_t mask,
+                                       uint32_t target_state)
+{
+  const unsigned timeout = 1000;
+  for (unsigned wait_ack = 0; wait_ack < timeout; wait_ack++)
+    {
+      const bool state = (getreg32(base + S32K1XX_CAN_MCR_OFFSET) & mask)
+          != 0;
+      if (state == target_state)
+        {
+          return true;
+        }
+
+      up_udelay(10);
+    }
+
+  return false;
+}
+
+static uint32_t s32k1xx_waitfreezeack_change(uint32_t base,
+                                             uint32_t target_state)
+{
+  return s32k1xx_waitmcr_change(base, CAN_MCR_FRZACK, target_state);
+}
+
+/****************************************************************************
+ * Function: s32k1xx_ifup
+ *
+ * Description:
+ *   NuttX Callback: Bring up the Ethernet interface when an IP address is
+ *   provided
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int s32k1xx_ifup(struct net_driver_s *dev)
+{
+  FAR struct s32k1xx_driver_s *priv =
+    (FAR struct s32k1xx_driver_s *)dev->d_private;
+
+  if (!s32k1xx_initialize(priv))
+    {
+      nerr("initialize failed");
+      return -1;
+    }
+
+  priv->bifup = true;
+
+#ifdef CONFIG_NET_CAN_CANFD
+  priv->txdesc = (struct canfd_frame *)&g_tx_pool;
+  priv->rxdesc = (struct canfd_frame *)&g_rx_pool;
+#else
+  priv->txdesc = (struct can_frame *)&g_tx_pool;
+  priv->rxdesc = (struct can_frame *)&g_rx_pool;
+#endif
+
+  priv->dev.d_buf = (uint8_t *)priv->txdesc;
+
+  /* Set interrupts */
+
+  up_enable_irq(priv->config->bus_irq);
+  up_enable_irq(priv->config->error_irq);
+  if (priv->config->lprx_irq > 0)
+    {
+      up_enable_irq(priv->config->lprx_irq);
+    }
+
+  up_enable_irq(priv->config->mb_irq);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_ifdown
+ *
+ * Description:
+ *   NuttX Callback: Stop the interface.
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int s32k1xx_ifdown(struct net_driver_s *dev)
+{
+  FAR struct s32k1xx_driver_s *priv =
+    (FAR struct s32k1xx_driver_s *)dev->d_private;
+
+  s32k1xx_reset(priv);
+
+  priv->bifup = false;
+  return OK;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txavail_work
+ *
+ * Description:
+ *   Perform an out-of-cycle poll on the worker thread.
+ *
+ * Input Parameters:
+ *   arg - Reference to the NuttX driver state structure (cast to void*)
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called on the higher priority worker thread.
+ *
+ ****************************************************************************/
+
+static void s32k1xx_txavail_work(FAR void *arg)
+{
+  FAR struct s32k1xx_driver_s *priv = (FAR struct s32k1xx_driver_s *)arg;
+
+  /* Ignore the notification if the interface is not yet up */
+
+  net_lock();
+  if (priv->bifup)
+    {
+      /* Check if there is room in the hardware to hold another outgoing
+       * packet.
+       */
+
+      if (!s32k1xx_txringfull(priv))
+        {
+          /* No, there is space for another transfer.  Poll the network for
+           * new XMIT data.
+           */
+
+          devif_poll(&priv->dev, s32k1xx_txpoll);
+        }
+    }
+
+  net_unlock();
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txavail
+ *
+ * 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.
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called in normal user mode
+ *
+ ****************************************************************************/
+
+static int s32k1xx_txavail(struct net_driver_s *dev)
+{
+  FAR struct s32k1xx_driver_s *priv =
+    (FAR struct s32k1xx_driver_s *)dev->d_private;
+
+  /* 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(&priv->pollwork))
+    {
+      /* Schedule to serialize the poll on the worker thread. */
+
+      s32k1xx_txavail_work(priv);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_ioctl
+ *
+ * Description:
+ *   PHY ioctl command handler
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *   cmd  - ioctl command
+ *   arg  - Argument accompanying the command
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL
+static int s32k1xx_ioctl(struct net_driver_s *dev, int cmd,
+                         unsigned long arg)
+{
+  FAR struct s32k1xx_driver_s *priv =
+      (FAR struct s32k1xx_driver_s *)dev->d_private;
+
+  int ret;
+
+  switch (cmd)
+    {
+      case SIOCGCANBITRATE: /* Get bitrate from a CAN controller */
+        {
+          struct can_ioctl_data_s *req =
+              (struct can_ioctl_data_s *)((uintptr_t)arg);
+          req->arbi_bitrate = priv->arbi_timing.bitrate / 1000; /* kbit/s */
+          req->arbi_samplep = priv->arbi_timing.samplep;
+#ifdef CONFIG_NET_CAN_CANFD
+          req->data_bitrate = priv->data_timing.bitrate / 1000; /* kbit/s */
+          req->data_samplep = priv->data_timing.samplep;
+#else
+          req->data_bitrate = 0;
+          req->data_samplep = 0;
+#endif
+          ret = OK;
+        }
+        break;
+
+      case SIOCSCANBITRATE: /* Set bitrate of a CAN controller */
+        {
+          struct can_ioctl_data_s *req =
+              (struct can_ioctl_data_s *)((uintptr_t)arg);
+
+          struct flexcan_timeseg arbi_timing;
+          arbi_timing.bitrate = req->arbi_bitrate * 1000;
+          arbi_timing.samplep = req->arbi_samplep;
+
+          if (s32k1xx_bitratetotimeseg(&arbi_timing, 10, 0))
+            {
+              ret = OK;
+            }
+          else
+            {
+              ret = -EINVAL;
+            }
+
+#ifdef CONFIG_NET_CAN_CANFD
+          struct flexcan_timeseg data_timing;
+          data_timing.bitrate = req->data_bitrate * 1000;
+          data_timing.samplep = req->data_samplep;
+
+          if (ret == OK && s32k1xx_bitratetotimeseg(&data_timing, 10, 1))
+            {
+              ret = OK;
+            }
+          else
+            {
+              ret = -EINVAL;
+            }
+#endif
+
+          if (ret == OK)
+            {
+              /* Reset CAN controller and start with new timings */
+
+              priv->arbi_timing = arbi_timing;
+#ifdef CONFIG_NET_CAN_CANFD
+              priv->data_timing = data_timing;
+#endif
+              s32k1xx_ifup(dev);
+            }
+        }
+        break;
+
+      default:
+        ret = -ENOTTY;
+        break;
+    }
+
+  return ret;
+}
+#endif /* CONFIG_NETDEV_IOCTL */
+
+/****************************************************************************
+ * Function: s32k1xx_initalize
+ *
+ * Description:
+ *   Initialize FLEXCAN device
+ *
+ * Input Parameters:
+ *   priv - Reference to the private FLEXCAN driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int s32k1xx_initialize(struct s32k1xx_driver_s *priv)
+{
+  uint32_t regval;
+  uint32_t i;
+
+  /* initialize CAN device */
+
+  s32k1xx_setenable(priv->base, 0);
+
+  /* Set SYS_CLOCK src */
+
+  regval  = getreg32(priv->base + S32K1XX_CAN_CTRL1_OFFSET);
+  regval |= CAN_CTRL1_CLKSRC;
+  putreg32(regval, priv->base + S32K1XX_CAN_CTRL1_OFFSET);
+
+  s32k1xx_setenable(priv->base, 1);
+
+  s32k1xx_reset(priv);
+
+  /* Enter freeze mode */
+
+  s32k1xx_setfreeze(priv->base, 1);
+  if (!s32k1xx_waitfreezeack_change(priv->base, 1))
+    {
+      ninfo("FLEXCAN: freeze fail\r\n");
+      return -1;
+    }
+
+#ifndef CONFIG_NET_CAN_CANFD
+  regval  = getreg32(priv->base + S32K1XX_CAN_CTRL1_OFFSET);
+  regval |= CAN_CTRL1_PRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
+            CAN_CTRL1_PROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
+            CAN_CTRL1_PSEG1(priv->arbi_timing.pseg1) |   /* Phase buffer segment 1 */
+            CAN_CTRL1_PSEG2(priv->arbi_timing.pseg2) |   /* Phase buffer segment 2 */
+            CAN_CTRL1_RJW(1);      /* Resynchronization jump width */
+  putreg32(regval, priv->base + S32K1XX_CAN_CTRL1_OFFSET);
+
+#else
+  regval  = getreg32(priv->base + S32K1XX_CAN_CBT_OFFSET);
+  regval |= CAN_CBT_BTF |         /* Enable extended bit timing
+                                   * configurations for CAN-FD for setting up
+                                   * separately nominal and data phase */
+            CAN_CBT_EPRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
+            CAN_CBT_EPROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
+            CAN_CBT_EPSEG1(priv->arbi_timing.pseg1) |   /* Phase buffer segment 1 */
+            CAN_CBT_EPSEG2(priv->arbi_timing.pseg2) |   /* Phase buffer segment 2 */
+            CAN_CBT_ERJW(1);      /* Resynchronization jump width */
+  putreg32(regval, priv->base + S32K1XX_CAN_CBT_OFFSET);
+
+  /* Enable CAN FD feature */
+
+  regval  = getreg32(priv->base + S32K1XX_CAN_MCR_OFFSET);
+  regval |= CAN_MCR_FDEN;
+  putreg32(regval, priv->base + S32K1XX_CAN_MCR_OFFSET);
+
+  regval  = getreg32(priv->base + S32K1XX_CAN_FDCBT_OFFSET);
+  regval |= CAN_FDCBT_FPRESDIV(priv->data_timing.presdiv) |  /* Prescaler divisor factor of 1 */
+            CAN_FDCBT_FPROPSEG(priv->data_timing.propseg) | /* Propagation
+                                                             * segment (only register that doesn't add 1) */
+            CAN_FDCBT_FPSEG1(priv->data_timing.pseg1) |    /* Phase buffer segment 1 */
+            CAN_FDCBT_FPSEG2(priv->data_timing.pseg2) |    /* Phase buffer segment 2 */
+            CAN_FDCBT_FRJW(priv->data_timing.pseg2);       /* Resynchorinzation jump width same as PSEG2 */
+  putreg32(regval, priv->base + S32K1XX_CAN_FDCBT_OFFSET);
+
+  /* Additional CAN-FD configurations */
+
+  regval  = getreg32(priv->base + S32K1XX_CAN_FDCTRL_OFFSET);
+
+  regval |= CAN_FDCTRL_FDRATE |     /* Enable bit rate switch in data phase of frame */
+            CAN_FDCTRL_TDCEN |      /* Enable transceiver delay compensation */
+            CAN_FDCTRL_TDCOFF(5) |  /* Setup 5 cycles for data phase sampling delay */
+            CAN_FDCTRL_MBDSR0(3);   /* Setup 64 bytes per message buffer (7 MB's) */
+  putreg32(regval, priv->base + S32K1XX_CAN_FDCTRL_OFFSET);
+
+  regval  = getreg32(priv->base + S32K1XX_CAN_CTRL2_OFFSET);
+  regval |= CAN_CTRL2_ISOCANFDEN;
+  putreg32(regval, priv->base + S32K1XX_CAN_CTRL2_OFFSET);
+#endif
+
+  for (i = TXMBCOUNT; i < TOTALMBCOUNT; i++)
+    {
+      priv->rx[i].id.w = 0x0;
+
+      /* FIXME sometimes we get a hard fault here */
+    }
+
+  putreg32(0x0, priv->base + S32K1XX_CAN_RXFGMASK_OFFSET);
+
+  for (i = 0; i < TOTALMBCOUNT; i++)
+    {
+      putreg32(0, priv->base + S32K1XX_CAN_RXIMR_OFFSET(i));
+    }
+
+  for (i = 0; i < RXMBCOUNT; i++)
+    {
+      ninfo("Set MB%i to receive %p\r\n", i, &priv->rx[i]);
+      priv->rx[i].cs.edl = 0x1;
+      priv->rx[i].cs.brs = 0x1;
+      priv->rx[i].cs.esi = 0x0;
+      priv->rx[i].cs.code = 4;
+      priv->rx[i].cs.srr = 0x0;
+      priv->rx[i].cs.ide = 0x1;
+      priv->rx[i].cs.rtr = 0x0;
+    }
+
+  putreg32(IFLAG1_RX, priv->base + S32K1XX_CAN_IFLAG1_OFFSET);
+  putreg32(IFLAG1_RX, priv->base + S32K1XX_CAN_IMASK1_OFFSET);
+
+  /* Exit freeze mode */
+
+  s32k1xx_setfreeze(priv->base, 0);
+  if (!s32k1xx_waitfreezeack_change(priv->base, 0))
+    {
+      ninfo("FLEXCAN: unfreeze fail\r\n");
+      return -1;
+    }
+
+  return 1;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_reset
+ *
+ * Description:
+ *   Put the EMAC in the non-operational, reset state
+ *
+ * Input Parameters:
+ *   priv - Reference to the private FLEXCAN driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void s32k1xx_reset(struct s32k1xx_driver_s *priv)
+{
+  uint32_t regval;
+  uint32_t i;
+
+  regval  = getreg32(priv->base + S32K1XX_CAN_MCR_OFFSET);
+  regval |= CAN_MCR_SOFTRST;
+  putreg32(regval, priv->base + S32K1XX_CAN_MCR_OFFSET);
+
+  if (!s32k1xx_waitmcr_change(priv->base, CAN_MCR_SOFTRST, 0))
+    {
+      nerr("Reset failed");
+      return;
+    }
+
+  regval  = getreg32(priv->base + S32K1XX_CAN_MCR_OFFSET);
+  regval &= ~(CAN_MCR_SUPV);
+  putreg32(regval, priv->base + S32K1XX_CAN_MCR_OFFSET);
+
+  /* Initialize all MB rx and tx */
+
+  for (i = 0; i < TOTALMBCOUNT; i++)
+    {
+      ninfo("MB %i %p\r\n", i, &priv->rx[i]);
+      ninfo("MB %i %p\r\n", i, &priv->rx[i].id.w);
+      priv->rx[i].cs.cs = 0x0;
+      priv->rx[i].id.w = 0x0;
+      priv->rx[i].data[0].w00 = 0x0;
+      priv->rx[i].data[1].w00 = 0x0;
+    }
+
+  regval  = getreg32(priv->base + S32K1XX_CAN_MCR_OFFSET);
+  regval |= CAN_MCR_SLFWAK | CAN_MCR_WRNEN | CAN_MCR_SRXDIS |
+            CAN_MCR_IRMQ | CAN_MCR_AEN |
+            (((TOTALMBCOUNT - 1) << CAN_MCR_MAXMB_SHIFT) &
+            CAN_MCR_MAXMB_MASK);
+  putreg32(regval, priv->base + S32K1XX_CAN_MCR_OFFSET);
+
+  regval  = CAN_CTRL2_RRS | CAN_CTRL2_EACEN;
+  putreg32(regval, priv->base + S32K1XX_CAN_CTRL2_OFFSET);
+
+  for (i = 0; i < TOTALMBCOUNT; i++)
+    {
+      putreg32(0, priv->base + S32K1XX_CAN_RXIMR_OFFSET(i));
+    }
+
+  /* Filtering catchall */
+
+  putreg32(0x3fffffff, priv->base + S32K1XX_CAN_RX14MASK_OFFSET);
+  putreg32(0x3fffffff, priv->base + S32K1XX_CAN_RX15MASK_OFFSET);
+  putreg32(0x3fffffff, priv->base + S32K1XX_CAN_RXMGMASK_OFFSET);
+  putreg32(0x0, priv->base + S32K1XX_CAN_RXFGMASK_OFFSET);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: s32k1xx_netinitialize
+ *
+ * Description:
+ *   Initialize the Ethernet controller and driver
+ *
+ * Input Parameters:
+ *   intf - In the case where there are multiple EMACs, this value
+ *          identifies which EMAC is to be initialized.
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+int s32k1xx_netinitialize(int intf)
+{
+  struct s32k1xx_driver_s *priv;
+  int ret;
+
+  switch (intf)
+    {
+#ifdef CONFIG_S32K1XX_FLEXCAN0
+    case 0:
+      priv               = &g_flexcan0;
+      memset(priv, 0, sizeof(struct s32k1xx_driver_s));
+      priv->base         = S32K1XX_FLEXCAN0_BASE;
+      priv->config       = &s32k1xx_flexcan0_config;
+
+      /* Default bitrate configuration */
+
+#  ifdef CONFIG_NET_CAN_CANFD
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_ARBI_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN0_ARBI_SAMPLEP;
+      priv->data_timing.bitrate = CONFIG_FLEXCAN0_DATA_BITRATE;
+      priv->data_timing.samplep = CONFIG_FLEXCAN0_DATA_SAMPLEP;
+#  else
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN0_SAMPLEP;
+#  endif
+      break;
+#endif
+
+#ifdef CONFIG_S32K1XX_FLEXCAN1
+    case 1:
+      priv         = &g_flexcan1;
+      memset(priv, 0, sizeof(struct s32k1xx_driver_s));
+      priv->base   = S32K1XX_FLEXCAN1_BASE;
+      priv->config = &s32k1xx_flexcan1_config;
+
+      /* Default bitrate configuration */
+
+#  ifdef CONFIG_NET_CAN_CANFD
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_ARBI_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN1_ARBI_SAMPLEP;
+      priv->data_timing.bitrate = CONFIG_FLEXCAN1_DATA_BITRATE;
+      priv->data_timing.samplep = CONFIG_FLEXCAN1_DATA_SAMPLEP;
+#  else
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN1_SAMPLEP;
+#  endif
+      break;
+#endif
+
+#ifdef CONFIG_S32K1XX_FLEXCAN2
+    case 2:
+      priv         = &g_flexcan2;
+      memset(priv, 0, sizeof(struct s32k1xx_driver_s));
+      priv->base   = S32K1XX_FLEXCAN2_BASE;
+      priv->config = &s32k1xx_flexcan2_config;
+
+      /* Default bitrate configuration */
+
+#  ifdef CONFIG_NET_CAN_CANFD
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_ARBI_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN2_ARBI_SAMPLEP;
+      priv->data_timing.bitrate = CONFIG_FLEXCAN2_DATA_BITRATE;
+      priv->data_timing.samplep = CONFIG_FLEXCAN2_DATA_SAMPLEP;
+#  else
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN2_SAMPLEP;
+#  endif
+      break;
+#endif
+
+    default:
+      return -ENODEV;
+    }
+
+  if (!s32k1xx_bitratetotimeseg(&priv->arbi_timing, 1, 0))
+    {
+      nerr("ERROR: Invalid CAN timings please try another sample point "
+           "or refer to the reference manual\n");
+      return -1;
+    }
+
+#ifdef CONFIG_NET_CAN_CANFD
+  if (!s32k1xx_bitratetotimeseg(&priv->data_timing, 1, 1))
+    {
+      nerr("ERROR: Invalid CAN data phase timings please try another "
+           "sample point or refer to the reference manual\n");
+      return -1;
+    }
+#endif
+
+  s32k1xx_pinconfig(priv->config->tx_pin);
+  s32k1xx_pinconfig(priv->config->rx_pin);
+  if (priv->config->enable_pin > 0)
+    {
+      s32k1xx_pinconfig(priv->config->enable_pin);
+      s32k1xx_gpiowrite(priv->config->enable_pin, priv->config->enable_high);
+    }
+
+  /* Attach the flexcan interrupt handler */
+
+  if (irq_attach(priv->config->bus_irq, s32k1xx_flexcan_interrupt, priv))
+    {
+      /* We could not attach the ISR to the interrupt */
+
+      nerr("ERROR: Failed to attach CAN bus IRQ\n");
+      return -EAGAIN;
+    }
+
+  if (irq_attach(priv->config->error_irq, s32k1xx_flexcan_interrupt, priv))
+    {
+      /* We could not attach the ISR to the interrupt */
+
+      nerr("ERROR: Failed to attach CAN error IRQ\n");
+      return -EAGAIN;
+    }
+
+  if (priv->config->lprx_irq > 0)
+    {
+      if (irq_attach(priv->config->lprx_irq,
+                     s32k1xx_flexcan_interrupt, priv))
+        {
+          /* We could not attach the ISR to the interrupt */
+
+          nerr("ERROR: Failed to attach CAN LPRX IRQ\n");
+          return -EAGAIN;
+        }
+    }
+
+  if (irq_attach(priv->config->mb_irq, s32k1xx_flexcan_interrupt, priv))
+    {
+      /* We could not attach the ISR to the interrupt */
+
+      nerr("ERROR: Failed to attach CAN OR'ed Message buffer (0-15) IRQ\n");
+      return -EAGAIN;
+    }
+
+  /* Initialize the driver structure */
+
+  priv->dev.d_ifup    = s32k1xx_ifup;      /* I/F up (new IP address) callback */
+  priv->dev.d_ifdown  = s32k1xx_ifdown;    /* I/F down callback */
+  priv->dev.d_txavail = s32k1xx_txavail;   /* New TX data callback */
+#ifdef CONFIG_NETDEV_IOCTL
+  priv->dev.d_ioctl   = s32k1xx_ioctl;     /* Support CAN ioctl() calls */
+#endif
+  priv->dev.d_private = (void *)priv;      /* Used to recover private state from dev */
+
+#ifdef TX_TIMEOUT_WQ
+  for (int i = 0; i < TXMBCOUNT; i++)
+    {
+      priv->txtimeout[i] = wd_create();    /* Create TX timeout timer */
+    }
+
+#endif
+  priv->rx            = (struct mb_s *)(priv->base + S32K1XX_CAN_MB_OFFSET);
+  priv->tx            = (struct mb_s *)(priv->base + S32K1XX_CAN_MB_OFFSET +
+                          (sizeof(struct mb_s) * RXMBCOUNT));
+
+  /* Put the interface in the down state.  This usually amounts to resetting
+   * the device and/or calling s32k1xx_ifdown().
+   */
+
+  ninfo("callbacks done\r\n");
+
+  s32k1xx_ifdown(&priv->dev);
+
+  /* Register the device with the OS so that socket IOCTLs can be performed */
+
+  netdev_register(&priv->dev, NET_LL_CAN);
+
+  UNUSED(ret);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: arm_netinitialize
+ *
+ * Description:
+ *   Initialize the first network interface.  If there are more than one
+ *   interface in the chip, then board-specific logic will have to provide
+ *   this function to determine which, if any, Ethernet controllers should
+ *   be initialized.
+ *
+ ****************************************************************************/
+
+#if !defined(CONFIG_NETDEV_LATEINIT)
+void arm_netinitialize(void)
+{
+#ifdef CONFIG_S32K1XX_FLEXCAN0
+  s32k1xx_netinitialize(0);
+#endif
+
+#ifdef CONFIG_S32K1XX_FLEXCAN1
+  s32k1xx_netinitialize(1);
+#endif
+
+#ifdef CONFIG_S32K1XX_FLEXCAN2
+  s32k1xx_netinitialize(2);
+#endif
+}
+#endif
+
+#endif /* CONFIG_S32K1XX_FLEXCAN */
diff --git a/arch/arm/src/s32k1xx/s32k1xx_rtc.h b/arch/arm/src/s32k1xx/s32k1xx_flexcan.h
similarity index 63%
copy from arch/arm/src/s32k1xx/s32k1xx_rtc.h
copy to arch/arm/src/s32k1xx/s32k1xx_flexcan.h
index b00c3d3..3b19332 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_rtc.h
+++ b/arch/arm/src/s32k1xx/s32k1xx_flexcan.h
@@ -1,5 +1,5 @@
-/****************************************************************************
- * arch/arm/src/s32k1xx/s32k1xx_rtc.h
+/************************************************************************************
+ * arch/arm/src/s32k1xx/s32k1xx_flexcan.h
  *
  *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <gn...@nuttx.org>
@@ -31,44 +31,28 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- ****************************************************************************/
+ ************************************************************************************/
 
-/****************************************************************************
- * Included Files
- ****************************************************************************/
+#ifndef __ARCH_ARM_SRC_S32K1XX_S32K1XX_FLEXCAN_H
+#define __ARCH_ARM_SRC_S32K1XX_S32K1XX_FLEXCAN_H
 
-#ifndef __ARCH_ARM_SRC_s32k1xx_s32k1xx_rtc_H
-#define __ARCH_ARM_SRC_s32k1xx_s32k1xx_rtc_H
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
 
 #include <nuttx/config.h>
 
-#include "chip.h"
-
-#ifdef CONFIG_S32K1XX_RTC
-
-/****************************************************************************
- * Preprocessor Definitions
- ****************************************************************************/
-
-#  ifdef CONFIG_RTC_DATETIME
-#    error CONFIG_RTC_DATETIME should not be selected with this driver
-#  endif
-
-#  ifdef CONFIG_RTC_PERIODIC
-#    error CONFIG_RTC_PERIODIC should not be selected with this driver
-#  endif
+#include "hardware/s32k1xx_flexcan.h"
 
-/* REVISIT: This is probably supportable.  The 47 bit timer does have
- * accuracy greater than 1 second.
- */
+#ifdef CONFIG_S32K1XX_FLEXCAN
 
-#  ifdef CONFIG_RTC_HIRES
-#    error CONFIG_RTC_PERIODIC should not be selected with this driver
-#  endif
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
 
-/****************************************************************************
+/************************************************************************************
  * Public Function Prototypes
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifndef __ASSEMBLY__
 
@@ -81,41 +65,51 @@ extern "C"
 #define EXTERN extern
 #endif
 
-/****************************************************************************
- * Name: up_rtc_initialize
+/************************************************************************************
+ * Function: arm_netinitialize
  *
  * Description:
- *   Initialize the rtc per the selected configuration.
+ *   Initialize the first network interface.  If there are more than one
+ *   interface in the chip, then board-specific logic will have to provide
+ *   this function to determine which, if any, Ethernet controllers should
+ *   be initialized.  Also prototyped in up_internal.h.
+ *
  * Input Parameters:
  *   None
  *
  * Returned Value:
- *   Zero (OK) on success; a negated errno on failure
+ *   OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *   Called very early in the initialization sequence.
  *
- ****************************************************************************/
+ ************************************************************************************/
 
-int up_rtc_initialize(void);
+void arm_netinitialize(void);
 
-/****************************************************************************
- * Name: s32k1xx_rtc_havesettime
+/************************************************************************************
+ * Function: s32k1xx_phy_boardinitialize
  *
  * Description:
- *   Check if the rtc time has been set
+ *   Some boards require specialized initialization of the PHY before it can be
+ *   used.  This may include such things as configuring GPIOs, resetting the PHY,
+ *   etc.  If CONFIG_S32K1XX_FLEXCAN_PHYINIT is defined in the configuration then the
+ *   board specific logic must provide s32k1xx_phyinitialize();  The i.MX RT Ethernet
+ *   driver will call this function one time before it first uses the PHY.
  *
  * Input Parameters:
- *   None
+ *   intf - Always zero for now.
  *
  * Returned Value:
- *   Returns true if RTC date-time have been previously set.
+ *   OK on success; Negated errno on failure.
  *
- ****************************************************************************/
-
-bool s32k1xx_rtc_havesettime(void);
+ ************************************************************************************/
 
 #undef EXTERN
 #if defined(__cplusplus)
 }
 #endif
+
 #endif /* __ASSEMBLY__ */
-#endif /* CONFIG_S32K1XX_RTC */
-#endif /* __ARCH_ARM_SRC_s32k1xx_s32k1xx_rtc_H */
+#endif /* CONFIG_S32K1XX_FLEXCAN */
+#endif /* __ARCH_ARM_SRC_S32K1XX_S32K1XX_FLEXCAN_H */
diff --git a/arch/arm/src/s32k1xx/s32k1xx_progmem.c b/arch/arm/src/s32k1xx/s32k1xx_progmem.c
new file mode 100644
index 0000000..78d6ad9
--- /dev/null
+++ b/arch/arm/src/s32k1xx/s32k1xx_progmem.c
@@ -0,0 +1,424 @@
+/******************************************************************************
+ * arch/arm/src/s32k1xx/s32k1xx_progmem.c
+ *
+ *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ *   Author:  Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ * Included Files
+ ******************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "arm_arch.h"
+
+#include "hardware/s32k1xx_ftfc.h"
+
+#include "s32k1xx_config.h"
+#include "s32k1xx_progmem.h"
+
+#include "arm_internal.h"
+
+#include <arch/board/board.h> /* Include last:  has dependencies */
+
+/******************************************************************************
+ * Pre-processor Definitions
+ ******************************************************************************/
+#ifdef CONFIG_MTD_SMART
+#  warning FlexNVM does not support back-to-back programming \
+         thus SmartFS willt not work
+#endif
+
+/******************************************************************************
+ * Private Data
+ ******************************************************************************/
+
+union fccob_flash_addr
+{
+    uint32_t addr;
+    struct
+    {
+        uint8_t fccob3;
+        uint8_t fccob2;
+        uint8_t fccob1;
+        uint8_t pad;
+    } fccobs;
+};
+
+/******************************************************************************
+ * Private Functions
+ ******************************************************************************/
+
+static inline void wait_ftfc_ready()
+{
+  while ((getreg8(S32K1XX_FTFC_FSTAT) & FTTC_FSTAT_CCIF) == 0)
+    {
+      /* Busy */
+    }
+}
+
+static uint32_t execute_ftfc_command()
+{
+  uint8_t regval;
+  uint32_t retval;
+
+  /* Clear CCIF to launch command */
+
+  regval = getreg8(S32K1XX_FTFC_FSTAT);
+  regval |= FTTC_FSTAT_CCIF;
+  putreg8(regval, S32K1XX_FTFC_FSTAT);
+
+  wait_ftfc_ready();
+
+  retval = getreg8(S32K1XX_FTFC_FSTAT);
+
+  if (retval & (FTTC_FSTAT_MGSTAT0 | FTTC_FSTAT_FPVIOL |
+                FTTC_FSTAT_ACCERR | FTTC_FSTAT_RDCOLERR))
+    {
+      return retval; /* Error has occured */
+    }
+  else
+    {
+      return 0; /* success */
+    }
+}
+
+/******************************************************************************
+ * Public Functions
+ ******************************************************************************/
+
+/******************************************************************************
+ * Name: up_progmem_neraseblocks
+ *
+ * Description:
+ *   Return number of erase blocks
+ *
+ ******************************************************************************/
+
+size_t up_progmem_neraseblocks(void)
+{
+  return S32K1XX_PROGMEM_SECTOR_COUNT;
+}
+
+/******************************************************************************
+ * Name: up_progmem_isuniform
+ *
+ * Description:
+ *   Is program memory uniform or page size differs?
+ *
+ ******************************************************************************/
+
+bool up_progmem_isuniform(void)
+{
+  return true;
+}
+
+/******************************************************************************
+ * Name: up_progmem_pagesize
+ *
+ * Description:
+ *   Return read/write page size
+ *
+ ******************************************************************************/
+
+size_t up_progmem_pagesize(size_t page)
+{
+  return (size_t)S32K1XX_PROGMEM_PAGE_SIZE;
+}
+
+/******************************************************************************
+ * Name: up_progmem_erasesize
+ *
+ * Description:
+ *   Return erase block size
+ *
+ ******************************************************************************/
+
+size_t up_progmem_erasesize(size_t block)
+{
+  return (size_t)S32K1XX_PROGMEM_BLOCK_SECTOR_SIZE;
+}
+
+/******************************************************************************
+ * Name: up_progmem_getpage
+ *
+ * Description:
+ *   Address to read/write page conversion
+ *
+ * Input Parameters:
+ *   addr - Address with or without flash offset (absolute or aligned to page0)
+ *
+ * Returned Value:
+ *   Page or negative value on error.  The following errors are reported
+ *   (errno is not set!):
+ *
+ *     -EFAULT: On invalid address
+ *
+ ******************************************************************************/
+
+ssize_t up_progmem_getpage(size_t addr)
+{
+  if (addr >= S32K1XX_PROGMEM_START_ADDR)
+    {
+      addr -= S32K1XX_PROGMEM_START_ADDR;
+    }
+
+  return (size_t)(addr / S32K1XX_PROGMEM_PAGE_SIZE);
+}
+
+/******************************************************************************
+ * Name: up_progmem_getaddress
+ *
+ * Description:
+ *   Read/write page to address conversion
+ *
+ * Input Parameters:
+ *   page - page index
+ *
+ * Returned Value:
+ *   Base address of given page, SIZE_MAX if page index is not valid.
+ *
+ ******************************************************************************/
+
+size_t up_progmem_getaddress(size_t page)
+{
+  return (size_t)(S32K1XX_PROGMEM_START_ADDR
+           + (page * S32K1XX_PROGMEM_PAGE_SIZE));
+}
+
+/******************************************************************************
+ * Name: up_progmem_eraseblock
+ *
+ * Description:
+ *   Erase selected block.
+ *
+ * Input Parameters:
+ *   block - The erase block index to be erased.
+ *
+ * Returned Value:
+ *   block size or negative value on error.  The following errors are reported
+ *   (errno is not set!):
+ *
+ *     -EFAULT: On invalid page
+ *     -EIO:    On unsuccessful erase
+ *     -EROFS:  On access to write protected area
+ *     -EACCES: Insufficient permissions (read/write protected)
+ *     -EPERM:  If operation is not permitted due to some other constraints
+ *              (i.e. some internal block is not running etc.)
+ *
+ ******************************************************************************/
+
+ssize_t up_progmem_eraseblock(size_t block)
+{
+  union fccob_flash_addr dest;
+
+  dest.addr = (block * S32K1XX_PROGMEM_BLOCK_SECTOR_SIZE) + 0x800000;
+
+  wait_ftfc_ready();
+
+  /* Clear FSTAT error bits */
+
+  putreg8(FTTC_FSTAT_FPVIOL | FTTC_FSTAT_ACCERR | FTTC_FSTAT_RDCOLERR,
+           S32K1XX_FTFC_FSTAT);
+
+  /* Set FTFC command */
+
+  putreg8(S32K1XX_FTFC_ERASE_SECTOR, S32K1XX_FTFC_FCCOB0);
+
+  /* Destination address of sector to erase */
+
+  putreg8(dest.fccobs.fccob1, S32K1XX_FTFC_FCCOB1);
+  putreg8(dest.fccobs.fccob2, S32K1XX_FTFC_FCCOB2);
+  putreg8(dest.fccobs.fccob3, S32K1XX_FTFC_FCCOB3);
+
+  if (execute_ftfc_command() & (FTTC_FSTAT_MGSTAT0 | FTTC_FSTAT_FPVIOL |
+      FTTC_FSTAT_ACCERR | FTTC_FSTAT_RDCOLERR))
+    {
+      return -EIO; /* Error has occured */
+    }
+
+  return (ssize_t)S32K1XX_PROGMEM_BLOCK_SECTOR_SIZE;
+}
+
+/******************************************************************************
+ * Name: up_progmem_ispageerased
+ *
+ * Description:
+ *   Checks whether page is erased
+ *
+ * Input Parameters:
+ *   page - The erase page index to be checked.
+ *
+ * Returned Value:
+ *   Returns number of bytes NOT erased or negative value on error. If it
+ *   returns zero then complete page is erased.
+ *
+ *   The following errors are reported:
+ *     -EFAULT: On invalid page
+ *
+ ******************************************************************************/
+
+ssize_t up_progmem_ispageerased(size_t page)
+{
+  const uint8_t *p;
+  int i;
+
+  if (page >= S32K1XX_PROGMEM_PAGE_COUNT)
+    {
+      return -EFAULT;
+    }
+
+  p = (const uint8_t *)up_progmem_getaddress(page);
+
+  for (i = 0; i < S32K1XX_PROGMEM_PAGE_SIZE; i++)
+    {
+      if (p[i] != 0xff)
+        {
+          break;
+        }
+    }
+
+  return (ssize_t)(S32K1XX_PROGMEM_PAGE_SIZE - i);
+}
+
+/******************************************************************************
+ * Name: up_progmem_write
+ *
+ * Description:
+ *   Program data at given address
+ *
+ *   Note: this function is not limited to single page and nor it requires
+ *   the address be aligned inside the page boundaries.
+ *
+ * Input Parameters:
+ *   addr  - Address with or without flash offset
+ *   buf   - Pointer to buffer
+ *   count - Number of bytes to write
+ *
+ * Returned Value:
+ *   Bytes written or negative value on error.  The following errors are
+ *   reported (errno is not set!)
+ *
+ *     EINVAL: If count is not aligned with the flash boundaries (i.e.
+ *             some MCU's require per half-word or even word access)
+ *     EFAULT: On invalid address
+ *     EIO:    On unsuccessful write, do note when this occurs the complete
+ *             flash sector is deemed to be unreadable and a read will most
+ *             likely result in a hard fault.
+ *     EROFS:  On access to write protected area
+ *     EACCES: Insufficient permissions (read/write protected)
+ *     EPERM:  If operation is not permitted due to some other constraints
+ *             (i.e. some internal block is not running etc.)
+ *
+ ******************************************************************************/
+
+ssize_t up_progmem_write(size_t addr, FAR const void *buf, size_t count)
+{
+  union fccob_flash_addr dest;
+  uint32_t i;
+  uint32_t j;
+  uint8_t *src;
+
+  if (addr >= S32K1XX_PROGMEM_START_ADDR)
+    {
+      addr -= S32K1XX_PROGMEM_START_ADDR;
+    }
+
+  if (count % S32K1XX_PROGMEM_DFLASH_WRITE_UNIT_SIZE != 0)
+    {
+      return -EINVAL;
+    }
+
+  src = (uint8_t *)buf;
+  dest.addr = addr + 0x800000;
+
+  for (i = 0; i < count / S32K1XX_PROGMEM_DFLASH_WRITE_UNIT_SIZE ; i++)
+    {
+      wait_ftfc_ready();
+
+      /* Clear FSTAT error bits */
+
+      putreg8(FTTC_FSTAT_FPVIOL | FTTC_FSTAT_ACCERR | FTTC_FSTAT_RDCOLERR,
+               S32K1XX_FTFC_FSTAT);
+
+      /* Set FTFC command */
+
+      putreg8(S32K1XX_FTFC_PROGRAM_PHRASE, S32K1XX_FTFC_FCCOB0);
+
+      /* Destination address */
+
+      putreg8(dest.fccobs.fccob1, S32K1XX_FTFC_FCCOB1);
+      putreg8(dest.fccobs.fccob2, S32K1XX_FTFC_FCCOB2);
+      putreg8(dest.fccobs.fccob3, S32K1XX_FTFC_FCCOB3);
+
+      /* Write data */
+
+      for (j = 0; j < S32K1XX_PROGMEM_DFLASH_WRITE_UNIT_SIZE; j++)
+        {
+          putreg8(src[j], S32K1XX_FTFC_BASE + j + 0x8);
+        }
+
+      if (execute_ftfc_command() & (FTTC_FSTAT_MGSTAT0 | FTTC_FSTAT_FPVIOL |
+          FTTC_FSTAT_ACCERR | FTTC_FSTAT_RDCOLERR))
+        {
+          return -EIO; /* Error has occured */
+        }
+
+      dest.addr = dest.addr + S32K1XX_PROGMEM_DFLASH_WRITE_UNIT_SIZE;
+      src = src + S32K1XX_PROGMEM_DFLASH_WRITE_UNIT_SIZE;
+    }
+
+  return count;
+}
+
+void s32k1xx_progmem_init()
+{
+  /* Disable D-Flash Cache */
+
+  putreg32(0xc706b030, S32K1XX_MSCM_BASE + 0x404);
+
+  /* Setup D-flash partitioning */
+
+  putreg8(S32K1XX_FTFC_PROGRAM_PARTITION, S32K1XX_FTFC_FCCOB0); /* Command */
+
+  putreg8(0x0, S32K1XX_FTFC_FCCOB1); /* CSEc key size */
+  putreg8(0x0, S32K1XX_FTFC_FCCOB2); /* uSFE */
+  putreg8(0x0, S32K1XX_FTFC_FCCOB3); /* Disable FlexRAM EEE */
+  putreg8(0xf, S32K1XX_FTFC_FCCOB4); /* EEE Partition code */
+  putreg8(0x0, S32K1XX_FTFC_FCCOB5); /* DE  Partition code */
+
+  execute_ftfc_command();
+}
diff --git a/boards/arm/s32k1xx/s32k118evb/src/s32k1xx_bringup.c b/arch/arm/src/s32k1xx/s32k1xx_progmem.h
similarity index 59%
copy from boards/arm/s32k1xx/s32k118evb/src/s32k1xx_bringup.c
copy to arch/arm/src/s32k1xx/s32k1xx_progmem.h
index 495468a..9b97d77 100644
--- a/boards/arm/s32k1xx/s32k118evb/src/s32k1xx_bringup.c
+++ b/arch/arm/src/s32k1xx/s32k1xx_progmem.h
@@ -1,8 +1,8 @@
-/****************************************************************************
- * boards/arm/s32k1xx/s32k118evb/src/s32k1xx_bringup.c
+/******************************************************************************
+ * arch/arm/src/s32k1xx/s32k1xx_progmem.h
  *
  *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
- *   Author: Gregory Nutt <gn...@nuttx.org>
+ *   Author:  Gregory Nutt <gn...@nuttx.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,79 +31,65 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- ****************************************************************************/
+ ******************************************************************************/
 
-/****************************************************************************
+#ifndef __ARCH_ARM_SRC_S32K1XX_PROGMEM_H
+#define __ARCH_ARM_SRC_S32K1XX_PROGMEM_H
+
+/******************************************************************************
  * Included Files
- ****************************************************************************/
+ ******************************************************************************/
 
 #include <nuttx/config.h>
+#include <nuttx/compiler.h>
 
 #include <sys/types.h>
-#include <sys/mount.h>
-#include <syslog.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "up_internal.h"
+#include "s32k1xx_config.h"
+
+/******************************************************************************
+ * Pre-processor Definitions
+ ******************************************************************************/
+
+#define DFLASH_SIZE CONFIG_PROGMEM_SIZE
 
-#ifdef CONFIG_BUTTONS
-#  include <nuttx/input/buttons.h>
+#if (DFLASH_SIZE % 2) == 1
+# error "Progmem size has to be a multiple of 2"
 #endif
 
-#ifdef CONFIG_USERLED
-#  include <nuttx/leds/userled.h>
+#if defined(CONFIG_ARCH_CHIP_S32K14X) && (DFLASH_SIZE > 64)
+# error "Progmem size is bigger than FlexNVM size"
 #endif
 
-#include "s32k118evb.h"
+#if defined(CONFIG_ARCH_CHIP_S32K11X) && (DFLASH_SIZE > 32)
+# error "Progmem size is bigger than FlexNVM size"
+#endif
 
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
+/* Base address of the flash segment used for progmem. */
 
-/****************************************************************************
- * Name: s32k1xx_bringup
- *
- * Description:
- *   Perform architecture-specific initialization
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=y :
- *     Called from board_late_initialize().
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_LIB_BOARDCTL=y :
- *     Called from the NSH library
- *
- ****************************************************************************/
+#define S32K1XX_PROGMEM_START_ADDR            0x10000000
 
-int s32k1xx_bringup(void)
-{
-  int ret = OK;
+#define S32K1XX_PROGMEM_BLOCK_COUNT           1
 
-#ifdef CONFIG_BUTTONS
-  /* Register the BUTTON driver */
+#define S32K1XX_PROGMEM_BLOCK_SIZE            DFLASH_SIZE * 1024
 
-  ret = btn_lower_initialize("/dev/buttons");
-  if (ret < 0)
-    {
-      syslog(LOG_ERR, "ERROR: btn_lower_initialize() failed: %d\n", ret);
-    }
-#endif
+#define S32K1XX_PROGMEM_BLOCK_SECTOR_SIZE     2048
 
-#ifdef CONFIG_USERLED
-  /* Register the LED driver */
+#define S32K1XX_PROGMEM_PAGE_SIZE             8
 
-  ret = userled_lower_initialize("/dev/userleds");
-  if (ret < 0)
-    {
-      syslog(LOG_ERR, "ERROR: userled_lower_initialize() failed: %d\n", ret);
-    }
-#endif
+#define S32K1XX_PROGMEM_SECTOR_COUNT          S32K1XX_PROGMEM_BLOCK_SIZE / S32K1XX_PROGMEM_BLOCK_SECTOR_SIZE
 
-#ifdef CONFIG_FS_PROCFS
-  /* Mount the procfs file system */
+#define S32K1XX_PROGMEM_PAGE_COUNT            (S32K1XX_PROGMEM_BLOCK_SIZE / S32K1XX_PROGMEM_PAGE_SIZE)
 
-  ret = mount(NULL, "/proc", "procfs", 0, NULL);
-  if (ret < 0)
-    {
-      syslog(LOG_ERR, "ERROR: Failed to mount procfs at /proc: %d\n", ret);
-    }
-#endif
+#define S32K1XX_PROGMEM_DFLASH_WRITE_UNIT_SIZE 8
+
+/******************************************************************************
+ * Public Function Prototypes
+ ******************************************************************************/
+
+void s32k1xx_progmem_init();
 
-  return ret;
-}
+#endif /* __ARCH_ARM_SRC_S32K1XX_PROGMEM_H */
diff --git a/arch/arm/src/s32k1xx/s32k1xx_rtc.c b/arch/arm/src/s32k1xx/s32k1xx_rtc.c
index 7c70b76..85e7ad2 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_rtc.c
+++ b/arch/arm/src/s32k1xx/s32k1xx_rtc.c
@@ -157,11 +157,11 @@ int up_rtc_initialize(void)
 
   putreg32(regval, S32K1XX_RTC_CR);
 
-  /* Set LPO_1KHZ clock source */
+  /* Increment on 32.768Khz clock */
 
   regval  = getreg32(S32K1XX_RTC_CR);
 
-  regval |= RTC_CR_LPOS;
+  regval &= ~RTC_CR_LPOS;
 
   putreg32(regval, S32K1XX_RTC_CR);
 
@@ -181,6 +181,18 @@ int up_rtc_initialize(void)
 
   putreg32(regval, S32K1XX_RTC_CR);
 
+  regval  = getreg32(S32K1XX_RTC_SR);
+
+  if (regval & RTC_SR_TIF)
+    {
+      regval &= ~RTC_SR_TCE;
+      putreg32(regval, S32K1XX_RTC_SR);
+
+      /* Write TSR register to clear invalid */
+
+      putreg32(0x0, S32K1XX_RTC_TSR);
+    }
+
   /* Enable the rtc */
 
   s32k1xx_rtc_enable();
@@ -207,7 +219,7 @@ int up_rtc_initialize(void)
  *   The current time in seconds
  *
  ****************************************************************************/
-
+#ifndef CONFIG_RTC_HIRES
 time_t up_rtc_time(void)
 {
   uint32_t regval;
@@ -217,6 +229,55 @@ time_t up_rtc_time(void)
 
   return (uint32_t) (regval);
 }
+#endif
+
+/****************************************************************************
+ * Name: up_rtc_gettime
+ *
+ * Description:
+ *   Get the current time from the high resolution RTC clock/counter.  This
+ *   interface is only supported by the high-resolution RTC/counter hardware
+ *   implementation. It is used to replace the system timer.
+ *
+ * Input Parameters:
+ *   tp - The location to return the high resolution time value.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RTC_HIRES
+int up_rtc_gettime(FAR struct timespec *tp)
+{
+  irqstate_t flags;
+  uint32_t seconds;
+  uint32_t prescaler;
+  uint32_t prescaler2;
+
+  /* Get prescaler and seconds register. this is in a loop which ensures that
+   * registers will be re-read if during the reads the prescaler has
+   * wrapped-around.
+   */
+
+  flags = enter_critical_section();
+  do
+    {
+      prescaler = getreg32(S32K1XX_RTC_TPR);
+      seconds = getreg32(S32K1XX_RTC_TSR);
+      prescaler2 = getreg32(S32K1XX_RTC_TPR);
+    }
+  while (prescaler > prescaler2);
+
+  leave_critical_section(flags);
+
+  /* Build seconds + nanoseconds from seconds and prescaler register */
+
+  tp->tv_sec = seconds;
+  tp->tv_nsec = prescaler * (1000000000 / CONFIG_RTC_FREQUENCY);
+  return OK;
+}
+#endif
 
 /****************************************************************************
  * Name: up_rtc_settime
@@ -237,12 +298,28 @@ int up_rtc_settime(FAR const struct timespec *ts)
 {
   DEBUGASSERT(ts != NULL);
 
+  irqstate_t flags;
+  uint32_t seconds;
+  uint32_t prescaler;
+
+  seconds = ts->tv_sec;
+#ifdef CONFIG_RTC_HIRES
+  prescaler = ts->tv_nsec * (CONFIG_RTC_FREQUENCY / 1000000000);
+#else
+  prescaler = 0;
+#endif
+
+  flags = enter_critical_section();
+
   s32k1xx_rtc_disable();
 
-  putreg32((uint32_t)ts->tv_sec, S32K1XX_RTC_TSR);
+  putreg32(prescaler, S32K1XX_RTC_TPR); /* Always write prescaler first */
+  putreg32(seconds, S32K1XX_RTC_TSR);
 
   s32k1xx_rtc_enable();
 
+  leave_critical_section(flags);
+
   return OK;
 }
 
diff --git a/arch/arm/src/s32k1xx/s32k1xx_rtc.h b/arch/arm/src/s32k1xx/s32k1xx_rtc.h
index b00c3d3..35ce10d 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_rtc.h
+++ b/arch/arm/src/s32k1xx/s32k1xx_rtc.h
@@ -58,14 +58,6 @@
 #    error CONFIG_RTC_PERIODIC should not be selected with this driver
 #  endif
 
-/* REVISIT: This is probably supportable.  The 47 bit timer does have
- * accuracy greater than 1 second.
- */
-
-#  ifdef CONFIG_RTC_HIRES
-#    error CONFIG_RTC_PERIODIC should not be selected with this driver
-#  endif
-
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
diff --git a/arch/arm/src/s32k1xx/s32k1xx_start.c b/arch/arm/src/s32k1xx/s32k1xx_start.c
index 542e152..430d52d 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_start.c
+++ b/arch/arm/src/s32k1xx/s32k1xx_start.c
@@ -65,6 +65,10 @@
 #include "hardware/s32k1xx_mpu.h"
 #endif
 
+#ifdef CONFIG_S32K1XX_PROGMEM
+#include "s32k1xx_progmem.h"
+#endif
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
@@ -353,6 +357,10 @@ void __start(void)
 #endif
   showprogress('E');
 
+#ifdef CONFIG_S32K1XX_PROGMEM
+  s32k1xx_progmem_init();
+#endif
+
   /* For the case of the separate user-/kernel-space build, perform whatever
    * platform specific initialization of the user memory is required.
    * Normally this just means initializing the user space .data and .bss
diff --git a/boards/arm/s32k1xx/rddrone-uavcan144/src/s32k1xx_bringup.c b/boards/arm/s32k1xx/rddrone-uavcan144/src/s32k1xx_bringup.c
index bc0abbf..0adea7e 100644
--- a/boards/arm/s32k1xx/rddrone-uavcan144/src/s32k1xx_bringup.c
+++ b/boards/arm/s32k1xx/rddrone-uavcan144/src/s32k1xx_bringup.c
@@ -143,5 +143,16 @@ int s32k1xx_bringup(void)
 #endif
 #endif
 
+#ifdef CONFIG_S32K1XX_PROGMEM
+  FAR struct mtd_dev_s *mtd;
+  int minor = 0;
+
+  mtd = progmem_initialize();
+  if (!mtd)
+    {
+      syslog(LOG_ERR, "ERROR: progmem_initialize failed\n");
+    }
+#endif
+
   return ret;
 }
diff --git a/boards/arm/s32k1xx/rddrone-uavcan144/src/s32k1xx_clockconfig.c b/boards/arm/s32k1xx/rddrone-uavcan144/src/s32k1xx_clockconfig.c
index 3cf1656..126904f 100644
--- a/boards/arm/s32k1xx/rddrone-uavcan144/src/s32k1xx_clockconfig.c
+++ b/boards/arm/s32k1xx/rddrone-uavcan144/src/s32k1xx_clockconfig.c
@@ -165,7 +165,7 @@ const struct clock_configuration_s g_initial_clkconfig =
     },
     .lpoclk        =                                   /* Low Power Clock configuration. */
     {
-      .rtc_source  = SIM_RTCCLK_SEL_SOSCDIV1_CLK,      /* RTCCLKSEL */
+      .rtc_source  = SIM_RTCCLK_SEL_LPO_32K,           /* RTCCLKSEL */
       .lpo_source  = SIM_LPO_CLK_SEL_LPO_128K,         /* LPOCLKSEL */
       .initialize  = true,                             /* Initialize */
       .lpo32k      = true,                             /* LPO32KCLKEN */
diff --git a/boards/arm/s32k1xx/rddrone-uavcan146/configs/nsh/defconfig b/boards/arm/s32k1xx/rddrone-uavcan146/configs/nsh/defconfig
index 5b68d47..ef17982 100644
--- a/boards/arm/s32k1xx/rddrone-uavcan146/configs/nsh/defconfig
+++ b/boards/arm/s32k1xx/rddrone-uavcan146/configs/nsh/defconfig
@@ -69,3 +69,32 @@ CONFIG_SYSTEM_NSH=y
 CONFIG_SYSTEM_NSH_CXXINITIALIZE=y
 CONFIG_SYSTEM_SPITOOL=y
 CONFIG_USER_ENTRYPOINT="nsh_main"
+CONFIG_S32K1XX_FLEXCAN0=y
+CONFIG_S32K1XX_FLEXCAN1=y
+CONFIG_NET=y
+CONFIG_NET_ETHERNET=n
+CONFIG_NET_IPv4=n
+CONFIG_ARCH_HAVE_NET=y
+CONFIG_NET_READAHEAD=y
+CONFIG_NSOCKET_DESCRIPTORS=8
+CONFIG_NET_NACTIVESOCKETS=16
+CONFIG_NET_SOCKOPTS=y
+CONFIG_NET_CANPROTO_OPTIONS=y
+CONFIG_NET_CAN=y
+CONFIG_NET_CAN_HAVE_TX_DEADLINE=y
+CONFIG_CAN_CONNS=4
+CONFIG_NET_CAN_SOCK_OPTS=y
+CONFIG_NET_CAN_RAW_FILTER_MAX=32
+CONFIG_NET_TIMESTAMP=y
+CONFIG_NET_CMSG=y
+CONFIG_NETDEV_IFINDEX=y
+CONFIG_NSH_NETINIT=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_LPNTHREADS=1
+CONFIG_SCHED_LPWORKPRIORITY=100
+CONFIG_SCHED_LPWORKSTACKSIZE=2048
+CONFIG_S32K1XX_RTC=y
+CONFIG_RTC=y
+CONFIG_RTC_HIRES=y
+CONFIG_RTC_FREQUENCY=32768
+CONFIG_SIG_DEFAULT=y
diff --git a/boards/arm/s32k1xx/rddrone-uavcan146/include/board.h b/boards/arm/s32k1xx/rddrone-uavcan146/include/board.h
index c0ab9d1..fbe1f79 100644
--- a/boards/arm/s32k1xx/rddrone-uavcan146/include/board.h
+++ b/boards/arm/s32k1xx/rddrone-uavcan146/include/board.h
@@ -150,4 +150,14 @@
 #define PIN_LPI2C0_SCL   PIN_LPI2C0_SCL_2   /* PTA3 */
 #define PIN_LPI2C0_SDA	 PIN_LPI2C0_SDA_2   /* PTA2 */
 
+/* CAN selections ***********************************************************/
+#define PIN_CAN0_TX      PIN_CAN0_TX_4      /* PTE5 */
+#define PIN_CAN0_RX      PIN_CAN0_RX_4      /* PTE4 */
+#define PIN_CAN0_ENABLE  (GPIO_OUTPUT | PIN_PORTE | PIN11 )
+#define CAN0_ENABLE_OUT  0
+#define PIN_CAN1_TX      PIN_CAN1_TX_1      /* PTA13 */
+#define PIN_CAN1_RX      PIN_CAN1_RX_1      /* PTA12 */
+#define PIN_CAN1_ENABLE  (GPIO_OUTPUT | PIN_PORTE | PIN10 )
+#define CAN1_ENABLE_OUT  0
+
 #endif  /* __BOARDS_ARM_RDDRONE_UAVCAN146_INCLUDE_BOARD_H */
diff --git a/boards/arm/s32k1xx/rddrone-uavcan146/src/rddrone-uavcan146.h b/boards/arm/s32k1xx/rddrone-uavcan146/src/rddrone-uavcan146.h
index 2ab91bd..e5532a2 100644
--- a/boards/arm/s32k1xx/rddrone-uavcan146/src/rddrone-uavcan146.h
+++ b/boards/arm/s32k1xx/rddrone-uavcan146/src/rddrone-uavcan146.h
@@ -69,14 +69,12 @@
 #define GPIO_LED_G     (PIN_PTD16 | GPIO_LOWDRIVE | GPIO_OUTPUT_ZERO)
 #define GPIO_LED_B     (PIN_PTD0  | GPIO_LOWDRIVE | GPIO_OUTPUT_ZERO)
 
-/* Buttons.  The RDDRONE-UAVCAN146 supports two buttons:
+/* Buttons.  The RDDRONE-UAVCAN146 supports one button:
  *
- *   SW2  PTC12
- *   SW3  PTC13
+ *   SW3  PTC14
  */
 
-#define GPIO_SW2       (PIN_PTC12 | PIN_INT_BOTH)
-#define GPIO_SW3       (PIN_PTC13 | PIN_INT_BOTH)
+#define GPIO_SW3       (PIN_PTC14 | PIN_INT_BOTH)
 
 /* SPI chip selects */
 
@@ -86,7 +84,7 @@
 
 /* Count of peripheral clock user configurations */
 
-#define NUM_OF_PERIPHERAL_CLOCKS_0 11
+#define NUM_OF_PERIPHERAL_CLOCKS_0 12
 
 /****************************************************************************
  * Public Types
diff --git a/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_bringup.c b/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_bringup.c
index 300f08e..c792546 100644
--- a/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_bringup.c
+++ b/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_bringup.c
@@ -140,5 +140,16 @@ int s32k1xx_bringup(void)
 #endif
 #endif
 
+#ifdef CONFIG_S32K1XX_PROGMEM
+  FAR struct mtd_dev_s *mtd;
+  int minor = 0;
+
+  mtd = progmem_initialize();
+  if (!mtd)
+    {
+      syslog(LOG_ERR, "ERROR: progmem_initialize failed\n");
+    }
+#endif
+
   return ret;
 }
diff --git a/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_buttons.c b/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_buttons.c
index ff48587..b51acee 100644
--- a/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_buttons.c
+++ b/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_buttons.c
@@ -33,10 +33,9 @@
  *
  ****************************************************************************/
 
-/* The RDDRONE-UAVCAN146 supports two buttons:
+/* The RDDRONE-UAVCAN146 supports one button:
  *
- *   SW2  PTC12
- *   SW3  PTC13
+ *   SW3  PTC14
  */
 
 /****************************************************************************
@@ -77,7 +76,6 @@ uint32_t board_button_initialize(void)
 {
   /* Configure the GPIO pins as interrupting inputs. */
 
-  s32k1xx_pinconfig(GPIO_SW2);
   s32k1xx_pinconfig(GPIO_SW3);
   return NUM_BUTTONS;
 }
@@ -90,11 +88,6 @@ uint32_t board_buttons(void)
 {
   uint32_t ret = 0;
 
-  if (s32k1xx_gpioread(GPIO_SW2))
-    {
-      ret |= BUTTON_SW2_BIT;
-    }
-
   if (s32k1xx_gpioread(GPIO_SW3))
     {
       ret |= BUTTON_SW3_BIT;
@@ -133,11 +126,7 @@ int board_button_irq(int id, xcpt_t irqhandler, FAR void *arg)
 
   /* Map the button id to the GPIO bit set. */
 
-  if (id == BUTTON_SW2)
-    {
-      pinset = GPIO_SW2;
-    }
-  else if (id == BUTTON_SW3)
+  if (id == BUTTON_SW3)
     {
       pinset = GPIO_SW3;
     }
diff --git a/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_clockconfig.c b/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_clockconfig.c
index 6ec3679..badf9be 100644
--- a/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_clockconfig.c
+++ b/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_clockconfig.c
@@ -165,7 +165,7 @@ const struct clock_configuration_s g_initial_clkconfig =
     },
     .lpoclk        =                                   /* Low Power Clock configuration. */
     {
-      .rtc_source  = SIM_RTCCLK_SEL_SOSCDIV1_CLK,      /* RTCCLKSEL */
+      .rtc_source  = SIM_RTCCLK_SEL_LPO_32K,           /* RTCCLKSEL */
       .lpo_source  = SIM_LPO_CLK_SEL_LPO_128K,         /* LPOCLKSEL */
       .initialize  = true,                             /* Initialize */
       .lpo32k      = true,                             /* LPO32KCLKEN */
diff --git a/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_periphclocks.c b/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_periphclocks.c
index e6f84c9..9fd3f72 100644
--- a/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_periphclocks.c
+++ b/boards/arm/s32k1xx/rddrone-uavcan146/src/s32k1xx_periphclocks.c
@@ -73,7 +73,7 @@ const struct peripheral_clock_config_s g_peripheral_clockconfig0[] =
 {
   {
     .clkname = FLEXCAN0_CLK,
-#ifdef CONFIG_S32K1XX_FLEXCAN
+#ifdef CONFIG_S32K1XX_FLEXCAN0
     .clkgate = true,
 #else
     .clkgate = false,
@@ -81,7 +81,7 @@ const struct peripheral_clock_config_s g_peripheral_clockconfig0[] =
   },
   {
     .clkname = FLEXCAN1_CLK,
-#ifdef CONFIG_S32K1XX_FLEXCAN
+#ifdef CONFIG_S32K1XX_FLEXCAN1
     .clkgate = true,
 #else
     .clkgate = false,
@@ -143,6 +143,14 @@ const struct peripheral_clock_config_s g_peripheral_clockconfig0[] =
     .clkname = PORTE_CLK,
     .clkgate = true,
   },
+  {
+    .clkname = RTC0_CLK,
+#ifdef CONFIG_S32K1XX_RTC
+    .clkgate = true,
+#else
+    .clkgate = false,
+#endif
+  },
 };
 
 /****************************************************************************
diff --git a/boards/arm/s32k1xx/s32k118evb/src/s32k1xx_bringup.c b/boards/arm/s32k1xx/s32k118evb/src/s32k1xx_bringup.c
index 495468a..81615fc 100644
--- a/boards/arm/s32k1xx/s32k118evb/src/s32k1xx_bringup.c
+++ b/boards/arm/s32k1xx/s32k118evb/src/s32k1xx_bringup.c
@@ -105,5 +105,16 @@ int s32k1xx_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_S32K1XX_PROGMEM
+  FAR struct mtd_dev_s *mtd;
+  int minor = 0;
+
+  mtd = progmem_initialize();
+  if (!mtd)
+    {
+      syslog(LOG_ERR, "ERROR: progmem_initialize failed\n");
+    }
+#endif
+
   return ret;
 }
diff --git a/boards/arm/s32k1xx/s32k144evb/src/s32k1xx_bringup.c b/boards/arm/s32k1xx/s32k144evb/src/s32k1xx_bringup.c
index 607b3d4..ec88b7b 100644
--- a/boards/arm/s32k1xx/s32k144evb/src/s32k1xx_bringup.c
+++ b/boards/arm/s32k1xx/s32k144evb/src/s32k1xx_bringup.c
@@ -137,5 +137,16 @@ int s32k1xx_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_S32K1XX_PROGMEM
+  FAR struct mtd_dev_s *mtd;
+  int minor = 0;
+
+  mtd = progmem_initialize();
+  if (!mtd)
+    {
+      syslog(LOG_ERR, "ERROR: progmem_initialize failed\n");
+    }
+#endif
+
   return ret;
 }
diff --git a/boards/arm/s32k1xx/s32k144evb/src/s32k1xx_clockconfig.c b/boards/arm/s32k1xx/s32k144evb/src/s32k1xx_clockconfig.c
index e907882..fe3e263 100644
--- a/boards/arm/s32k1xx/s32k144evb/src/s32k1xx_clockconfig.c
+++ b/boards/arm/s32k1xx/s32k144evb/src/s32k1xx_clockconfig.c
@@ -165,7 +165,7 @@ const struct clock_configuration_s g_initial_clkconfig =
     },
     .lpoclk        =                                   /* Low Power Clock configuration. */
     {
-      .rtc_source  = SIM_RTCCLK_SEL_SOSCDIV1_CLK,      /* RTCCLKSEL */
+      .rtc_source  = SIM_RTCCLK_SEL_LPO_32K,           /* RTCCLKSEL */
       .lpo_source  = SIM_LPO_CLK_SEL_LPO_128K,         /* LPOCLKSEL */
       .initialize  = true,                             /* Initialize */
       .lpo32k      = true,                             /* LPO32KCLKEN */
diff --git a/boards/arm/s32k1xx/s32k146evb/src/s32k1xx_bringup.c b/boards/arm/s32k1xx/s32k146evb/src/s32k1xx_bringup.c
index 830d574..c04617a 100644
--- a/boards/arm/s32k1xx/s32k146evb/src/s32k1xx_bringup.c
+++ b/boards/arm/s32k1xx/s32k146evb/src/s32k1xx_bringup.c
@@ -137,5 +137,16 @@ int s32k1xx_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_S32K1XX_PROGMEM
+  FAR struct mtd_dev_s *mtd;
+  int minor = 0;
+
+  mtd = progmem_initialize();
+  if (!mtd)
+    {
+      syslog(LOG_ERR, "ERROR: progmem_initialize failed\n");
+    }
+#endif
+
   return ret;
 }
diff --git a/boards/arm/s32k1xx/s32k146evb/src/s32k1xx_clockconfig.c b/boards/arm/s32k1xx/s32k146evb/src/s32k1xx_clockconfig.c
index 37596e6..3481093 100644
--- a/boards/arm/s32k1xx/s32k146evb/src/s32k1xx_clockconfig.c
+++ b/boards/arm/s32k1xx/s32k146evb/src/s32k1xx_clockconfig.c
@@ -165,7 +165,7 @@ const struct clock_configuration_s g_initial_clkconfig =
     },
     .lpoclk        =                                   /* Low Power Clock configuration. */
     {
-      .rtc_source  = SIM_RTCCLK_SEL_SOSCDIV1_CLK,      /* RTCCLKSEL */
+      .rtc_source  = SIM_RTCCLK_SEL_LPO_32K,           /* RTCCLKSEL */
       .lpo_source  = SIM_LPO_CLK_SEL_LPO_128K,         /* LPOCLKSEL */
       .initialize  = true,                             /* Initialize */
       .lpo32k      = true,                             /* LPO32KCLKEN */
diff --git a/boards/arm/s32k1xx/s32k148evb/include/board.h b/boards/arm/s32k1xx/s32k148evb/include/board.h
index be8ccdf..06f3c3c 100644
--- a/boards/arm/s32k1xx/s32k148evb/include/board.h
+++ b/boards/arm/s32k1xx/s32k148evb/include/board.h
@@ -133,4 +133,12 @@
 #define PIN_LPUART1_RX    PIN_LPUART1_RX_1  /* PTC6 */
 #define PIN_LPUART1_TX    PIN_LPUART1_TX_1  /* PTC7 */
 
+/* CAN selections ***********************************************************/
+#define PIN_CAN0_TX      PIN_CAN0_TX_1
+#define PIN_CAN0_RX      PIN_CAN0_RX_1
+#define PIN_CAN1_TX      PIN_CAN1_TX_1
+#define PIN_CAN1_RX      PIN_CAN1_RX_1
+#define PIN_CAN2_TX      PIN_CAN2_TX_1
+#define PIN_CAN2_RX      PIN_CAN2_RX_1
+
 #endif  /* __BOARDS_ARM_S32K148EVB_INCLUDE_BOARD_H */
diff --git a/boards/arm/s32k1xx/s32k148evb/src/s32k1xx_clockconfig.c b/boards/arm/s32k1xx/s32k148evb/src/s32k1xx_clockconfig.c
index d41060b..ac597ce 100644
--- a/boards/arm/s32k1xx/s32k148evb/src/s32k1xx_clockconfig.c
+++ b/boards/arm/s32k1xx/s32k148evb/src/s32k1xx_clockconfig.c
@@ -165,7 +165,7 @@ const struct clock_configuration_s g_initial_clkconfig =
     },
     .lpoclk        =                                   /* Low Power Clock configuration. */
     {
-      .rtc_source  = SIM_RTCCLK_SEL_SOSCDIV1_CLK,      /* RTCCLKSEL */
+      .rtc_source  = SIM_RTCCLK_SEL_LPO_32K,           /* RTCCLKSEL */
       .lpo_source  = SIM_LPO_CLK_SEL_LPO_128K,         /* LPOCLKSEL */
       .initialize  = true,                             /* Initialize */
       .lpo32k      = true,                             /* LPO32KCLKEN */


[incubator-nuttx] 01/04: net: Add SocketCAN support

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 55d9e5f7af05e75ca62f57863b880d723aa83c56
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Mon Jun 15 10:23:25 2020 +0200

    net: Add SocketCAN support
---
 fs/vfs/fs_write.c                                  |   9 +-
 include/net/if.h                                   |  19 +-
 include/netpacket/can.h                            | 140 ++++
 include/nuttx/can.h                                | 319 ++++++++
 include/nuttx/can/error.h                          | 129 ++++
 include/nuttx/mm/iob.h                             |  10 +-
 include/nuttx/net/can.h                            | 122 +++
 include/nuttx/net/ioctl.h                          |   8 +
 include/nuttx/net/net.h                            |  31 +-
 include/nuttx/wqueue.h                             |   3 +-
 include/sys/socket.h                               |  13 +
 libs/libc/net/lib_recvmsg.c                        |   7 +-
 libs/libc/net/lib_sendmsg.c                        |   4 +-
 net/Kconfig                                        |   1 +
 net/Makefile                                       |   1 +
 net/bluetooth/bluetooth_sockif.c                   |  38 +-
 net/can/Kconfig                                    |  97 +++
 net/can/Make.defs                                  |  48 ++
 net/can/can.h                                      | 385 ++++++++++
 net/can/can_callback.c                             | 242 ++++++
 net/can/can_conn.c                                 | 223 ++++++
 net/can/can_getsockopt.c                           | 220 ++++++
 net/can/can_input.c                                | 204 +++++
 .../net/lib_recvmsg.c => net/can/can_notifier.c    |  56 +-
 net/can/can_poll.c                                 |  88 +++
 net/can/can_recvfrom.c                             | 838 +++++++++++++++++++++
 net/can/can_send.c                                 | 441 +++++++++++
 net/can/can_setsockopt.c                           | 177 +++++
 net/{netlink/netlink_sockif.c => can/can_sockif.c} | 723 +++++++++---------
 net/devif/Make.defs                                |   4 +
 net/devif/devif.h                                  | 112 +--
 .../local_sendpacket.c => devif/devif_cansend.c}   | 124 +--
 net/devif/devif_poll.c                             |  48 ++
 net/icmp/icmp_sockif.c                             |  18 +-
 net/icmpv6/icmpv6_sockif.c                         |  32 +-
 net/ieee802154/ieee802154_sockif.c                 |  47 +-
 net/inet/inet_sockif.c                             |   4 +
 net/local/local_sendpacket.c                       |   1 +
 net/local/local_sockif.c                           |  12 +-
 net/net_initialize.c                               |   7 +
 net/netdev/Kconfig                                 |   8 +
 net/netdev/netdev_ioctl.c                          |  48 ++
 net/netdev/netdev_register.c                       |  12 +
 net/netlink/netlink_sockif.c                       |   4 +
 net/pkt/pkt_sockif.c                               |   4 +
 net/socket/Kconfig                                 |  24 +
 net/socket/Make.defs                               |   6 +
 net/socket/getsockopt.c                            |  19 +
 net/socket/net_sockif.c                            |   7 +
 net/socket/recvmsg.c                               | 244 ++++++
 net/socket/sendmsg.c                               | 243 ++++++
 net/socket/setsockopt.c                            |  29 +
 net/socket/socket.h                                |   2 +-
 net/utils/net_lock.c                               |  51 ++
 54 files changed, 5085 insertions(+), 621 deletions(-)

diff --git a/fs/vfs/fs_write.c b/fs/vfs/fs_write.c
index 6e9a379..d1b7f03 100644
--- a/fs/vfs/fs_write.c
+++ b/fs/vfs/fs_write.c
@@ -86,7 +86,8 @@
  *
  ****************************************************************************/
 
-ssize_t file_write(FAR struct file *filep, FAR const void *buf, size_t nbytes)
+ssize_t file_write(FAR struct file *filep, FAR const void *buf,
+                   size_t nbytes)
 {
   FAR struct inode *inode;
 
@@ -149,8 +150,10 @@ ssize_t nx_write(int fd, FAR const void *buf, size_t nbytes)
 
   if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS)
     {
-#ifdef CONFIG_NET_TCP
-      /* Write to a socket descriptor is equivalent to send with flags == 0. */
+#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_CAN)
+      /* Write to a socket descriptor is equivalent to
+       * send with flags == 0.
+       */
 
       ret = nx_send(fd, buf, nbytes, 0);
 #else
diff --git a/include/net/if.h b/include/net/if.h
index 0b90045..0332ab7 100644
--- a/include/net/if.h
+++ b/include/net/if.h
@@ -136,6 +136,18 @@ struct mii_ioctl_data_s
   uint16_t val_out;     /* PHY output data */
 };
 
+/* Structure passed to get or set the CAN bitrate
+ * SIOCxCANBITRATE ioctl commands.
+ */
+
+struct can_ioctl_data_s
+{
+  uint16_t arbi_bitrate; /* Classic CAN / Arbitration phase bitrate kbit/s */
+  uint16_t arbi_samplep; /* Classic CAN / Arbitration phase input % */
+  uint16_t data_bitrate; /* Data phase bitrate kbit/s */
+  uint16_t data_samplep; /* Data phase sample point % */
+};
+
 /* There are two forms of the I/F request structure.  One for IPv6 and one for IPv4.
  * Notice that they are (and must be) cast compatible and really different only
  * in the size of the structure allocation.
@@ -158,6 +170,7 @@ struct lifreq
     uint8_t                   lifru_flags;              /* Interface flags */
     struct mii_ioctl_notify_s llfru_mii_notify;         /* PHY event notification */
     struct mii_ioctl_data_s   lifru_mii_data;           /* MII request data */
+    struct can_ioctl_data_s   lifru_can_data;           /* CAN bitrate request data */
   } lifr_ifru;
 };
 
@@ -196,6 +209,9 @@ struct lifconf
 struct ifreq
 {
   char                        ifr_name[IFNAMSIZ];       /* Network device name (e.g. "eth0") */
+#ifdef CONFIG_NETDEV_IFINDEX
+  int16_t                     ifr_ifindex;              /* Interface index */
+#endif
   union
   {
     struct sockaddr           ifru_addr;                /* IP Address */
@@ -208,6 +224,7 @@ struct ifreq
     uint8_t                   ifru_flags;               /* Interface flags */
     struct mii_ioctl_notify_s ifru_mii_notify;          /* PHY event notification */
     struct mii_ioctl_data_s   ifru_mii_data;            /* MII request data */
+    struct can_ioctl_data_s   ifru_can_data;            /* CAN bitrate request data */
   } ifr_ifru;
 };
 
@@ -226,7 +243,7 @@ struct ifreq
 #define ifr_mii_val_in        ifr_ifru.ifru_mii_data.val_in  /* PHY input data */
 #define ifr_mii_val_out       ifr_ifru.ifru_mii_data.val_out /* PHY output data */
 
-/* Used only with the SIOCGIFCONF IOCTL command*/
+/* Used only with the SIOCGIFCONF IOCTL command */
 
 struct ifconf
 {
diff --git a/include/netpacket/can.h b/include/netpacket/can.h
new file mode 100644
index 0000000..4ee6645
--- /dev/null
+++ b/include/netpacket/can.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+ * include/netpacket/can.h
+ * Definitions for use with AF_PACKET sockets
+ *
+ * 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 __INCLUDE_NETPACKET_CAN_H
+#define __INCLUDE_NETPACKET_CAN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Special address description flags for the CAN_ID */
+
+#define CAN_EFF_FLAG 0x80000000  /* EFF/SFF is set in the MSB */
+#define CAN_RTR_FLAG 0x40000000  /* Remote transmission request */
+#define CAN_ERR_FLAG 0x20000000  /* Error message frame */
+
+/* Valid bits in CAN ID for frame formats */
+
+#define CAN_SFF_MASK 0x000007ff  /* Standard frame format (SFF) */
+#define CAN_EFF_MASK 0x1fffffff  /* Extended frame format (EFF) */
+#define CAN_ERR_MASK 0x1fffffff  /* Omit EFF, RTR, ERR flags */
+
+#define CAN_MTU		(sizeof(struct can_frame))
+#define CANFD_MTU	(sizeof(struct canfd_frame))
+
+/* PF_CAN protocols */
+
+#define CAN_RAW      1           /* RAW sockets */
+#define CAN_BCM      2           /* Broadcast Manager */
+#define CAN_TP16     3           /* VAG Transport Protocol v1.6 */
+#define CAN_TP20     4           /* VAG Transport Protocol v2.0 */
+#define CAN_MCNET    5           /* Bosch MCNet */
+#define CAN_ISOTP    6           /* ISO 15765-2 Transport Protocol */
+#define CAN_J1939    7           /* SAE J1939 */
+#define CAN_NPROTO   8
+
+/* CAN_RAW socket options */
+
+#define CAN_RAW_FILTER         (__SO_PROTOCOL + 0)     
+                                 /* set 0 .. n can_filter(s) */
+#define CAN_RAW_ERR_FILTER     (__SO_PROTOCOL + 1)      
+                                 /* set filter for error frames */
+#define CAN_RAW_LOOPBACK       (__SO_PROTOCOL + 2)      
+                                 /* local loopback (default:on) */
+#define CAN_RAW_RECV_OWN_MSGS  (__SO_PROTOCOL + 3)	     
+                                 /* receive my own msgs (default:off) */
+#define CAN_RAW_FD_FRAMES      (__SO_PROTOCOL + 4)      
+                                 /* allow CAN FD frames (default:off) */
+#define CAN_RAW_JOIN_FILTERS   (__SO_PROTOCOL + 5)     
+                                 /* all filters must match to trigger */
+#define CAN_RAW_TX_DEADLINE    (__SO_PROTOCOL + 6)
+                                 /* Abort frame when deadline passed */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Controller Area Network Identifier structure
+ *
+ *   Bit 0-28: CAN identifier (11/29 bit)
+ *   Bit 29:   Error message frame flag (0 = data frame, 1 = error message)
+ *   Bit 30:   Remote transmission request flag (1 = rtr frame)
+ *   Bit 31:   Frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
+ */
+
+typedef uint32_t canid_t;
+
+/* The sockaddr structure for CAN sockets
+ *
+ *   can_family:  Address family number AF_CAN.
+ *   can_ifindex: CAN network interface index.
+ *   can_addr:    Protocol specific address information
+ */
+
+struct sockaddr_can
+{
+  sa_family_t can_family;
+  int16_t     can_ifindex;
+  union
+  {
+    /* Transport protocol class address information */
+
+    struct
+    {
+      canid_t rx_id;
+      canid_t tx_id;
+    } tp;
+
+    /* J1939 address information */
+
+    struct
+    {
+      /* 8 byte name when using dynamic addressing */
+
+      uint64_t name;
+
+      /* pgn:
+       *   8 bit: PS in PDU2 case, else 0
+       *   8 bit: PF
+       *   1 bit: DP
+       *   1 bit: reserved
+       */
+
+      uint32_t pgn;
+
+      /* 1 byte address */
+
+      uint8_t addr;
+    } j1939;
+  } can_addr;
+};
+
+#endif /* __INCLUDE_NETPACKET_CAN_H */
diff --git a/include/nuttx/can.h b/include/nuttx/can.h
new file mode 100644
index 0000000..c681b32
--- /dev/null
+++ b/include/nuttx/can.h
@@ -0,0 +1,319 @@
+/************************************************************************************
+ * include/nuttx/can/can.h
+ *
+ *   Copyright (C) 2008, 2009, 2011-2012, 2015-2017, 2019 Gregory Nutt. All rights
+ *     reserved.
+ *   Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_CAN_CAN_H
+#define __INCLUDE_NUTTX_CAN_CAN_H
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#ifdef CONFIG_CAN_TXREADY
+#  include <nuttx/wqueue.h>
+#endif
+
+#include <queue.h>
+
+#ifdef CONFIG_NET_CAN
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+
+/* Ioctl Commands *******************************************************************/
+
+/* Ioctl commands supported by the upper half CAN driver.
+ *
+ * CANIOC_RTR:
+ *   Description:  Send the remote transmission request and wait for the response.
+ *   Argument:     A reference to struct canioc_rtr_s
+ *
+ * Ioctl commands that may or may not be supported by the lower half CAN driver.
+ *
+ * CANIOC_ADD_STDFILTER:
+ *   Description:    Add an address filter for a standard 11 bit address.
+ *   Argument:       A reference to struct canioc_stdfilter_s
+ *   Returned Value: A non-negative filter ID is returned on success.
+ *                   Otherwise -1 (ERROR) is returned with the errno
+ *                   variable set to indicate the nature of the error.
+ *   Dependencies:   None
+ *
+ * CANIOC_ADD_EXTFILTER:
+ *   Description:    Add an address filter for a extended 29 bit address.
+ *   Argument:       A reference to struct canioc_extfilter_s
+ *   Returned Value: A non-negative filter ID is returned on success.
+ *                   Otherwise -1 (ERROR) is returned with the errno
+ *                   variable set to indicate the nature of the error.
+ *   Dependencies:   Requires CONFIG_CAN_EXTID=y
+ *
+ * CANIOC_DEL_STDFILTER:
+ *   Description:    Remove an address filter for a standard 11 bit address.
+ *   Argument:       The filter index previously returned by the
+ *                   CANIOC_ADD_STDFILTER command
+ *   Returned Value: Zero (OK) is returned on success.  Otherwise -1 (ERROR)
+ *                   is returned with the errno variable set to indicate the
+ *                   nature of the error.
+ *   Dependencies:   None
+ *
+ * CANIOC_DEL_EXTFILTER:
+ *   Description:    Remove an address filter for a standard 29 bit address.
+ *   Argument:       The filter index previously returned by the
+ *                   CANIOC_ADD_EXTFILTER command
+ *   Returned Value: Zero (OK) is returned on success.  Otherwise -1 (ERROR)
+ *                   is returned with the errno variable set to indicate the
+ *                   nature of the error.
+ *   Dependencies:   Requires CONFIG_CAN_EXTID=y
+ *
+ * CANIOC_GET_BITTIMING:
+ *   Description:    Return the current bit timing settings
+ *   Argument:       A pointer to a write-able instance of struct
+ *                   canioc_bittiming_s in which current bit timing values
+ *                   will be returned.
+ *   Returned Value: Zero (OK) is returned on success.  Otherwise -1 (ERROR)
+ *                   is returned with the errno variable set to indicate the
+ *                   nature of the error.
+ *   Dependencies:   None
+ *
+ * CANIOC_SET_BITTIMING:
+ *   Description:    Set new current bit timing values
+ *   Argument:       A pointer to a read-able instance of struct
+ *                   canioc_bittiming_s in which the new bit timing values
+ *                   are provided.
+ *   Returned Value: Zero (OK) is returned on success.  Otherwise -1 (ERROR)
+ *                   is returned with the errno variable set to indicate the
+ *                   nature of the error.
+ *   Dependencies:   None
+ *
+ * CANIOC_GET_CONNMODES:
+ *   Description:    Get the current bus connection modes
+ *   Argument:       A pointer to a write-able instance of struct
+ *                   canioc_connmodes_s in which the new bus modes will be returned.
+ *   Returned Value: Zero (OK) is returned on success.  Otherwise -1 (ERROR)
+ *                   is returned with the errno variable set to indicate the
+ *                   nature of the error.
+ *   Dependencies:   None
+ *
+ * CANIOC_SET_CONNMODES:
+ *   Description:    Set new bus connection modes values
+ *   Argument:       A pointer to a read-able instance of struct
+ *                   canioc_connmodes_s in which the new bus modes are provided.
+ *   Returned Value: Zero (OK) is returned on success.  Otherwise -1 (ERROR)
+ *                   is returned with the errno variable set to indicate the
+ *                   nature of the error.
+ *   Dependencies:   None
+ *
+ * CANIOC_BUSOFF_RECOVERY:
+ *   Description:    Initiates the BUS-OFF recovery sequence
+ *   Argument:       None
+ *   Returned Value: Zero (OK) is returned on success.  Otherwise -1 (ERROR)
+ *                   is returned with the errno variable set to indicate the
+ *                   nature of the error.
+ *   Dependencies:   None
+ */
+
+#define CANIOC_RTR                _CANIOC(1)
+#define CANIOC_GET_BITTIMING      _CANIOC(2)
+#define CANIOC_SET_BITTIMING      _CANIOC(3)
+#define CANIOC_ADD_STDFILTER      _CANIOC(4)
+#define CANIOC_ADD_EXTFILTER      _CANIOC(5)
+#define CANIOC_DEL_STDFILTER      _CANIOC(6)
+#define CANIOC_DEL_EXTFILTER      _CANIOC(7)
+#define CANIOC_GET_CONNMODES      _CANIOC(8)
+#define CANIOC_SET_CONNMODES      _CANIOC(9)
+#define CANIOC_BUSOFF_RECOVERY    _CANIOC(10)
+
+#define CAN_FIRST                 0x0001         /* First common command */
+#define CAN_NCMDS                 10             /* Ten common commands */
+
+/* User defined ioctl commands are also supported. These will be forwarded
+ * by the upper-half CAN driver to the lower-half CAN driver via the co_ioctl()
+ * method fo the CAN lower-half interface.  However, the lower-half driver
+ * must reserve a block of commands as follows in order prevent IOCTL
+ * command numbers from overlapping.
+ *
+ * This is generally done as follows.  The first reservation for CAN driver A would
+ * look like:
+ *
+ *   CAN_A_FIRST                 (CAN_FIRST + CAN_NCMDS)     <- First command
+ *   CAN_A_NCMDS                 42                          <- Number of commands
+ *
+ * IOCTL commands for CAN driver A would then be defined in a CAN A header file like:
+ *
+ *   CANIOC_A_CMD1               _CANIOC(CAN_A_FIRST+0)
+ *   CANIOC_A_CMD2               _CANIOC(CAN_A_FIRST+1)
+ *   CANIOC_A_CMD3               _CANIOC(CAN_A_FIRST+2)
+ *   ...
+ *   CANIOC_A_CMD42              _CANIOC(CAN_A_FIRST+41)
+ *
+ * The next reservation would look like:
+ *
+ *   CAN_B_FIRST                 (CAN_A_FIRST + CAN_A_NCMDS) <- Next command
+ *   CAN_B_NCMDS                 77                          <- Number of commands
+ */
+
+/* CAN payload length and DLC definitions according to ISO 11898-1 */
+
+#define CAN_MAX_DLC 8
+#define CAN_MAX_DLEN 8
+
+/* CAN FD payload length and DLC definitions according to ISO 11898-7 */
+
+#define CANFD_MAX_DLC 15
+#define CANFD_MAX_DLEN 64
+
+/* Defined bits for canfd_frame.flags
+ *
+ * The use of struct canfd_frame implies the Extended Data Length (EDL) bit to
+ * be set in the CAN frame bitstream on the wire. The EDL bit switch turns
+ * the CAN controllers bitstream processor into the CAN FD mode which creates
+ * two new options within the CAN FD frame specification:
+ *
+ * Bit Rate Switch - to indicate a second bitrate is/was used for the payload
+ * Error State Indicator - represents the error state of the transmitting node
+ *
+ * As the CANFD_ESI bit is internally generated by the transmitting CAN
+ * controller only the CANFD_BRS bit is relevant for real CAN controllers when
+ * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make
+ * sense for virtual CAN interfaces to test applications with echoed frames.
+ */
+
+#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
+#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
+
+#define CAN_INV_FILTER     0x20000000U /* to be set in can_filter.can_id */
+
+/************************************************************************************
+ * Public Types
+ ************************************************************************************/
+
+typedef FAR void *CAN_HANDLE;
+
+struct can_response_s
+{
+  sq_entry_t flink;
+
+  /* Message-specific data may follow */
+}; /* FIXME remove */
+
+typedef uint32_t canid_t;
+
+/* Controller Area Network Error Message Frame Mask structure
+ *
+ * bit 0-28  : error class mask (see include/uapi/linux/can/error.h)
+ * bit 29-31 : set to zero
+ */
+
+typedef uint32_t can_err_mask_t;
+
+/* struct can_frame - basic CAN frame structure
+ * can_id:  CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
+ * can_dlc: frame payload length in byte (0 .. 8) aka data length code
+ *          N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
+ *          mapping of the 'data length code' to the real payload length
+ * __pad:   padding
+ * __res0:  reserved / padding
+ * __res1:  reserved / padding
+ * data:    CAN frame payload (up to 8 byte)
+ */
+
+struct can_frame
+{
+  canid_t can_id;   /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+  uint8_t  can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
+  uint8_t  __pad;   /* padding */
+  uint8_t  __res0;  /* reserved / padding */
+  uint8_t  __res1;  /* reserved / padding */
+  uint8_t  data[CAN_MAX_DLEN] __attribute__((aligned(8)));
+};
+
+/* struct canfd_frame - CAN flexible data rate frame structure
+ * can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
+ * len:    frame payload length in byte (0 .. CANFD_MAX_DLEN)
+ * flags:  additional flags for CAN FD
+ * __res0: reserved / padding
+ * __res1: reserved / padding
+ * data:   CAN FD frame payload (up to CANFD_MAX_DLEN byte)
+ */
+
+struct canfd_frame
+{
+  canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+  uint8_t len;     /* frame payload length in byte */
+  uint8_t flags;   /* additional flags for CAN FD */
+  uint8_t __res0;  /* reserved / padding */
+  uint8_t __res1;  /* reserved / padding */
+  uint8_t data[CANFD_MAX_DLEN] __attribute__((aligned(8)));
+};
+
+/* struct can_filter - CAN ID based filter in can_register().
+ * can_id:   relevant bits of CAN ID which are not masked out.
+ * can_mask: CAN mask (see description)
+ *
+ * Description:
+ * A filter matches, when
+ *
+ *   <received_can_id> & mask == can_id & mask
+ *
+ * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
+ * filter for error message frames (CAN_ERR_FLAG bit set in mask).
+ */
+
+struct can_filter
+{
+  canid_t can_id;
+  canid_t can_mask;
+};
+
+/************************************************************************************
+ * Public Function Prototypes
+ ************************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* CONFIG_CAN */
+#endif /* __INCLUDE_NUTTX_CAN_CAN_H */
diff --git a/include/nuttx/can/error.h b/include/nuttx/can/error.h
new file mode 100644
index 0000000..cf5fec6
--- /dev/null
+++ b/include/nuttx/can/error.h
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */
+
+/************************************************************************************
+ * linux/can/error.h
+ *
+ * Definitions of the CAN error messages to be filtered and passed to the
+ * user.
+ *
+ * Author: Oliver Hartkopp <ol...@volkswagen.de>
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ ************************************************************************************/
+
+#ifndef _UAPI_CAN_ERROR_H
+#define _UAPI_CAN_ERROR_H
+
+#define CAN_ERR_DLC 8 /* dlc for error message frames */
+
+/* error class (mask) in can_id */
+#define CAN_ERR_TX_TIMEOUT   0x00000001U /* TX timeout (by netdevice driver) */
+#define CAN_ERR_LOSTARB      0x00000002U /* lost arbitration    / data[0]    */
+#define CAN_ERR_CRTL         0x00000004U /* controller problems / data[1]    */
+#define CAN_ERR_PROT         0x00000008U /* protocol violations / data[2..3] */
+#define CAN_ERR_TRX          0x00000010U /* transceiver status  / data[4]    */
+#define CAN_ERR_ACK          0x00000020U /* received no ACK on transmission */
+#define CAN_ERR_BUSOFF       0x00000040U /* bus off */
+#define CAN_ERR_BUSERROR     0x00000080U /* bus error (may flood!) */
+#define CAN_ERR_RESTARTED    0x00000100U /* controller restarted */
+
+/* arbitration lost in bit ... / data[0] */
+#define CAN_ERR_LOSTARB_UNSPEC   0x00 /* unspecified */
+
+/* else bit number in bitstream */
+
+/* error status of CAN-controller / data[1] */
+#define CAN_ERR_CRTL_UNSPEC      0x00 /* unspecified */
+#define CAN_ERR_CRTL_RX_OVERFLOW 0x01 /* RX buffer overflow */
+#define CAN_ERR_CRTL_TX_OVERFLOW 0x02 /* TX buffer overflow */
+#define CAN_ERR_CRTL_RX_WARNING  0x04 /* reached warning level for RX errors */
+#define CAN_ERR_CRTL_TX_WARNING  0x08 /* reached warning level for TX errors */
+#define CAN_ERR_CRTL_RX_PASSIVE  0x10 /* reached error passive status RX */
+#define CAN_ERR_CRTL_TX_PASSIVE  0x20 /* reached error passive status TX */
+                                      /* (at least one error counter exceeds */
+                                      /* the protocol-defined level of 127)  */
+#define CAN_ERR_CRTL_ACTIVE      0x40 /* recovered to error active state */
+
+/* error in CAN protocol (type) / data[2] */
+#define CAN_ERR_PROT_UNSPEC      0x00 /* unspecified */
+#define CAN_ERR_PROT_BIT         0x01 /* single bit error */
+#define CAN_ERR_PROT_FORM        0x02 /* frame format error */
+#define CAN_ERR_PROT_STUFF       0x04 /* bit stuffing error */
+#define CAN_ERR_PROT_BIT0        0x08 /* unable to send dominant bit */
+#define CAN_ERR_PROT_BIT1        0x10 /* unable to send recessive bit */
+#define CAN_ERR_PROT_OVERLOAD    0x20 /* bus overload */
+#define CAN_ERR_PROT_ACTIVE      0x40 /* active error announcement */
+#define CAN_ERR_PROT_TX          0x80 /* error occurred on transmission */
+
+/* error in CAN protocol (location) / data[3] */
+#define CAN_ERR_PROT_LOC_UNSPEC  0x00 /* unspecified */
+#define CAN_ERR_PROT_LOC_SOF     0x03 /* start of frame */
+#define CAN_ERR_PROT_LOC_ID28_21 0x02 /* ID bits 28 - 21 (SFF: 10 - 3) */
+#define CAN_ERR_PROT_LOC_ID20_18 0x06 /* ID bits 20 - 18 (SFF: 2 - 0 )*/
+#define CAN_ERR_PROT_LOC_SRTR    0x04 /* substitute RTR (SFF: RTR) */
+#define CAN_ERR_PROT_LOC_IDE     0x05 /* identifier extension */
+#define CAN_ERR_PROT_LOC_ID17_13 0x07 /* ID bits 17-13 */
+#define CAN_ERR_PROT_LOC_ID12_05 0x0f /* ID bits 12-5 */
+#define CAN_ERR_PROT_LOC_ID04_00 0x0e /* ID bits 4-0 */
+#define CAN_ERR_PROT_LOC_RTR     0x0c /* RTR */
+#define CAN_ERR_PROT_LOC_RES1    0x0d /* reserved bit 1 */
+#define CAN_ERR_PROT_LOC_RES0    0x09 /* reserved bit 0 */
+#define CAN_ERR_PROT_LOC_DLC     0x0b /* data length code */
+#define CAN_ERR_PROT_LOC_DATA    0x0a /* data section */
+#define CAN_ERR_PROT_LOC_CRC_SEQ 0x08 /* CRC sequence */
+#define CAN_ERR_PROT_LOC_CRC_DEL 0x18 /* CRC delimiter */
+#define CAN_ERR_PROT_LOC_ACK     0x19 /* ACK slot */
+#define CAN_ERR_PROT_LOC_ACK_DEL 0x1b /* ACK delimiter */
+#define CAN_ERR_PROT_LOC_EOF     0x1a /* end of frame */
+#define CAN_ERR_PROT_LOC_INTERM  0x12 /* intermission */
+
+/* error status of CAN-transceiver / data[4] */
+
+                                            /* CANH CANL */
+#define CAN_ERR_TRX_UNSPEC             0x00 /* 0000 0000 */
+#define CAN_ERR_TRX_CANH_NO_WIRE       0x04 /* 0000 0100 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_BAT  0x05 /* 0000 0101 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_VCC  0x06 /* 0000 0110 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_GND  0x07 /* 0000 0111 */
+#define CAN_ERR_TRX_CANL_NO_WIRE       0x40 /* 0100 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_BAT  0x50 /* 0101 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_VCC  0x60 /* 0110 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_GND  0x70 /* 0111 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_CANH 0x80 /* 1000 0000 */
+
+/* controller specific additional information / data[5..7] */
+
+#endif /* _UAPI_CAN_ERROR_H */
diff --git a/include/nuttx/mm/iob.h b/include/nuttx/mm/iob.h
index 8984af6..32c0bfd 100644
--- a/include/nuttx/mm/iob.h
+++ b/include/nuttx/mm/iob.h
@@ -54,6 +54,7 @@
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
+
 /* Configuration ************************************************************/
 
 /* I/O buffer allocation logic supports a throttle value for read-ahead
@@ -220,6 +221,9 @@ enum iob_user_e
 #ifdef CONFIG_WIRELESS_BLUETOOTH
   IOBUSER_WIRELESS_BLUETOOTH,
 #endif
+#ifdef CONFIG_NET_CAN
+  IOBUSER_NET_CAN_READAHEAD,
+#endif
   IOBUSER_GLOBAL,
   IOBUSER_NENTRIES /* MUST BE LAST ENTRY */
 };
@@ -248,7 +252,8 @@ void iob_initialize(void);
  * Name: iob_alloc
  *
  * Description:
- *   Allocate an I/O buffer by taking the buffer at the head of the free list.
+ *   Allocate an I/O buffer by taking the buffer at the head of the free
+ *   list.
  *
  ****************************************************************************/
 
@@ -586,7 +591,8 @@ void iob_dump(FAR const char *msg, FAR struct iob_s *iob, unsigned int len,
  * Name: iob_getuserstats
  *
  * Description:
- *   Return a reference to the IOB usage statistics for the IOB consumer/producer
+ *   Return a reference to the IOB usage statistics for the IOB
+ *   consumer/producer
  *
  * Input Parameters:
  *   userid - id representing the IOB producer/consumer
diff --git a/include/nuttx/net/can.h b/include/nuttx/net/can.h
new file mode 100644
index 0000000..f9cbe93
--- /dev/null
+++ b/include/nuttx/net/can.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+ * include/nuttx/net/can.h
+ * Macros and definitions for the CAN link layer.
+ *
+ *   Copyright (C) 2007, 2009-2012, 2015 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Derived from uIP with has a similar BSD-styple license:
+ *
+ *   Author: Adam Dunkels <ad...@dunkels.com>
+ *   Copyright (c) 2001-2003, Adam Dunkels.
+ *   All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_NET_CAN_H
+#define __INCLUDE_NUTTX_NET_CAN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/can.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#ifdef CONFIG_NET_CAN_CANFD
+#define NET_CAN_PKTSIZE sizeof(struct canfd_frame)
+#else
+#define NET_CAN_PKTSIZE sizeof(struct can_frame)
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CAN_CANFD
+
+/* Lookup tables convert can_dlc <-> payload len */
+
+extern const uint8_t can_dlc_to_len[16];
+extern const uint8_t len_to_can_dlc[65];
+
+#endif
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_input
+ *
+ * Description:
+ *   Handle incoming CAN frame input
+ *
+ *   This function provides the interface between CAN device drivers and
+ *   SocketCAN logic.  All frames that are received should be provided to
+ *   can_input() prior to other routing.
+ *
+ * Input Parameters:
+ *   dev - The device driver structure containing the received packet
+ *
+ * Returned Value:
+ *   OK    The packet has been processed  and can be deleted
+ *   ERROR There is a matching connection, but could not dispatch the packet
+ *         yet.  Useful when a packet arrives before a recv call is in
+ *         place.
+ *
+ * Assumptions:
+ *   Called from the CAN device diver with the network locked.
+ *
+ ****************************************************************************/
+
+struct net_driver_s; /* Forward reference */
+int can_input(FAR struct net_driver_s *dev);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_NET_CAN_H */
diff --git a/include/nuttx/net/ioctl.h b/include/nuttx/net/ioctl.h
index 4717542..6f2f20e 100644
--- a/include/nuttx/net/ioctl.h
+++ b/include/nuttx/net/ioctl.h
@@ -85,6 +85,9 @@
 #define SIOCGIFCONF      _SIOC(0x0018)  /* Return an interface list (IPv4) */
 #define SIOCGLIFCONF     _SIOC(0x0019)  /* Return an interface list (IPv6) */
 
+#define SIOCGIFNAME      _SIOC(0x002A)  /* Get interface name string */
+#define SIOCGIFINDEX     _SIOC(0x002B)  /* Get index based name string */
+
 /* Interface flags */
 
 #define SIOCSIFFLAGS     _SIOC(0x001a)  /* Sets the interface flags */
@@ -122,6 +125,11 @@
 #define SIOCTELNET       _SIOC(0x0029)  /* Create a Telnet sessions.
                                          * See include/nuttx/net/telnet.h */
 
+/* SocketCAN ****************************************************************/
+
+#define SIOCGCANBITRATE  _SIOC(0x002C)  /* Get bitrate from a CAN controller */
+#define SIOCSCANBITRATE  _SIOC(0x002D)  /* Set bitrate of a CAN controller */
+
 /****************************************************************************
  * Public Type Definitions
  ****************************************************************************/
diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h
index c2cbb93..836edbf 100644
--- a/include/nuttx/net/net.h
+++ b/include/nuttx/net/net.h
@@ -156,7 +156,8 @@ enum net_lltype_e
   NET_LL_IEEE80211,    /* IEEE 802.11 */
   NET_LL_IEEE802154,   /* IEEE 802.15.4 MAC */
   NET_LL_PKTRADIO,     /* Non-standard packet radio */
-  NET_LL_MBIM          /* CDC-MBIM USB host driver */
+  NET_LL_MBIM,         /* CDC-MBIM USB host driver */
+  NET_LL_CAN           /* CAN bus */
 };
 
 /* This defines a bitmap big enough for one bit for each socket option */
@@ -215,6 +216,12 @@ struct sock_intf_s
   CODE ssize_t    (*si_recvfrom)(FAR struct socket *psock, FAR void *buf,
                     size_t len, int flags, FAR struct sockaddr *from,
                     FAR socklen_t *fromlen);
+#ifdef CONFIG_NET_CMSG
+  CODE ssize_t    (*si_recvmsg)(FAR struct socket *psock,
+    FAR struct msghdr *msg, int flags);
+  CODE ssize_t    (*si_sendmsg)(FAR struct socket *psock,
+    FAR struct msghdr *msg, int flags);
+#endif
   CODE int        (*si_close)(FAR struct socket *psock);
 #ifdef CONFIG_NET_USRSOCK
   CODE int        (*si_ioctl)(FAR struct socket *psock, int cmd,
@@ -271,6 +278,9 @@ struct socket
 #ifdef CONFIG_NET_SOLINGER
   socktimeo_t   s_linger;    /* Linger timeout value (in deciseconds) */
 #endif
+#ifdef CONFIG_NET_TIMESTAMP
+  int32_t       s_timestamp; /* Socket timestamp enabled/disabled */
+#endif
 #endif
 
   FAR void     *s_conn;      /* Connection inherits from struct socket_conn_s */
@@ -371,6 +381,25 @@ void net_initialize(void);
 int net_lock(void);
 
 /****************************************************************************
+ * Name: net_trylock
+ *
+ * Description:
+ *   Try to take the network lock only when it is currently not locked.
+ *   Otherwise, it locks the semaphore.  In either
+ *   case, the call returns without blocking.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   failured (probably -EAGAIN).
+ *
+ ****************************************************************************/
+
+int net_trylock(void);
+
+/****************************************************************************
  * Name: net_unlock
  *
  * Description:
diff --git a/include/nuttx/wqueue.h b/include/nuttx/wqueue.h
index d353772..ea7563c 100644
--- a/include/nuttx/wqueue.h
+++ b/include/nuttx/wqueue.h
@@ -280,7 +280,8 @@ enum work_evtype_e
   WORK_TCP_DISCONNECT,   /* Notify loss of TCP connection */
   WORK_UDP_READAHEAD,    /* Notify that UDP read-ahead data is available */
   WORK_UDP_WRITEBUFFER,  /* Notify that UDP write buffer is empty */
-  WORK_NETLINK_RESPONSE  /* Notify that Netlink response is available */
+  WORK_NETLINK_RESPONSE, /* Notify that Netlink response is available */
+  WORK_CAN_READAHEAD     /* Notify that CAN read-ahead data is available */
 };
 
 /* This structure describes one notification and is provided as input to
diff --git a/include/sys/socket.h b/include/sys/socket.h
index b940126..e8eca51 100644
--- a/include/sys/socket.h
+++ b/include/sys/socket.h
@@ -62,6 +62,7 @@
 #define PF_NETLINK    16         /* Netlink IPC socket */
 #define PF_ROUTE      PF_NETLINK /* 4.4BSD Compatibility*/
 #define PF_PACKET     17         /* Low level packet interface */
+#define PF_CAN        29         /* Controller Area Network (SocketCAN) */
 #define PF_BLUETOOTH  31         /* Bluetooth sockets */
 #define PF_IEEE802154 36         /* Low level IEEE 802.15.4 radio frame interface */
 #define PF_PKTRADIO   64         /* Low level packet radio interface */
@@ -78,6 +79,7 @@
 #define AF_NETLINK     PF_NETLINK
 #define AF_ROUTE       PF_ROUTE
 #define AF_PACKET      PF_PACKET
+#define AF_CAN         PF_CAN
 #define AF_BLUETOOTH   PF_BLUETOOTH
 #define AF_IEEE802154  PF_IEEE802154
 #define AF_PKTRADIO    PF_PKTRADIO
@@ -199,6 +201,16 @@
 #define SO_TYPE         15 /* Reports the socket type (get only).
                             * return: int
                             */
+#define SO_TIMESTAMP    16 /* Generates a timestamp for each incoming packet
+                            * arg: integer value
+                            */
+
+/* The options are unsupported but included for compatibility
+ * and portability
+ */
+#define SO_SNDBUFFORCE  32
+#define SO_RCVBUFFORCE  33
+#define SO_RXQ_OVFL     40
 
 /* Protocol-level socket operations. */
 
@@ -210,6 +222,7 @@
 #define SOL_L2CAP       6 /* See options in include/netpacket/bluetooth.h */
 #define SOL_SCO         7 /* See options in include/netpacket/bluetooth.h */
 #define SOL_RFCOMM      8 /* See options in include/netpacket/bluetooth.h */
+#define SOL_CAN_RAW     9 /* See options in include/netpacket/can.h */
 
 /* Protocol-level socket options may begin with this value */
 
diff --git a/libs/libc/net/lib_recvmsg.c b/libs/libc/net/lib_recvmsg.c
index 984a16f..071c189 100644
--- a/libs/libc/net/lib_recvmsg.c
+++ b/libs/libc/net/lib_recvmsg.c
@@ -39,7 +39,7 @@
 
 #include <nuttx/config.h>
 
-#ifdef CONFIG_NET
+#if defined(CONFIG_NET) && !defined(CONFIG_NET_CMSG)
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -53,7 +53,8 @@
  * Function: recvmsg
  *
  * Description:
- *   The recvmsg() call is identical to recvfrom() with a NULL from parameter.
+ *   The recvmsg() call is identical to recvfrom() with a NULL from
+ *   parameter.
  *
  * Parameters:
  *   sockfd   Socket descriptor of socket
@@ -86,4 +87,4 @@ ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
     }
 }
 
-#endif /* CONFIG_NET */
+#endif /* CONFIG_NET && !CONFIG_NET_CMSG */
diff --git a/libs/libc/net/lib_sendmsg.c b/libs/libc/net/lib_sendmsg.c
index 0d09faa..9f98e51 100644
--- a/libs/libc/net/lib_sendmsg.c
+++ b/libs/libc/net/lib_sendmsg.c
@@ -39,7 +39,7 @@
 
 #include <nuttx/config.h>
 
-#ifdef CONFIG_NET
+#if defined(CONFIG_NET) && !defined(CONFIG_NET_CMSG)
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -86,4 +86,4 @@ ssize_t sendmsg(int sockfd, FAR struct msghdr *msg, int flags)
     }
 }
 
-#endif /* CONFIG_NET */
+#endif /* CONFIG_NET && !CONFIG_NET_CMSG */
diff --git a/net/Kconfig b/net/Kconfig
index bedf933..80fe919 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -349,6 +349,7 @@ source "net/socket/Kconfig"
 source "net/inet/Kconfig"
 source "net/pkt/Kconfig"
 source "net/local/Kconfig"
+source "net/can/Kconfig"
 source "net/netlink/Kconfig"
 source "net/tcp/Kconfig"
 source "net/udp/Kconfig"
diff --git a/net/Makefile b/net/Makefile
index 077d035..f8ffe85 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -52,6 +52,7 @@ include igmp/Make.defs
 include pkt/Make.defs
 include local/Make.defs
 include mld/Make.defs
+include can/Make.defs
 include netlink/Make.defs
 include tcp/Make.defs
 include udp/Make.defs
diff --git a/net/bluetooth/bluetooth_sockif.c b/net/bluetooth/bluetooth_sockif.c
index 41bcafa..4057d93 100644
--- a/net/bluetooth/bluetooth_sockif.c
+++ b/net/bluetooth/bluetooth_sockif.c
@@ -106,9 +106,13 @@ const struct sock_intf_s g_bluetooth_sockif =
   bluetooth_send,        /* si_send */
   bluetooth_sendto,      /* si_sendto */
 #ifdef CONFIG_NET_SENDFILE
-  NULL,                   /* si_sendfile */
+  NULL,                  /* si_sendfile */
 #endif
   bluetooth_recvfrom,    /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+  NULL,                  /* si_recvmsg */
+  NULL,                  /* si_sendmsg */
+#endif
   bluetooth_close        /* si_close */
 };
 
@@ -243,10 +247,10 @@ static void bluetooth_addref(FAR struct socket *psock)
  * Name: bluetooth_connect
  *
  * Description:
- *   bluetooth_connect() connects the local socket referred to by the structure
- *   'psock' to the address specified by 'addr'. The addrlen argument
- *   specifies the size of 'addr'.  The format of the address in 'addr' is
- *   determined by the address space of the socket 'psock'.
+ *   bluetooth_connect() connects the local socket referred to by the
+ *   structure 'psock' to the address specified by 'addr'. The addrlen
+ *   argument specifies the size of 'addr'.  The format of the address in
+ *   'addr' is determined by the address space of the socket 'psock'.
  *
  *   Generally, connection-based protocol sockets may successfully
  *   bluetooth_connect() only once; connectionless protocol sockets may use
@@ -330,7 +334,8 @@ static int bluetooth_connect(FAR struct socket *psock,
  * Input Parameters:
  *   psock    Reference to the listening socket structure
  *   addr     Receives the address of the connecting client
- *   addrlen  Input: allocated size of 'addr', Return: returned size of 'addr'
+ *   addrlen  Input: allocated size of 'addr',
+ *            Return: returned size of 'addr'
  *   newsock  Location to return the accepted socket information.
  *
  * Returned Value:
@@ -372,7 +377,7 @@ static int bluetooth_accept(FAR struct socket *psock,
  ****************************************************************************/
 
 static int bluetooth_bind(FAR struct socket *psock,
-                           FAR const struct sockaddr *addr, socklen_t addrlen)
+                          FAR const struct sockaddr *addr, socklen_t addrlen)
 {
   FAR const struct sockaddr_bt_s *iaddr;
   FAR struct radio_driver_s *radio;
@@ -439,10 +444,10 @@ static int bluetooth_bind(FAR struct socket *psock,
  * Name: bluetooth_getsockname
  *
  * Description:
- *   The bluetooth_getsockname() function retrieves the locally-bound name of the
- *   specified packet socket, stores this address in the sockaddr structure
- *   pointed to by the 'addr' argument, and stores the length of this
- *   address in the object pointed to by the 'addrlen' argument.
+ *   The bluetooth_getsockname() function retrieves the locally-bound name of
+ *   the specified packet socket, stores this address in the sockaddr
+ *   structure pointed to by the 'addr' argument, and stores the length of
+ *   this address in the object pointed to by the 'addrlen' argument.
  *
  *   If the actual length of the address is greater than the length of the
  *   supplied sockaddr structure, the stored address will be truncated.
@@ -501,8 +506,8 @@ static int bluetooth_getsockname(FAR struct socket *psock,
  * Name: bluetooth_getpeername
  *
  * Description:
- *   The bluetooth_getpeername() function retrieves the remote-connected name of
- *   the specified local socket, stores this address in the sockaddr
+ *   The bluetooth_getpeername() function retrieves the remote-connected name
+ *   of the specified local socket, stores this address in the sockaddr
  *   structure pointed to by the 'addr' argument, and stores the length of
  *   this address in the object pointed to by the 'addrlen' argument.
  *
@@ -705,9 +710,10 @@ static ssize_t bluetooth_send(FAR struct socket *psock, FAR const void *buf,
  *
  ****************************************************************************/
 
-static ssize_t bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
-                                 size_t len, int flags,
-                                 FAR const struct sockaddr *to, socklen_t tolen)
+static ssize_t bluetooth_sendto(FAR struct socket *psock,
+                                FAR const void *buf, size_t len, int flags,
+                                FAR const struct sockaddr *to,
+                                socklen_t tolen)
 {
   ssize_t ret;
 
diff --git a/net/can/Kconfig b/net/can/Kconfig
new file mode 100644
index 0000000..e84c99d
--- /dev/null
+++ b/net/can/Kconfig
@@ -0,0 +1,97 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+menu "SocketCAN Support"
+
+config NET_CAN
+	bool "SocketCAN support"
+	default n
+	select NET_READAHEAD
+	depends on NET
+	---help---
+		Enable support for SocketCAN sockets that will permit.
+
+		This logic is a WIP.  Currently only fragmentary support is
+		available, not enough to actually do anything of consequence.
+
+if NET_CAN
+
+config NET_CAN_HAVE_TX_DEADLINE
+	bool
+	default n
+	
+config NET_CAN_HAVE_CANFD
+	bool
+	default n
+
+config CAN_CONNS
+	int "Number of CAN connections"
+	default 4
+	---help---
+		Maximum number of CAN connections (all tasks).
+		
+config NET_CAN_CANFD
+	bool "Enable CAN FD support"
+	default y
+	depends on NET_CAN_HAVE_CANFD
+	---help---
+		Enable CAN FD support in SocketCAN stack
+		
+config NET_CAN_SOCK_OPTS
+	bool "sockopt support"
+	default n
+	select NET_SOCKOPTS
+	select NET_CANPROTO_OPTIONS
+	---help---
+		Enable support for the CAN socket options
+				
+config NET_CAN_RAW_TX_DEADLINE
+	bool "TX deadline sockopt"
+	default n
+	depends on NET_CAN_SOCK_OPTS && NET_CAN_HAVE_TX_DEADLINE
+	select NET_CMSG
+	---help---
+	    Note: Non-standard SocketCAN sockopt, but this options helps us in
+	    real-time use cases.
+	    
+		When the CAN_RAW_TX_DEADLINE sockopt is enabled. The user can send 
+		CAN frames using sendmsg() function and add a deadline timespec 
+		value in the CMSG data. When the deadline has been passed and the
+		CAN frame is still in the HW TX mailbox then the CAN driver will 
+		discard the CAN frame automatically.
+		
+config NET_CAN_RAW_DEFAULT_TX_DEADLINE
+	int "Default TX deadline when no deadline is given (us)"
+	default 0
+	depends on NET_CAN_RAW_TX_DEADLINE
+	---help---
+		Some applications may not use the NET_CAN_RAW_TX_DEADLINE flag.
+		By default their deadline becomes 0 which means it becomes infinite.
+		This would mean that packets from applications without the 
+		NET_CAN_RAW_TX_DEADLINE flag, can block the TX mailboxes forever.
+		This config can set the default deadline when no deadline has been 
+		given.
+		
+config NET_CAN_RAW_FILTER_MAX
+	int "CAN_RAW_FILTER max filter count"
+	default 32
+	depends on NET_CAN_SOCK_OPTS
+	---help---
+		Maximum number of CAN_RAW filters that can be set per CAN connection.
+		
+config NET_CAN_NOTIFIER
+	bool "Support CAN notifications"
+	default n
+	depends on SCHED_WORKQUEUE
+	select WQUEUE_NOTIFIER
+	---help---
+		Enable building of CAN notifier logic that will execute a worker
+		function on the low priority work queue when read-ahead data
+		is available or when a CAN connection is lost.  This is is a general
+		purpose notifier, but was developed specifically to support poll()
+		logic where the poll must wait for these events.
+
+endif # NET_CAN
+endmenu # CAN Socket Support
diff --git a/net/can/Make.defs b/net/can/Make.defs
new file mode 100644
index 0000000..3204b3b
--- /dev/null
+++ b/net/can/Make.defs
@@ -0,0 +1,48 @@
+############################################################################
+# net/can/Make.defs
+#
+# 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.
+#
+############################################################################
+
+# Logic specific to SocketCAN socket support
+
+ifeq ($(CONFIG_NET_CAN),y)
+
+# Socket layer
+
+SOCK_CSRCS += can_sockif.c
+SOCK_CSRCS += can_send.c
+SOCK_CSRCS += can_recvfrom.c
+
+ifeq ($(CONFIG_NET_CAN_NOTIFIER),y)
+SOCK_CSRCS += can_notifier.c
+endif
+
+ifeq ($(CONFIG_NET_CANPROTO_OPTIONS),y)
+SOCK_CSRCS += can_setsockopt.c can_getsockopt.c
+endif
+
+NET_CSRCS += can_conn.c
+NET_CSRCS += can_input.c
+NET_CSRCS += can_callback.c
+NET_CSRCS += can_poll.c
+
+# Include can build support
+
+DEPPATH += --dep-path can
+VPATH += :can
+endif # CONFIG_NET_CAN
diff --git a/net/can/can.h b/net/can/can.h
new file mode 100644
index 0000000..cae3eb4
--- /dev/null
+++ b/net/can/can.h
@@ -0,0 +1,385 @@
+/****************************************************************************
+ * net/can/can.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 __NET_CAN_CAN_H
+#define __NET_CAN_CAN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <poll.h>
+
+#include <netpacket/can.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/can.h>
+#include <nuttx/net/netdev.h>
+
+#include "devif/devif.h"
+#include "socket/socket.h"
+
+#ifdef CONFIG_NET_CAN_NOTIFIER
+#  include <nuttx/wqueue.h>
+#endif
+
+#ifdef CONFIG_NET_CAN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Allocate a new packet socket data callback */
+
+#define can_callback_alloc(dev,conn) \
+  devif_callback_alloc(dev, &conn->list)
+#define can_callback_free(dev,conn,cb) \
+  devif_conn_callback_free(dev, cb, &conn->list)
+
+/****************************************************************************
+ * Public Type Definitions
+ ****************************************************************************/
+
+/* This is a container that holds the poll-related information */
+
+struct can_poll_s
+{
+  FAR struct socket *psock;        /* Needed to handle loss of connection */
+  FAR struct net_driver_s *dev;    /* Needed to free the callback structure */
+  struct pollfd *fds;              /* Needed to handle poll events */
+  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
+};
+
+/* This "connection" structure describes the underlying state of the socket */
+
+struct can_conn_s
+{
+  /* Common prologue of all connection structures. */
+
+  dq_entry_t node;                   /* Supports a doubly linked list */
+
+  /* This is a list of NetLink connection callbacks.  Each callback
+   * represents a thread that is stalled, waiting for a device-specific
+   * event.
+   */
+
+  FAR struct devif_callback_s *list; /* NetLink callbacks */
+
+  FAR struct net_driver_s *dev;      /* Reference to CAN device */
+
+  /* Read-ahead buffering.
+   *
+   *   readahead - A singly linked list of type struct iob_qentry_s
+   *               where the CAN/IP read-ahead data is retained.
+   */
+
+  struct iob_queue_s readahead;      /* remove Read-ahead buffering */
+
+  /* CAN-specific content follows */
+
+  uint8_t protocol;                  /* Selected CAN protocol */
+  int16_t crefs;                     /* Reference count */
+
+  /* The following is a list of poll structures of threads waiting for
+   * socket events.
+   */
+
+  struct can_poll_s pollinfo[4]; /* FIXME make dynamic */
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+  int32_t loopback;
+  int32_t recv_own_msgs;
+#ifdef CONFIG_NET_CAN_CANFD
+  int32_t fd_frames;
+#endif
+  struct can_filter filters[CONFIG_NET_CAN_RAW_FILTER_MAX];
+  int32_t filter_count;
+# ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+  int32_t tx_deadline;
+# endif
+#endif
+
+#ifdef CONFIG_NET_TIMESTAMP
+  FAR struct socket *psock; /* Needed to get SO_TIMESTAMP value */
+#endif
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#  define EXTERN extern "C"
+extern "C"
+{
+#else
+#  define EXTERN extern
+#endif
+
+EXTERN const struct sock_intf_s g_can_sockif;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+struct sockaddr_can;  /* Forward reference */
+
+/****************************************************************************
+ * Name: can_initialize()
+ *
+ * Description:
+ *   Initialize the NetLink connection structures.  Called once and only
+ *   from the networking layer.
+ *
+ ****************************************************************************/
+
+void can_initialize(void);
+
+/****************************************************************************
+ * Name: can_alloc()
+ *
+ * Description:
+ *   Allocate a new, uninitialized NetLink connection structure.  This is
+ *   normally something done by the implementation of the socket() API
+ *
+ ****************************************************************************/
+
+FAR struct can_conn_s *can_alloc(void);
+
+/****************************************************************************
+ * Name: can_free()
+ *
+ * Description:
+ *   Free a NetLink connection structure that is no longer in use. This
+ *   should be done by the implementation of close().
+ *
+ ****************************************************************************/
+
+void can_free(FAR struct can_conn_s *conn);
+
+/****************************************************************************
+ * Name: can_nextconn()
+ *
+ * Description:
+ *   Traverse the list of allocated NetLink connections
+ *
+ * Assumptions:
+ *   This function is called from NetLink device logic.
+ *
+ ****************************************************************************/
+
+FAR struct can_conn_s *can_nextconn(FAR struct can_conn_s *conn);
+
+/****************************************************************************
+ * Name: can_callback
+ *
+ * Description:
+ *   Inform the application holding the packet socket of a change in state.
+ *
+ * Returned Value:
+ *   OK if packet has been processed, otherwise ERROR.
+ *
+ * Assumptions:
+ *   This function is called from network logic at with the network locked.
+ *
+ ****************************************************************************/
+
+uint16_t can_callback(FAR struct net_driver_s *dev,
+                      FAR struct can_conn_s *conn, uint16_t flags);
+
+/****************************************************************************
+ * Name: can_datahandler
+ *
+ * Description:
+ *   Handle data that is not accepted by the application.  This may be called
+ *   either (1) from the data receive logic if it cannot buffer the data, or
+ *   (2) from the CAN event logic is there is no listener in place ready to
+ *   receive the data.
+ *
+ * Input Parameters:
+ *   conn - A pointer to the CAN connection structure
+ *   buffer - A pointer to the buffer to be copied to the read-ahead
+ *     buffers
+ *   buflen - The number of bytes to copy to the read-ahead buffer.
+ *
+ * Returned Value:
+ *   The number of bytes actually buffered is returned.  This will be either
+ *   zero or equal to buflen; partial packets are not buffered.
+ *
+ * Assumptions:
+ * - The caller has checked that CAN_NEWDATA is set in flags and that is no
+ *   other handler available to process the incoming data.
+ * - Called from network stack logic with the network stack locked
+ *
+ ****************************************************************************/
+
+uint16_t can_datahandler(FAR struct can_conn_s *conn, FAR uint8_t *buffer,
+                         uint16_t buflen);
+
+/****************************************************************************
+ * Name: can_recvfrom
+ *
+ * Description:
+ *   Implements the socket recvfrom interface pkt_recvfrom() receives
+ *   messages from a socket, and may be used to receive data on a socket
+ *   whether or not it is connection-oriented.
+ *
+ * Input Parameters:
+ *   psock    A pointer to a NuttX-specific, internal socket structure
+ *   buf      Buffer to receive data
+ *   len      Length of buffer
+ *   flags    Receive flags
+ *   from     Address of source (may be NULL)
+ *   fromlen  The length of the address structure
+ *
+ * Returned Value:
+ *   On success, returns the number of characters received.  If no data is
+ *   available to be received and the peer has performed an orderly shutdown,
+ *   recv() will return 0.  Otherwise, on errors, a negated errno value is
+ *   returned (see recvfrom() for the list of appropriate error values).
+ *
+ ****************************************************************************/
+
+ssize_t can_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
+                     int flags, FAR struct sockaddr *from,
+                     FAR socklen_t *fromlen);
+
+/****************************************************************************
+ * Name: can_recvmsg
+ *
+ * Description:
+ *   recvmsg() receives messages from a socket, and may be used to receive
+ *   data on a socket whether or not it is connection-oriented.
+ *
+ *   If from is not NULL, and the underlying protocol provides the source
+ *   address, this source address is filled in. The argument 'fromlen'
+ *   initialized to the size of the buffer associated with from, and modified
+ *   on return to indicate the actual size of the address stored there.
+ *
+ * Input Parameters:
+ *   psock    A pointer to a NuttX-specific, internal socket structure
+ *   msg      Buffer to receive msg
+ *   flags    Receive flags (ignored)
+ *
+ ****************************************************************************/
+#ifdef CONFIG_NET_CMSG
+ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+                    int flags);
+#endif
+
+/****************************************************************************
+ * Name: can_poll
+ *
+ * Description:
+ *   Poll a CAN connection structure for availability of TX data
+ *
+ * Input Parameters:
+ *   dev - The device driver structure to use in the send operation
+ *   conn - The CAN "connection" to poll for TX data
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called from network stack logic with the network stack locked
+ *
+ ****************************************************************************/
+
+void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn);
+
+/****************************************************************************
+ * Name: psock_can_send
+ *
+ * Description:
+ *   The psock_can_send() call may be used only when the packet socket is in
+ *   a connected state (so that the intended recipient is known).
+ *
+ * Input Parameters:
+ *   psock    An instance of the internal socket structure.
+ *   buf      Data to send
+ *   len      Length of data to send
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  On  error,
+ *   a negated errno value is returned.  See send() for the complete list
+ *   of return values.
+ *
+ ****************************************************************************/
+
+struct socket;
+ssize_t psock_can_send(FAR struct socket *psock, FAR const void *buf,
+                       size_t len);
+
+/****************************************************************************
+ * Name: psock_can_sendmsg
+ *
+ * Description:
+ *   The psock_can_sendmsg() call may be used only when the packet socket is
+ *   in a connected state (so that the intended recipient is known).
+ *
+ * Input Parameters:
+ *   psock    An instance of the internal socket structure.
+ *   msg      msg to send
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  On  error,
+ *   a negated errno value is returned.  See send() for the complete list
+ *   of return values.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CMSG
+ssize_t psock_can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg);
+#endif
+
+/****************************************************************************
+ * Name: can_readahead_signal
+ *
+ * Description:
+ *   Read-ahead data has been buffered.  Signal all threads waiting for
+ *   read-ahead data to become available.
+ *
+ *   When read-ahead data becomes available, *all* of the workers waiting
+ *   for read-ahead data will be executed.  If there are multiple workers
+ *   waiting for read-ahead data then only the first to execute will get the
+ *   data.  Others will need to call can_readahead_notifier_setup() once
+ *   again.
+ *
+ * Input Parameters:
+ *   conn  - The CAN connection where read-ahead data was just buffered.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CAN_NOTIFIER
+void can_readahead_signal(FAR struct can_conn_s *conn);
+#endif
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_NET_CAN */
+#endif /* __NET_CAN_CAN_H */
diff --git a/net/can/can_callback.c b/net/can/can_callback.c
new file mode 100644
index 0000000..f8f0fae
--- /dev/null
+++ b/net/can/can_callback.c
@@ -0,0 +1,242 @@
+/****************************************************************************
+ * net/pkt/pkt_callback.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>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
+
+#include <stdint.h>
+#include <debug.h>
+
+#include <nuttx/net/netconfig.h>
+#include <nuttx/net/netdev.h>
+#include <nuttx/mm/iob.h>
+
+#include "devif/devif.h"
+#include "can/can.h"
+
+#ifdef CONFIG_NET_TIMESTAMP
+#include <sys/time.h>
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_data_event
+ *
+ * Description:
+ *   Handle data that is not accepted by the application because there is no
+ *   listener in place ready to receive the data.
+ *
+ * Assumptions:
+ * - The caller has checked that CAN_NEWDATA is set in flags and that is no
+ *   other handler available to process the incoming data.
+ * - This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+static inline uint16_t
+can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn,
+               uint16_t flags)
+{
+  uint16_t ret;
+  FAR uint8_t *buffer = dev->d_appdata;
+  int buflen = dev->d_len;
+  uint16_t recvlen;
+
+  ret = (flags & ~CAN_NEWDATA);
+
+  /* Save as the packet data as in the read-ahead buffer.  NOTE that
+   * partial packets will not be buffered.
+   */
+
+  recvlen = can_datahandler(conn, buffer, buflen);
+  if (recvlen < buflen)
+    {
+      /* There is no handler to receive new data and there are no free
+       * read-ahead buffers to retain the data -- drop the packet.
+       */
+
+      ninfo("Dropped %d bytes\n", dev->d_len);
+
+#ifdef CONFIG_NET_STATISTICS
+      /* No support CAN net statistics yet */
+
+      /* g_netstats.tcp.drop++; */
+
+#endif
+    }
+
+  /* In any event, the new data has now been handled */
+
+  dev->d_len = 0;
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_callback
+ *
+ * Description:
+ *   Inform the application holding the packet socket of a change in state.
+ *
+ * Returned Value:
+ *   OK if packet has been processed, otherwise ERROR.
+ *
+ * Assumptions:
+ *   This function can be called from an interrupt.
+ *
+ ****************************************************************************/
+
+uint16_t can_callback(FAR struct net_driver_s *dev,
+                      FAR struct can_conn_s *conn, uint16_t flags)
+{
+  /* Some sanity checking */
+
+  if (conn)
+    {
+#ifdef CONFIG_NET_TIMESTAMP
+      /* TIMESTAMP sockopt is activated, create timestamp and copy to iob */
+
+      if (conn->psock->s_timestamp)
+        {
+          struct timespec *ts = (struct timespec *)
+                                                &dev->d_appdata[dev->d_len];
+          struct timeval *tv = (struct timeval *)
+                                                &dev->d_appdata[dev->d_len];
+          dev->d_len += sizeof(struct timeval);
+          clock_systime_timespec(ts);
+          tv->tv_usec = ts->tv_nsec / 1000;
+        }
+#endif
+
+      /* Try to lock the network when successfull send data to the listener */
+
+      if (net_trylock() == OK)
+        {
+          flags = devif_conn_event(dev, conn, flags, conn->list);
+          net_unlock();
+        }
+
+      /* Either we did not get the lock or there is no application listening
+       * If we did not get a lock we store the frame in the read-ahead buffer
+       */
+
+      if ((flags & CAN_NEWDATA) != 0)
+        {
+          /* Data was not handled.. dispose of it appropriately */
+
+          flags = can_data_event(dev, conn, flags);
+        }
+    }
+
+  return flags;
+}
+
+/****************************************************************************
+ * Name: can_datahandler
+ *
+ * Description:
+ *   Handle data that is not accepted by the application.  This may be called
+ *   either (1) from the data receive logic if it cannot buffer the data, or
+ *   (2) from the CAN event logic is there is no listener in place ready to
+ *   receive the data.
+ *
+ * Input Parameters:
+ *   conn - A pointer to the CAN connection structure
+ *   buffer - A pointer to the buffer to be copied to the read-ahead
+ *     buffers
+ *   buflen - The number of bytes to copy to the read-ahead buffer.
+ *
+ * Returned Value:
+ *   The number of bytes actually buffered is returned.  This will be either
+ *   zero or equal to buflen; partial packets are not buffered.
+ *
+ * Assumptions:
+ * - The caller has checked that CAN_NEWDATA is set in flags and that is no
+ *   other handler available to process the incoming data.
+ * - This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+uint16_t can_datahandler(FAR struct can_conn_s *conn, FAR uint8_t *buffer,
+                         uint16_t buflen)
+{
+  FAR struct iob_s *iob;
+  int ret;
+
+  /* Try to allocate on I/O buffer to start the chain without waiting (and
+   * throttling as necessary).  If we would have to wait, then drop the
+   * packet.
+   */
+
+  iob = iob_tryalloc(true, IOBUSER_NET_CAN_READAHEAD);
+  if (iob == NULL)
+    {
+      nerr("ERROR: Failed to create new I/O buffer chain\n");
+      return 0;
+    }
+
+  /* Copy the new appdata into the I/O buffer chain (without waiting) */
+
+  ret = iob_trycopyin(iob, buffer, buflen, 0, true,
+                      IOBUSER_NET_CAN_READAHEAD);
+  if (ret < 0)
+    {
+      /* On a failure, iob_copyin return a negated error value but does
+       * not free any I/O buffers.
+       */
+
+      nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
+      iob_free_chain(iob, IOBUSER_NET_CAN_READAHEAD);
+      return 0;
+    }
+
+  /* Add the new I/O buffer chain to the tail of the read-ahead queue (again
+   * without waiting).
+   */
+
+  ret = iob_tryadd_queue(iob, &conn->readahead);
+  if (ret < 0)
+    {
+      nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
+      iob_free_chain(iob, IOBUSER_NET_CAN_READAHEAD);
+      return 0;
+    }
+
+#ifdef CONFIG_NET_CAN_NOTIFIER
+  /* Provide notification(s) that additional CAN read-ahead data is
+   * available.
+   */
+
+  can_readahead_signal(conn);
+#endif
+  return buflen;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/net/can/can_conn.c b/net/can/can_conn.c
new file mode 100644
index 0000000..574796c
--- /dev/null
+++ b/net/can/can_conn.c
@@ -0,0 +1,223 @@
+/****************************************************************************
+ * net/can/can_conn.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 <string.h>
+#include <queue.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/net/netconfig.h>
+#include <nuttx/net/net.h>
+
+#include "utils/utils.h"
+#include "can/can.h"
+
+#ifdef CONFIG_NET_CAN
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The array containing all NetLink connections. */
+
+static struct can_conn_s g_can_connections[CONFIG_CAN_CONNS];
+
+/* A list of all free NetLink connections */
+
+static dq_queue_t g_free_can_connections;
+static sem_t g_free_sem;
+
+/* A list of all allocated NetLink connections */
+
+static dq_queue_t g_active_can_connections;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: _can_semtake() and _can_semgive()
+ *
+ * Description:
+ *   Take/give semaphore
+ *
+ ****************************************************************************/
+
+static void _can_semtake(FAR sem_t *sem)
+{
+  net_lockedwait_uninterruptible(sem);
+}
+
+static void _can_semgive(FAR sem_t *sem)
+{
+  nxsem_post(sem);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_initialize()
+ *
+ * Description:
+ *   Initialize the User Socket connection structures.  Called once and only
+ *   from the networking layer.
+ *
+ ****************************************************************************/
+
+void can_initialize(void)
+{
+  int i;
+
+  /* Initialize the queues */
+
+  dq_init(&g_free_can_connections);
+  dq_init(&g_active_can_connections);
+  nxsem_init(&g_free_sem, 0, 1);
+
+  for (i = 0; i < CONFIG_CAN_CONNS; i++)
+    {
+      FAR struct can_conn_s *conn = &g_can_connections[i];
+
+      /* Mark the connection closed and move it to the free list */
+
+      memset(conn, 0, sizeof(*conn));
+      dq_addlast(&conn->node, &g_free_can_connections);
+    }
+}
+
+/****************************************************************************
+ * Name: can_alloc()
+ *
+ * Description:
+ *   Allocate a new, uninitialized NetLink connection structure.  This is
+ *   normally something done by the implementation of the socket() API
+ *
+ ****************************************************************************/
+
+FAR struct can_conn_s *can_alloc(void)
+{
+  FAR struct can_conn_s *conn;
+
+  /* The free list is protected by a semaphore (that behaves like a mutex). */
+
+  _can_semtake(&g_free_sem);
+  conn = (FAR struct can_conn_s *)dq_remfirst(&g_free_can_connections);
+  if (conn != NULL)
+    {
+      /* Make sure that the connection is marked as uninitialized */
+
+      memset(conn, 0, sizeof(*conn));
+
+      /* FIXME SocketCAN default behavior enables loopback */
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+      /* By default the filter is configured to catch all,
+       * this is done in commented filter code below:
+       *
+       * struct can_filter_t catchall_filter;
+       * filter.can_id = 0;
+       * filter.can_mask = 0;
+       * conn->filters[0] = catchall_filter;
+       *
+       * However memset already sets the filter to 0
+       * therefore we only have to set the filter count to 1
+       */
+
+      conn->filter_count = 1;
+#endif
+
+      /* Enqueue the connection into the active list */
+
+      dq_addlast(&conn->node, &g_active_can_connections);
+    }
+
+  _can_semgive(&g_free_sem);
+  return conn;
+}
+
+/****************************************************************************
+ * Name: can_free()
+ *
+ * Description:
+ *   Free a NetLink connection structure that is no longer in use. This
+ *   should be done by the implementation of close().
+ *
+ ****************************************************************************/
+
+void can_free(FAR struct can_conn_s *conn)
+{
+  /* The free list is protected by a semaphore (that behaves like a mutex). */
+
+  DEBUGASSERT(conn->crefs == 0);
+
+  _can_semtake(&g_free_sem);
+
+  /* Remove the connection from the active list */
+
+  dq_rem(&conn->node, &g_active_can_connections);
+
+  /* Reset structure */
+
+  memset(conn, 0, sizeof(*conn));
+
+  /* Free the connection */
+
+  dq_addlast(&conn->node, &g_free_can_connections);
+  _can_semgive(&g_free_sem);
+}
+
+/****************************************************************************
+ * Name: can_nextconn()
+ *
+ * Description:
+ *   Traverse the list of allocated NetLink connections
+ *
+ * Assumptions:
+ *   This function is called from NetLink device logic.
+ *
+ ****************************************************************************/
+
+FAR struct can_conn_s *can_nextconn(FAR struct can_conn_s *conn)
+{
+  if (conn == NULL)
+    {
+      return (FAR struct can_conn_s *)g_active_can_connections.head;
+    }
+  else
+    {
+      return (FAR struct can_conn_s *)conn->node.flink;
+    }
+}
+
+#endif /* CONFIG_NET_CAN */
diff --git a/net/can/can_getsockopt.c b/net/can/can_getsockopt.c
new file mode 100644
index 0000000..df6d0c9
--- /dev/null
+++ b/net/can/can_getsockopt.c
@@ -0,0 +1,220 @@
+/****************************************************************************
+ * net/can/can_setsockopt.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 <sys/time.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <netpacket/can.h>
+
+#include <nuttx/net/net.h>
+#include <nuttx/net/can.h>
+
+#include "socket/socket.h"
+#include "utils/utils.h"
+#include "can/can.h"
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_getsockopt
+ *
+ * Description:
+ *   can_getsockopt() retrieves the value for the option specified by the
+ *   'option' argument for the socket specified by the 'psock' argument.  If
+ *   the size of the option value is greater than 'value_len', the value
+ *   stored in the object pointed to by the 'value' argument will be silently
+ *   truncated. Otherwise, the length pointed to by the 'value_len' argument
+ *   will be modified to indicate the actual length of the 'value'.
+ *
+ *   See <sys/socket.h> a complete list of values for the socket-level
+ *   'option' argument.  Protocol-specific options are are protocol specific
+ *   header files (such as netpacket/can.h for the case of the CAN protocol).
+ *
+ * Input Parameters:
+ *   psock     Socket structure of the socket to query
+ *   level     Protocol level to set the option
+ *   option    identifies the option to get
+ *   value     Points to the argument value
+ *   value_len The length of the argument value
+ *
+ * Returned Value:
+ *   Returns zero (OK) on success.  On failure, it returns a negated errno
+ *   value to indicate the nature of the error.  See psock_getsockopt() for
+ *   the complete list of appropriate return error codes.
+ *
+ ****************************************************************************/
+
+int can_getsockopt(FAR struct socket *psock, int option,
+                   FAR void *value, FAR socklen_t *value_len)
+{
+  FAR struct can_conn_s *conn;
+  int ret;
+
+  DEBUGASSERT(psock != NULL && value != NULL && value_len != NULL &&
+              psock->s_conn != NULL);
+  conn = (FAR struct can_conn_s *)psock->s_conn;
+
+  if (psock->s_type != SOCK_RAW)
+    {
+      nerr("ERROR:  Not a RAW CAN socket\n");
+      return -ENOTCONN;
+    }
+
+  switch (option)
+    {
+      case CAN_RAW_FILTER:
+        if (*value_len % sizeof(struct can_filter) != 0)
+          {
+            ret = -EINVAL;
+          }
+        else if (*value_len > CONFIG_NET_CAN_RAW_FILTER_MAX *
+                   sizeof(struct can_filter))
+          {
+            ret = -EINVAL;
+          }
+        else
+          {
+            int count = conn->filter_count;
+
+          if (*value_len < count * sizeof(struct can_filter))
+              {
+                count = *value_len / sizeof(struct can_filter);
+              }
+          else
+            {
+              *value_len = count * sizeof(struct can_filter);
+            }
+
+            for (int i = 0; i < count; i++)
+              {
+                ((struct can_filter *)value)[i] = conn->filters[i];
+              }
+
+            ret = OK;
+          }
+        break;
+
+      case CAN_RAW_ERR_FILTER:
+        break;
+
+      case CAN_RAW_LOOPBACK:
+        if (*value_len < sizeof(conn->loopback))
+          {
+            /* REVISIT: POSIX says that we should truncate the value if it
+             * is larger than value_len.   That just doesn't make sense
+             * to me in this case.
+             */
+
+            ret              = -EINVAL;
+          }
+        else
+          {
+            FAR int *loopback  = (FAR int32_t *)value;
+            *loopback          = conn->loopback;
+            *value_len         = sizeof(conn->loopback);
+            ret                = OK;
+          }
+        break;
+
+      case CAN_RAW_RECV_OWN_MSGS:
+        if (*value_len < sizeof(conn->recv_own_msgs))
+          {
+            /* REVISIT: POSIX says that we should truncate the value if it
+             * is larger than value_len.   That just doesn't make sense
+             * to me in this case.
+             */
+
+            ret              = -EINVAL;
+          }
+        else
+          {
+            FAR int *recv_own_msgs = (FAR int32_t *)value;
+            *recv_own_msgs         = conn->recv_own_msgs;
+            *value_len             = sizeof(conn->recv_own_msgs);
+            ret                    = OK;
+          }
+        break;
+
+      case CAN_RAW_FD_FRAMES:
+        if (*value_len < sizeof(conn->fd_frames))
+          {
+            /* REVISIT: POSIX says that we should truncate the value if it
+             * is larger than value_len.   That just doesn't make sense
+             * to me in this case.
+             */
+
+            ret              = -EINVAL;
+          }
+        else
+          {
+            FAR int *fd_frames = (FAR int32_t *)value;
+            *fd_frames         = conn->fd_frames;
+            *value_len         = sizeof(conn->fd_frames);
+            ret                = OK;
+          }
+        break;
+
+      case CAN_RAW_JOIN_FILTERS:
+        break;
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+      case CAN_RAW_TX_DEADLINE:
+        if (*value_len < sizeof(conn->tx_deadline))
+          {
+            /* REVISIT: POSIX says that we should truncate the value if it
+             * is larger than value_len.   That just doesn't make sense
+             * to me in this case.
+             */
+
+            ret              = -EINVAL;
+          }
+        else
+          {
+            FAR int *tx_deadline = (FAR int32_t *)value;
+            *tx_deadline         = conn->tx_deadline;
+            *value_len         = sizeof(conn->tx_deadline);
+            ret                = OK;
+          }
+        break;
+#endif
+
+      default:
+        nerr("ERROR: Unrecognized RAW CAN socket option: %d\n", option);
+        ret = -ENOPROTOOPT;
+        break;
+    }
+
+  return ret;
+}
+
+#endif /* CONFIG_NET_CANPROTO_OPTIONS */
diff --git a/net/can/can_input.c b/net/can/can_input.c
new file mode 100644
index 0000000..024bb9a
--- /dev/null
+++ b/net/can/can_input.c
@@ -0,0 +1,204 @@
+/****************************************************************************
+ * net/can/can_input.c
+ * Handling incoming packet input
+ *
+ * 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>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
+
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/can.h>
+
+#include "devif/devif.h"
+#include "can/can.h"
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+const uint8_t can_dlc_to_len[16] =
+{
+    0,
+    1,
+    2,
+    3,
+    4,
+    5,
+    6,
+    7,
+    8,
+    12,
+    16,
+    20,
+    24,
+    32,
+    48,
+    64,
+};
+const uint8_t len_to_can_dlc[65] =
+{
+    0,
+    1,
+    2,
+    3,
+    4,
+    5,
+    6,
+    7,
+    8,
+    9,
+    9,
+    9,
+    9,
+    10,
+    10,
+    10,
+    10,
+    11,
+    11,
+    11,
+    11,
+    12,
+    12,
+    12,
+    12,
+    13,
+    13,
+    13,
+    13,
+    13,
+    13,
+    13,
+    13,
+    14,
+    14,
+    14,
+    14,
+    14,
+    14,
+    14,
+    14,
+    14,
+    14,
+    14,
+    14,
+    14,
+    14,
+    14,
+    14,
+    15,
+    15,
+    15,
+    15,
+    15,
+    15,
+    15,
+    15,
+    15,
+    15,
+    15,
+    15,
+    15,
+    15,
+    15,
+    15,
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_input
+ *
+ * Description:
+ *   Handle incoming packet input
+ *
+ * Input Parameters:
+ *   dev - The device driver structure containing the received packet
+ *
+ * Returned Value:
+ *   OK     The packet has been processed  and can be deleted
+ *  -EAGAIN There is a matching connection, but could not dispatch the packet
+ *          yet.  Useful when a packet arrives before a recv call is in
+ *          place.
+ *
+ * Assumptions:
+ *   This function can be called from an interrupt.
+ *
+ ****************************************************************************/
+
+int can_input(struct net_driver_s *dev)
+{
+  FAR struct can_conn_s *conn = NULL;
+  int ret = OK;
+
+  do
+    {
+      /* FIXME Support for multiple sockets??? */
+
+      conn = can_nextconn(conn);
+    }
+  while (conn && conn->dev != 0 && dev != conn->dev);
+
+  if (conn)
+    {
+      uint16_t flags;
+
+      /* Setup for the application callback */
+
+      dev->d_appdata = dev->d_buf;
+      dev->d_sndlen  = 0;
+
+      /* Perform the application callback */
+
+      flags = can_callback(dev, conn, CAN_NEWDATA);
+
+      /* If the operation was successful, the CAN_NEWDATA flag is removed
+       * and thus the packet can be deleted (OK will be returned).
+       */
+
+      if ((flags & CAN_NEWDATA) != 0)
+        {
+          /* No.. the packet was not processed now.  Return -EAGAIN so
+           * that the driver may retry again later.  We still need to
+           * set d_len to zero so that the driver is aware that there
+           * is nothing to be sent.
+           */
+
+           nwarn("WARNING: Packet not processed\n");
+           ret = -EAGAIN;
+        }
+    }
+  else
+    {
+      ninfo("No CAN listener\n");
+    }
+
+  return ret;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/libs/libc/net/lib_recvmsg.c b/net/can/can_notifier.c
similarity index 70%
copy from libs/libc/net/lib_recvmsg.c
copy to net/can/can_notifier.c
index 984a16f..f4c7b1e 100644
--- a/libs/libc/net/lib_recvmsg.c
+++ b/net/can/can_notifier.c
@@ -1,7 +1,7 @@
 /****************************************************************************
- * libc/net/lib_recvmsg.c
+ * net/can/can_notifier.c
  *
- *   Copyright (C) 2007, 2008, 2012, 2008 Gregory Nutt. All rights reserved.
+ *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <gn...@nuttx.org>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,51 +39,45 @@
 
 #include <nuttx/config.h>
 
-#ifdef CONFIG_NET
-
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <errno.h>
+#include <assert.h>
+
+#include <nuttx/wqueue.h>
+
+#include "can/can.h"
+
+#ifdef CONFIG_NET_CAN_NOTIFIER
 
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Function: recvmsg
+ * Name: can_readahead_signal
  *
  * Description:
- *   The recvmsg() call is identical to recvfrom() with a NULL from parameter.
+ *   Read-ahead data has been buffered.  Signal all threads waiting for
+ *   read-ahead data to become available.
  *
- * Parameters:
- *   sockfd   Socket descriptor of socket
- *   buf      Buffer to receive data
- *   len      Length of buffer
- *   flags    Receive flags
+ *   When read-ahead data becomes available, *all* of the workers waiting
+ *   for read-ahead data will be executed.  If there are multiple workers
+ *   waiting for read-ahead data then only the first to execute will get the
+ *   data.  Others will need to call can_readahead_notifier_setup() once
+ *   again.
  *
- * Returned Value:
- *  (see recvfrom)
+ * Input Parameters:
+ *   conn  - The CAN connection where read-ahead data was just buffered.
  *
- * Assumptions:
+ * Returned Value:
+ *   None.
  *
  ****************************************************************************/
 
-ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
+void can_readahead_signal(FAR struct can_conn_s *conn)
 {
-  FAR void *buf             = msg->msg_iov->iov_base;
-  FAR struct sockaddr *from = msg->msg_name;
-  FAR socklen_t *fromlen    = (FAR socklen_t *)&msg->msg_namelen;
-  size_t len                = msg->msg_iov->iov_len;
+  /* This is just a simple wrapper around work_notifier_signal(). */
 
-  if (msg->msg_iovlen == 1)
-    {
-      return recvfrom(sockfd, buf, len, flags, from, fromlen);
-    }
-  else
-    {
-      set_errno(ENOTSUP);
-      return ERROR;
-    }
+  work_notifier_signal(WORK_CAN_READAHEAD, conn);
 }
 
-#endif /* CONFIG_NET */
+#endif /* CONFIG_NET_CAN_NOTIFIER */
diff --git a/net/can/can_poll.c b/net/can/can_poll.c
new file mode 100644
index 0000000..2163242
--- /dev/null
+++ b/net/can/can_poll.c
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * net/pkt/pkt_poll.c
+ * Poll for the availability of packet TX data
+ *
+ * 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>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
+
+#include <debug.h>
+
+#include <nuttx/net/netconfig.h>
+#include <nuttx/net/netdev.h>
+
+#include "devif/devif.h"
+#include "can/can.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_poll
+ *
+ * Description:
+ *   Poll a packet "connection" structure for availability of TX data
+ *
+ * Input Parameters:
+ *   dev - The device driver structure to use in the send operation
+ *   conn - The packet "connection" to poll for TX data
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn)
+{
+  /* Verify that the packet connection is valid */
+
+  if (conn != NULL)
+    {
+      /* Setup for the application callback */
+
+      dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev)];
+      dev->d_len     = 0;
+      dev->d_sndlen  = 0;
+
+      /* Perform the application callback */
+
+      can_callback(dev, conn, CAN_POLL);
+
+      /* Check if the application has data to send */
+
+      if (dev->d_sndlen > 0)
+        {
+          return;
+        }
+    }
+
+  /* Make sure that d_len is zero meaning that there is nothing to be sent */
+
+  dev->d_len = 0;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/net/can/can_recvfrom.c b/net/can/can_recvfrom.c
new file mode 100644
index 0000000..bbea9c3
--- /dev/null
+++ b/net/can/can_recvfrom.c
@@ -0,0 +1,838 @@
+/****************************************************************************
+ * net/can/can_recvfrom.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>
+
+#ifdef CONFIG_NET_CAN
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+#include <assert.h>
+
+#include <arch/irq.h>
+
+#include <nuttx/semaphore.h>
+#include <nuttx/net/net.h>
+#include <nuttx/net/netdev.h>
+
+#include "netdev/netdev.h"
+#include "devif/devif.h"
+#include "can/can.h"
+#include "socket/socket.h"
+#include <netpacket/packet.h>
+
+#ifdef CONFIG_NET_TIMESTAMP
+#include <sys/time.h>
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct can_recvfrom_s
+{
+  FAR struct socket *pr_sock;          /* The parent socket structure */
+  FAR struct devif_callback_s *pr_cb;  /* Reference to callback instance */
+  sem_t        pr_sem;                 /* Semaphore signals recv completion */
+  size_t       pr_buflen;              /* Length of receive buffer */
+  FAR uint8_t *pr_buffer;              /* Pointer to receive buffer */
+  ssize_t      pr_recvlen;             /* The received length */
+#ifdef CONFIG_NET_CMSG
+  size_t       pr_msglen;              /* Length of msg buffer */
+  FAR uint8_t *pr_msgbuf;              /* Pointer to msg buffer */
+#endif
+  int          pr_result;              /* Success:OK, failure:negated errno */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_add_recvlen
+ *
+ * Description:
+ *   Update information about space available for new data and update size
+ *   of data in buffer,  This logic accounts for the case where
+ *   recvfrom_udpreadahead() sets state.pr_recvlen == -1 .
+ *
+ * Input Parameters:
+ *   pstate   recvfrom state structure
+ *   recvlen  size of new data appended to buffer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline void can_add_recvlen(FAR struct can_recvfrom_s *pstate,
+                                   size_t recvlen)
+{
+  if (pstate->pr_recvlen < 0)
+    {
+      pstate->pr_recvlen = 0;
+    }
+
+  pstate->pr_recvlen += recvlen;
+  pstate->pr_buffer  += recvlen;
+  pstate->pr_buflen  -= recvlen;
+}
+
+/****************************************************************************
+ * Name: can_recvfrom_newdata
+ *
+ * Description:
+ *   Copy the read data from the packet
+ *
+ * Input Parameters:
+ *   dev      The structure of the network driver that caused the event.
+ *   pstate   recvfrom state structure
+ *
+ * Returned Value:
+ *   None.
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static size_t can_recvfrom_newdata(FAR struct net_driver_s *dev,
+                                 FAR struct can_recvfrom_s *pstate)
+{
+  size_t recvlen;
+
+  if (dev->d_len > pstate->pr_buflen)
+    {
+      recvlen = pstate->pr_buflen;
+    }
+  else
+    {
+      recvlen = dev->d_len;
+    }
+
+  /* Copy the new packet data into the user buffer */
+
+  memcpy(pstate->pr_buffer, dev->d_buf, recvlen);
+
+  /* Update the accumulated size of the data read */
+
+  can_add_recvlen(pstate, recvlen);
+
+  return recvlen;
+}
+
+/****************************************************************************
+ * Name: can_newdata
+ *
+ * Description:
+ *   Copy the read data from the packet
+ *
+ * Input Parameters:
+ *   dev      The structure of the network driver that generated the event
+ *   pstate   recvfrom state structure
+ *
+ * Returned Value:
+ *   None.
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static inline void can_newdata(FAR struct net_driver_s *dev,
+                               FAR struct can_recvfrom_s *pstate)
+{
+  /* Take as much data from the packet as we can */
+
+  size_t recvlen = can_recvfrom_newdata(dev, pstate);
+
+  /* If there is more data left in the packet that we could not buffer, then
+   * add it to the read-ahead buffers.
+   */
+
+  if (recvlen < dev->d_len)
+    {
+      FAR struct can_conn_s *conn =
+        (FAR struct can_conn_s *)pstate->pr_sock->s_conn;
+      FAR uint8_t *buffer = (FAR uint8_t *)dev->d_appdata + recvlen;
+      uint16_t buflen = dev->d_len - recvlen;
+#ifdef CONFIG_DEBUG_NET
+      uint16_t nsaved;
+
+      nsaved = can_datahandler(conn, buffer, buflen);
+#else
+      can_datahandler(conn, buffer, buflen);
+#endif
+
+      /* There are complicated buffering issues that are not addressed fully
+       * here.  For example, what if up_datahandler() cannot buffer the
+       * remainder of the packet?  In that case, the data will be dropped but
+       * still ACKed.  Therefore it would not be resent.
+       *
+       * This is probably not an issue here because we only get here if the
+       * read-ahead buffers are empty and there would have to be something
+       * serioulsy wrong with the configuration not to be able to buffer a
+       * partial packet in this context.
+       */
+
+#ifdef CONFIG_DEBUG_NET
+      if (nsaved < buflen)
+        {
+          nerr("ERROR: packet data not saved (%d bytes)\n", buflen - nsaved);
+        }
+#endif
+    }
+
+  /* Indicate no data in the buffer */
+
+  dev->d_len = 0;
+}
+
+/****************************************************************************
+ * Name: can_readahead
+ *
+ * Description:
+ *   Copy the read-ahead data from the packet
+ *
+ * Input Parameters:
+ *   pstate   recvfrom state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static inline int can_readahead(struct can_recvfrom_s *pstate)
+{
+  FAR struct can_conn_s *conn =
+    (FAR struct can_conn_s *) pstate->pr_sock->s_conn;
+  FAR struct iob_s *iob;
+  int recvlen;
+
+  /* Check there is any CAN data already buffered in a read-ahead
+   * buffer.
+   */
+
+  pstate->pr_recvlen = -1;
+
+  if ((iob = iob_peek_queue(&conn->readahead)) != NULL &&
+      pstate->pr_buflen > 0)
+    {
+      DEBUGASSERT(iob->io_pktlen > 0);
+
+      /* Transfer that buffered data from the I/O buffer chain into
+       * the user buffer.
+       */
+
+      recvlen = iob_copyout(pstate->pr_buffer, iob, pstate->pr_buflen, 0);
+
+      /* If we took all of the data from the I/O buffer chain is empty, then
+       * release it.  If there is still data available in the I/O buffer
+       * chain, then just trim the data that we have taken from the
+       * beginning of the I/O buffer chain.
+       */
+
+      if (recvlen >= iob->io_pktlen)
+        {
+          FAR struct iob_s *tmp;
+
+          /* Remove the I/O buffer chain from the head of the read-ahead
+           * buffer queue.
+           */
+
+          tmp = iob_remove_queue(&conn->readahead);
+          DEBUGASSERT(tmp == iob);
+          UNUSED(tmp);
+
+          /* And free the I/O buffer chain */
+
+          iob_free_chain(iob, IOBUSER_NET_CAN_READAHEAD);
+        }
+      else
+        {
+          /* The bytes that we have received from the head of the I/O
+           * buffer chain (probably changing the head of the I/O
+           * buffer queue).
+           */
+
+          iob_trimhead_queue(&conn->readahead, recvlen,
+                             IOBUSER_NET_CAN_READAHEAD);
+        }
+
+      /* do not pass frames with DLC > 8 to a legacy socket */
+#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
+      if (!conn->fd_frames)
+#endif
+        {
+          if (recvlen > sizeof(struct can_frame))
+            {
+              return 0;
+            }
+        }
+
+      return recvlen;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: can_readahead
+ *
+ * Description:
+ *   Copy the read-ahead data from the packet
+ *
+ * Input Parameters:
+ *   pstate   recvfrom state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_TIMESTAMP
+static inline int can_readahead_timestamp(struct can_conn_s *conn,
+                                          FAR uint8_t *buffer)
+{
+  FAR struct iob_s *iob;
+  int recvlen;
+
+  if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
+    {
+      DEBUGASSERT(iob->io_pktlen > 0);
+
+      /* Transfer that buffered data from the I/O buffer chain into
+       * the user buffer.
+       */
+
+      recvlen = iob_copyout(buffer, iob, sizeof(struct timeval), 0);
+
+      /* If we took all of the data from the I/O buffer chain is empty, then
+       * release it.  If there is still data available in the I/O buffer
+       * chain, then just trim the data that we have taken from the
+       * beginning of the I/O buffer chain.
+       */
+
+      if (recvlen >= iob->io_pktlen)
+        {
+          FAR struct iob_s *tmp;
+
+          /* Remove the I/O buffer chain from the head of the read-ahead
+           * buffer queue.
+           */
+
+          tmp = iob_remove_queue(&conn->readahead);
+          DEBUGASSERT(tmp == iob);
+          UNUSED(tmp);
+
+          /* And free the I/O buffer chain */
+
+          iob_free_chain(iob, IOBUSER_NET_CAN_READAHEAD);
+        }
+      else
+        {
+          /* The bytes that we have received from the head of the I/O
+           * buffer chain (probably changing the head of the I/O
+           * buffer queue).
+           */
+
+          iob_trimhead_queue(&conn->readahead, recvlen,
+                             IOBUSER_NET_CAN_READAHEAD);
+        }
+
+      return recvlen;
+    }
+
+  return 0;
+}
+#endif
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+static int can_recv_filter(struct can_conn_s *conn, canid_t id)
+{
+  for (int i = 0; i < conn->filter_count; i++)
+    {
+      if (conn->filters[i].can_id & CAN_INV_FILTER)
+        {
+          if ((id & conn->filters[i].can_mask) !=
+                ((conn->filters[i].can_id & ~CAN_INV_FILTER) &
+                conn->filters[i].can_mask))
+            {
+              return 1;
+            }
+        }
+      else
+        {
+          if ((id & conn->filters[i].can_mask) ==
+                (conn->filters[i].can_id & conn->filters[i].can_mask))
+            {
+              return 1;
+            }
+        }
+    }
+
+  return 0;
+}
+#endif
+
+static uint16_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev,
+                                          FAR void *pvconn,
+                                          FAR void *pvpriv, uint16_t flags)
+{
+  struct can_recvfrom_s *pstate = (struct can_recvfrom_s *)pvpriv;
+  struct can_conn_s *conn = (struct can_conn_s *)pstate->pr_sock->s_conn;
+
+  /* 'priv' might be null in some race conditions (?) */
+
+  if (pstate)
+    {
+      if ((flags & CAN_NEWDATA) != 0)
+        {
+          /* If a new packet is available, check receive filters
+           * when is valid then complete the read action.
+           */
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+          if (can_recv_filter(conn, (canid_t) *dev->d_appdata) == 0)
+            {
+              flags &= ~CAN_NEWDATA;
+              return flags;
+            }
+#endif
+
+          /* do not pass frames with DLC > 8 to a legacy socket */
+#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
+          if (!conn->fd_frames)
+#endif
+            {
+              if (dev->d_len > sizeof(struct can_frame))
+                {
+                  /* DO WE NEED TO CLEAR FLAGS?? */
+
+                  flags &= ~CAN_NEWDATA;
+                  return flags;
+                }
+            }
+
+          /* Copy the packet */
+
+          can_newdata(dev, pstate);
+
+#ifdef CONFIG_NET_TIMESTAMP
+          if (pstate->pr_sock->s_timestamp)
+            {
+              if (pstate->pr_msglen == sizeof(struct timeval))
+                {
+                  can_readahead_timestamp(conn, pstate->pr_msgbuf);
+                }
+              else
+                {
+                  /* We still have to consume the data
+                   * otherwise IOB gets full
+                   */
+
+                  uint8_t dummy_buf[sizeof(struct timeval)];
+                  can_readahead_timestamp(conn, (uint8_t *)&dummy_buf);
+                }
+            }
+#endif
+
+          /* We are finished. */
+
+          /* Don't allow any further call backs. */
+
+          pstate->pr_cb->flags   = 0;
+          pstate->pr_cb->priv    = NULL;
+          pstate->pr_cb->event   = NULL;
+
+          /* indicate that the data has been consumed */
+
+          flags &= ~CAN_NEWDATA;
+
+          /* Wake up the waiting thread, returning the number of bytes
+           * actually read.
+           */
+
+          nxsem_post(&pstate->pr_sem);
+        }
+    }
+
+  return flags;
+}
+
+/****************************************************************************
+ * Name: can_recvfrom_result
+ *
+ * Description:
+ *   Evaluate the result of the recv operations
+ *
+ * Input Parameters:
+ *   result   The result of the net_lockedwait operation (may indicate EINTR)
+ *   pstate   A pointer to the state structure to be initialized
+ *
+ * Returned Value:
+ *   The result of the recv operation with errno set appropriately
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static ssize_t can_recvfrom_result(int result,
+                                   FAR struct can_recvfrom_s *pstate)
+{
+  /* Check for a error/timeout detected by the event handler.  Errors are
+   * signaled by negative errno values for the rcv length
+   */
+
+  if (pstate->pr_result < 0)
+    {
+      /* This might return EAGAIN on a timeout */
+
+      return pstate->pr_result;
+    }
+
+  /* If net_lockedwait failed, then we were probably reawakened by a signal.
+   * In this case, net_lockedwait will have returned negated errno
+   * appropriately.
+   */
+
+  if (result < 0)
+    {
+      return result;
+    }
+
+  return pstate->pr_recvlen;
+}
+
+/****************************************************************************
+ * Name: can_recvfrom
+ *
+ * Description:
+ *   recvfrom() receives messages from a socket, and may be used to receive
+ *   data on a socket whether or not it is connection-oriented.
+ *
+ *   If from is not NULL, and the underlying protocol provides the source
+ *   address, this source address is filled in. The argument 'fromlen'
+ *   initialized to the size of the buffer associated with from, and modified
+ *   on return to indicate the actual size of the address stored there.
+ *
+ * Input Parameters:
+ *   psock    A pointer to a NuttX-specific, internal socket structure
+ *   buf      Buffer to receive data
+ *   len      Length of buffer
+ *   flags    Receive flags (ignored)
+ *   from     Address of source (may be NULL)
+ *   fromlen  The length of the address structure
+ *
+ ****************************************************************************/
+
+ssize_t can_recvfrom(FAR struct socket *psock, FAR void *buf,
+                                size_t len, int flags,
+                                FAR struct sockaddr *from,
+                                FAR socklen_t *fromlen)
+{
+  FAR struct can_conn_s *conn;
+  FAR struct net_driver_s *dev;
+  struct can_recvfrom_s state;
+  int ret;
+
+  DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL);
+  DEBUGASSERT(from == NULL ||
+              (fromlen != NULL && *fromlen >= sizeof(struct sockaddr_can)));
+
+  conn = (FAR struct can_conn_s *)psock->s_conn;
+
+  if (psock->s_type != SOCK_RAW)
+    {
+      nerr("ERROR: Unsupported socket type: %d\n", psock->s_type);
+      ret = -ENOSYS;
+    }
+
+  net_lock();
+
+  /* Initialize the state structure. */
+
+  memset(&state, 0, sizeof(struct can_recvfrom_s));
+
+  /* This semaphore is used for signaling and, hence, should not have
+   * priority inheritance enabled.
+   */
+
+  nxsem_init(&state.pr_sem, 0, 0); /* Doesn't really fail */
+  nxsem_set_protocol(&state.pr_sem, SEM_PRIO_NONE);
+
+  state.pr_buflen = len;
+  state.pr_buffer = buf;
+  state.pr_sock   = psock;
+
+  /* Handle any any CAN data already buffered in a read-ahead buffer.  NOTE
+   * that there may be read-ahead data to be retrieved even after the
+   * socket has been disconnected.
+   */
+
+  ret = can_readahead(&state);
+  if (ret > 0)
+    {
+      goto errout_with_state;
+    }
+
+  ret = state.pr_recvlen;
+
+  /* Handle non-blocking CAN sockets */
+
+  if (_SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0)
+    {
+      /* Return the number of bytes read from the read-ahead buffer if
+       * something was received (already in 'ret'); EAGAIN if not.
+       */
+
+      if (ret < 0)
+        {
+          /* Nothing was received */
+
+          ret = -EAGAIN;
+          goto errout_with_state;
+        }
+    }
+
+  /* Get the device driver that will service this transfer */
+
+  dev  = conn->dev;
+  if (dev == NULL)
+    {
+      ret = -ENODEV;
+      goto errout_with_state;
+    }
+
+  /* Set up the callback in the connection */
+
+  state.pr_cb = can_callback_alloc(dev, conn);
+  if (state.pr_cb)
+    {
+      state.pr_cb->flags  = (CAN_NEWDATA | CAN_POLL);
+      state.pr_cb->priv   = (FAR void *)&state;
+      state.pr_cb->event  = can_recvfrom_eventhandler;
+
+      /* Wait for either the receive to complete or for an error/timeout to
+       * occur. NOTES:  (1) net_lockedwait will also terminate if a signal
+       * is received, (2) the network is locked!  It will be un-locked while
+       * the task sleeps and automatically re-locked when the task restarts.
+       */
+
+      ret = net_lockedwait(&state.pr_sem);
+
+      /* Make sure that no further events are processed */
+
+      can_callback_free(dev, conn, state.pr_cb);
+      ret = can_recvfrom_result(ret, &state);
+    }
+  else
+    {
+      ret = -EBUSY;
+    }
+
+errout_with_state:
+  net_unlock();
+  nxsem_destroy(&state.pr_sem);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: can_recvmsg
+ *
+ * Description:
+ *   recvmsg() receives messages from a socket, and may be used to receive
+ *   data on a socket whether or not it is connection-oriented.
+ *
+ *   If from is not NULL, and the underlying protocol provides the source
+ *   address, this source address is filled in. The argument 'fromlen'
+ *   initialized to the size of the buffer associated with from, and modified
+ *   on return to indicate the actual size of the address stored there.
+ *
+ * Input Parameters:
+ *   psock    A pointer to a NuttX-specific, internal socket structure
+ *   msg      Buffer to receive msg
+ *   flags    Receive flags (ignored)
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CMSG
+ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+                    int flags)
+{
+  FAR struct can_conn_s *conn;
+  FAR struct net_driver_s *dev;
+  struct can_recvfrom_s state;
+  int ret;
+
+  DEBUGASSERT(psock != NULL && psock->s_conn != NULL && msg != NULL);
+
+  conn = (FAR struct can_conn_s *)psock->s_conn;
+
+  if (psock->s_type != SOCK_RAW)
+    {
+      nerr("ERROR: Unsupported socket type: %d\n", psock->s_type);
+      ret = -ENOSYS;
+    }
+
+  net_lock();
+
+  /* Initialize the state structure. */
+
+  memset(&state, 0, sizeof(struct can_recvfrom_s));
+
+  /* This semaphore is used for signaling and, hence, should not have
+   * priority inheritance enabled.
+   */
+
+  nxsem_init(&state.pr_sem, 0, 0); /* Doesn't really fail */
+  nxsem_set_protocol(&state.pr_sem, SEM_PRIO_NONE);
+
+  state.pr_buflen = msg->msg_iov->iov_len;
+  state.pr_buffer = msg->msg_iov->iov_base;
+
+#ifdef CONFIG_NET_TIMESTAMP
+  if (psock->s_timestamp && msg->msg_controllen >=
+        (sizeof(struct cmsghdr) + sizeof(struct timeval)))
+    {
+      struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+      state.pr_msglen = sizeof(struct timeval);
+      state.pr_msgbuf = CMSG_DATA(cmsg);
+      cmsg->cmsg_level = SOL_SOCKET;
+      cmsg->cmsg_type = SO_TIMESTAMP;
+      cmsg->cmsg_len = state.pr_msglen;
+      msg->msg_controllen = sizeof(struct cmsghdr) + sizeof(struct timeval);
+    }
+  else
+    {
+      /* Expected behavior is that the msg_controllen becomes 0,
+       * otherwise CMSG_NXTHDR will go into a infinite loop
+       */
+
+      msg->msg_controllen = 0;
+    }
+#endif
+
+  state.pr_sock   = psock;
+
+  /* Handle any any CAN data already buffered in a read-ahead buffer.  NOTE
+   * that there may be read-ahead data to be retrieved even after the
+   * socket has been disconnected.
+   */
+
+  ret = can_readahead(&state);
+  if (ret > 0)
+    {
+#ifdef CONFIG_NET_TIMESTAMP
+      if (psock->s_timestamp)
+        {
+          if (state.pr_msglen == sizeof(struct timeval))
+            {
+              can_readahead_timestamp(conn, state.pr_msgbuf);
+            }
+          else
+            {
+              /* We still have to consume the data otherwise IOB gets full */
+
+              uint8_t dummy_buf[sizeof(struct timeval)];
+              can_readahead_timestamp(conn, (uint8_t *)&dummy_buf);
+            }
+        }
+#endif
+
+      goto errout_with_state;
+    }
+
+  ret = state.pr_recvlen;
+
+  /* Handle non-blocking CAN sockets */
+
+  if (_SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0)
+    {
+      /* Return the number of bytes read from the read-ahead buffer if
+       * something was received (already in 'ret'); EAGAIN if not.
+       */
+
+      if (ret < 0)
+        {
+          /* Nothing was received */
+
+          ret = -EAGAIN;
+          goto errout_with_state;
+        }
+    }
+
+  /* Get the device driver that will service this transfer */
+
+  dev  = conn->dev;
+  if (dev == NULL)
+    {
+      ret = -ENODEV;
+      goto errout_with_state;
+    }
+
+  /* Set up the callback in the connection */
+
+  state.pr_cb = can_callback_alloc(dev, conn);
+  if (state.pr_cb)
+    {
+      state.pr_cb->flags  = (CAN_NEWDATA | CAN_POLL);
+      state.pr_cb->priv   = (FAR void *)&state;
+      state.pr_cb->event  = can_recvfrom_eventhandler;
+
+      /* Wait for either the receive to complete or for an error/timeout to
+       * occur. NOTES:  (1) net_lockedwait will also terminate if a signal
+       * is received, (2) the network is locked!  It will be un-locked while
+       * the task sleeps and automatically re-locked when the task restarts.
+       */
+
+      ret = net_lockedwait(&state.pr_sem);
+
+      /* Make sure that no further events are processed */
+
+      can_callback_free(dev, conn, state.pr_cb);
+      ret = can_recvfrom_result(ret, &state);
+    }
+  else
+    {
+      ret = -EBUSY;
+    }
+
+errout_with_state:
+  net_unlock();
+  nxsem_destroy(&state.pr_sem);
+  return ret;
+}
+#endif
+
+#endif /* CONFIG_NET_CAN */
diff --git a/net/can/can_send.c b/net/can/can_send.c
new file mode 100644
index 0000000..3c01684
--- /dev/null
+++ b/net/can/can_send.c
@@ -0,0 +1,441 @@
+/****************************************************************************
+ * net/can/can_send.c
+ *
+ *   Copyright (C) 2014, 2016-2017 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include <nuttx/semaphore.h>
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/net.h>
+#include <nuttx/net/ip.h>
+
+#include "netdev/netdev.h"
+#include "devif/devif.h"
+#include "socket/socket.h"
+#include "can/can.h"
+
+#ifdef CONFIG_NET_CMSG
+#include <sys/time.h>
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure holds the state of the send operation until it can be
+ * operated upon by the event handler.
+ */
+
+struct send_s
+{
+  FAR struct socket      *snd_sock;    /* Points to the parent socket structure */
+  FAR struct devif_callback_s *snd_cb; /* Reference to callback instance */
+  sem_t                   snd_sem;     /* Used to wake up the waiting thread */
+  FAR const uint8_t      *snd_buffer;  /* Points to the buffer of data to send */
+  size_t                  snd_buflen;  /* Number of bytes in the buffer to send */
+#ifdef CONFIG_NET_CMSG
+  size_t                  pr_msglen;   /* Length of msg buffer */
+  FAR uint8_t            *pr_msgbuf;   /* Pointer to msg buffer */
+#endif
+  ssize_t                 snd_sent;    /* The number of bytes sent */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_send_eventhandler
+ ****************************************************************************/
+
+static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
+                                        FAR void *pvconn,
+                                        FAR void *pvpriv, uint16_t flags)
+{
+  FAR struct send_s *pstate = (FAR struct send_s *)pvpriv;
+
+  if (pstate)
+    {
+      /* Check if the outgoing packet is available. It may have been claimed
+       * by a send event handler serving a different thread -OR- if the
+       * output buffer currently contains unprocessed incoming data. In
+       * these cases we will just have to wait for the next polling cycle.
+       */
+
+      if (dev->d_sndlen > 0 || (flags & CAN_NEWDATA) != 0)
+        {
+          /* Another thread has beat us sending data or the buffer is busy,
+           * Check for a timeout. If not timed out, wait for the next
+           * polling cycle and check again.
+           */
+
+          /* No timeout. Just wait for the next polling cycle */
+
+          return flags;
+        }
+
+      /* It looks like we are good to send the data */
+
+      else
+        {
+          /* Copy the packet data into the device packet buffer and send it */
+
+          devif_can_send(dev, pstate->snd_buffer, pstate->snd_buflen);
+          pstate->snd_sent = pstate->snd_buflen;
+#ifdef CONFIG_NET_CMSG
+          if (pstate->pr_msglen > 0) /* concat cmsg data after packet */
+            {
+              memcpy(dev->d_buf + pstate->snd_buflen, pstate->pr_msgbuf,
+                      pstate->pr_msglen);
+              dev->d_sndlen = pstate->snd_buflen + pstate->pr_msglen;
+            }
+#endif
+        }
+
+      /* Don't allow any further call backs. */
+
+      pstate->snd_cb->flags    = 0;
+      pstate->snd_cb->priv     = NULL;
+      pstate->snd_cb->event    = NULL;
+
+      /* Wake up the waiting thread */
+
+      nxsem_post(&pstate->snd_sem);
+    }
+
+  return flags;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_can_send
+ *
+ * Description:
+ *   The psock_can_send() call may be used only when the packet socket is in
+ *   a connected state (so that the intended recipient is known).
+ *
+ * Input Parameters:
+ *   psock    An instance of the internal socket structure.
+ *   buf      Data to send
+ *   len      Length of data to send
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  On  error,
+ *   a negated errno value is retruend.  See send() for the complete list
+ *   of return values.
+ *
+ ****************************************************************************/
+
+ssize_t psock_can_send(FAR struct socket *psock, FAR const void *buf,
+                       size_t len)
+{
+  FAR struct net_driver_s *dev;
+  FAR struct can_conn_s *conn;
+  struct send_s state;
+  int ret = OK;
+
+  conn = (FAR struct can_conn_s *)psock->s_conn;
+
+  /* Verify that the sockfd corresponds to valid, allocated socket */
+
+  if (!psock || psock->s_crefs <= 0)
+    {
+      return -EBADF;
+    }
+
+  /* Get the device driver that will service this transfer */
+
+  dev = conn->dev;
+  if (dev == NULL)
+    {
+      return -ENODEV;
+    }
+#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
+
+  if (conn->fd_frames)
+    {
+      if (len != CANFD_MTU && len != CAN_MTU)
+        {
+          return -EINVAL;
+        }
+    }
+#endif
+  else
+    {
+      if (len != CAN_MTU)
+        {
+          return -EINVAL;
+        }
+    }
+
+  /* Perform the send operation */
+
+  /* Initialize the state structure. This is done with the network locked
+   * because we don't want anything to happen until we are ready.
+   */
+
+  net_lock();
+  memset(&state, 0, sizeof(struct send_s));
+
+  /* This semaphore is used for signaling and, hence, should not have
+   * priority inheritance enabled.
+   */
+
+  nxsem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */
+  nxsem_set_protocol(&state.snd_sem, SEM_PRIO_NONE);
+
+  state.snd_sock      = psock;          /* Socket descriptor to use */
+  state.snd_buflen    = len;            /* Number of bytes to send */
+  state.snd_buffer    = buf;            /* Buffer to send from */
+
+  /* Allocate resource to receive a callback */
+
+  state.snd_cb = can_callback_alloc(dev, conn);
+  if (state.snd_cb)
+    {
+      /* Set up the callback in the connection */
+
+      state.snd_cb->flags = CAN_POLL;
+      state.snd_cb->priv  = (FAR void *)&state;
+      state.snd_cb->event = psock_send_eventhandler;
+
+      /* Notify the device driver that new TX data is available. */
+
+      netdev_txnotify_dev(dev);
+
+      /* Wait for the send to complete or an error to occur.
+       * net_lockedwait will also terminate if a signal is received.
+       */
+
+      ret = net_lockedwait(&state.snd_sem);
+
+      /* Make sure that no further events are processed */
+
+      can_callback_free(dev, conn, state.snd_cb);
+    }
+
+  nxsem_destroy(&state.snd_sem);
+  net_unlock();
+
+  /* Check for a errors, Errors are signalled by negative errno values
+   * for the send length
+   */
+
+  if (state.snd_sent < 0)
+    {
+      return state.snd_sent;
+    }
+
+  /* If net_lockedwait failed, then we were probably reawakened by a signal.
+   * In this case, net_lockedwait will have returned negated errno
+   * appropriately.
+   */
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Return the number of bytes actually sent */
+
+  return state.snd_sent;
+}
+
+/****************************************************************************
+ * Name: psock_can_sendmsg
+ *
+ * Description:
+ *   The psock_can_sendmsg() call may be used only when the packet socket is
+ *   in a connected state (so that the intended recipient is known).
+ *
+ * Input Parameters:
+ *   psock    An instance of the internal socket structure.
+ *   msg      msg to send
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  On  error,
+ *   a negated errno value is retruend.  See send() for the complete list
+ *   of return values.
+ *
+ ****************************************************************************/
+
+ssize_t psock_can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg)
+{
+  FAR struct net_driver_s *dev;
+  FAR struct can_conn_s *conn;
+  struct send_s state;
+  int ret = OK;
+
+  conn = (FAR struct can_conn_s *)psock->s_conn;
+
+  /* Verify that the sockfd corresponds to valid, allocated socket */
+
+  if (!psock || psock->s_crefs <= 0)
+    {
+      return -EBADF;
+    }
+
+  /* Get the device driver that will service this transfer */
+
+  dev = conn->dev;
+  if (dev == NULL)
+    {
+      return -ENODEV;
+    }
+
+#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
+  if (conn->fd_frames)
+    {
+      if (msg->msg_iov->iov_len != CANFD_MTU
+              && msg->msg_iov->iov_len != CAN_MTU)
+        {
+          return -EINVAL;
+        }
+    }
+  else
+#endif
+    {
+      if (msg->msg_iov->iov_len != CAN_MTU)
+        {
+          return -EINVAL;
+        }
+    }
+
+  /* Perform the send operation */
+
+  /* Initialize the state structure. This is done with the network locked
+   * because we don't want anything to happen until we are ready.
+   */
+
+  net_lock();
+  memset(&state, 0, sizeof(struct send_s));
+
+  /* This semaphore is used for signaling and, hence, should not have
+   * priority inheritance enabled.
+   */
+
+  nxsem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */
+  nxsem_set_protocol(&state.snd_sem, SEM_PRIO_NONE);
+
+  state.snd_sock      = psock;                  /* Socket descriptor */
+  state.snd_buflen    = msg->msg_iov->iov_len;  /* bytes to send */
+  state.snd_buffer    = msg->msg_iov->iov_base; /* Buffer to send from */
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+  if (msg->msg_controllen > sizeof(struct cmsghdr))
+    {
+      struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+      if (conn->tx_deadline && cmsg->cmsg_level == SOL_CAN_RAW
+              && cmsg->cmsg_type == CAN_RAW_TX_DEADLINE
+              && cmsg->cmsg_len == sizeof(struct timeval))
+        {
+          state.pr_msgbuf     = CMSG_DATA(cmsg); /* Buffer to cmsg data */
+          state.pr_msglen     = cmsg->cmsg_len;  /* len of cmsg data */
+        }
+    }
+#endif
+
+  /* Allocate resource to receive a callback */
+
+  state.snd_cb = can_callback_alloc(dev, conn);
+  if (state.snd_cb)
+    {
+      /* Set up the callback in the connection */
+
+      state.snd_cb->flags = CAN_POLL;
+      state.snd_cb->priv  = (FAR void *)&state;
+      state.snd_cb->event = psock_send_eventhandler;
+
+      /* Notify the device driver that new TX data is available. */
+
+      netdev_txnotify_dev(dev);
+
+      /* Wait for the send to complete or an error to occur.
+       * net_lockedwait will also terminate if a signal is received.
+       */
+
+      ret = net_lockedwait(&state.snd_sem);
+
+      /* Make sure that no further events are processed */
+
+      can_callback_free(dev, conn, state.snd_cb);
+    }
+
+  nxsem_destroy(&state.snd_sem);
+  net_unlock();
+
+  /* Check for a errors, Errors are signalled by negative errno values
+   * for the send length
+   */
+
+  if (state.snd_sent < 0)
+    {
+      return state.snd_sent;
+    }
+
+  /* If net_lockedwait failed, then we were probably reawakened by a signal.
+   * In this case, net_lockedwait will have returned negated errno
+   * appropriately.
+   */
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Return the number of bytes actually sent */
+
+  return state.snd_sent;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/net/can/can_setsockopt.c b/net/can/can_setsockopt.c
new file mode 100644
index 0000000..3359e40
--- /dev/null
+++ b/net/can/can_setsockopt.c
@@ -0,0 +1,177 @@
+/****************************************************************************
+ * net/can/can_setsockopt.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 <sys/time.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <netpacket/can.h>
+
+#include <nuttx/net/net.h>
+#include <nuttx/net/can.h>
+
+#include "socket/socket.h"
+#include "utils/utils.h"
+#include "can/can.h"
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_setsockopt
+ *
+ * Description:
+ *   can_setsockopt() sets the CAN-protocol option specified by the
+ *   'option' argument to the value pointed to by the 'value' argument for
+ *   the socket specified by the 'psock' argument.
+ *
+ *   See <netinet/can.h> for the a complete list of values of CAN protocol
+ *   options.
+ *
+ * Input Parameters:
+ *   psock     Socket structure of socket to operate on
+ *   option    identifies the option to set
+ *   value     Points to the argument value
+ *   value_len The length of the argument value
+ *
+ * Returned Value:
+ *   Returns zero (OK) on success.  On failure, it returns a negated errno
+ *   value to indicate the nature of the error.  See psock_setcockopt() for
+ *   the list of possible error values.
+ *
+ ****************************************************************************/
+
+int can_setsockopt(FAR struct socket *psock, int option,
+                   FAR const void *value, socklen_t value_len)
+{
+  FAR struct can_conn_s *conn;
+  int ret;
+  int count = 0;
+
+  DEBUGASSERT(psock != NULL && value != NULL && psock->s_conn != NULL);
+  conn = (FAR struct can_conn_s *)psock->s_conn;
+
+  if (psock->s_type != SOCK_RAW)
+    {
+      nerr("ERROR:  Not a RAW CAN socket\n");
+      return -ENOTCONN;
+    }
+
+  switch (option)
+    {
+      case CAN_RAW_FILTER:
+        if (value_len == 0)
+          {
+            conn->filter_count = 0;
+            ret = OK;
+          }
+        else if (value_len % sizeof(struct can_filter) != 0)
+          {
+            ret = -EINVAL;
+          }
+        else if (value_len > CONFIG_NET_CAN_RAW_FILTER_MAX *
+                   sizeof(struct can_filter))
+          {
+            ret = -EINVAL;
+          }
+        else
+          {
+        count = value_len / sizeof(struct can_filter);
+
+        for (int i = 0; i < count; i++)
+          {
+        conn->filters[i] = ((struct can_filter *)value)[i];
+          }
+
+        conn->filter_count = count;
+
+            ret = OK;
+          }
+        break;
+
+      case CAN_RAW_ERR_FILTER:
+        break;
+
+      case CAN_RAW_LOOPBACK:
+        if (value_len != sizeof(conn->loopback))
+          {
+            return -EINVAL;
+          }
+
+        conn->loopback = *(FAR int32_t *)value;
+
+        break;
+
+      case CAN_RAW_RECV_OWN_MSGS:
+        if (value_len != sizeof(conn->recv_own_msgs))
+          {
+            return -EINVAL;
+          }
+
+        conn->recv_own_msgs = *(FAR int32_t *)value;
+
+        break;
+
+      case CAN_RAW_FD_FRAMES:
+        if (value_len != sizeof(conn->fd_frames))
+          {
+            return -EINVAL;
+          }
+
+          conn->fd_frames = *(FAR int32_t *)value;
+
+          break;
+
+      case CAN_RAW_JOIN_FILTERS:
+        break;
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+      case CAN_RAW_TX_DEADLINE:
+        if (value_len != sizeof(conn->tx_deadline))
+          {
+            return -EINVAL;
+          }
+
+        conn->tx_deadline = *(FAR int32_t *)value;
+
+        break;
+#endif
+
+      default:
+        nerr("ERROR: Unrecognized CAN option: %d\n", option);
+        ret = -ENOPROTOOPT;
+        break;
+    }
+
+  return ret;
+}
+
+#endif /* CONFIG_NET_CANPROTO_OPTIONS */
diff --git a/net/netlink/netlink_sockif.c b/net/can/can_sockif.c
similarity index 52%
copy from net/netlink/netlink_sockif.c
copy to net/can/can_sockif.c
index 577d520..d39934f 100644
--- a/net/netlink/netlink_sockif.c
+++ b/net/can/can_sockif.c
@@ -1,35 +1,20 @@
 /****************************************************************************
- * net/netlink/netlink_sockif.c
- *
- *   Copyright (C) 2018-2019 Gregory Nutt. All rights reserved.
- *   Author: Gregory Nutt <gn...@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * net/can/can_sockif.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.
  *
  ****************************************************************************/
 
@@ -54,64 +39,69 @@
 #include <nuttx/wqueue.h>
 #include <nuttx/net/net.h>
 
-#include "netlink/netlink.h"
+#include "can/can.h"
+#include "netdev/netdev.h"
 
-#ifdef CONFIG_NET_NETLINK
+#ifdef CONFIG_NET_CAN
 
 /****************************************************************************
  * Private Function Prototypes
  ****************************************************************************/
 
-static int  netlink_setup(FAR struct socket *psock, int protocol);
-static sockcaps_t netlink_sockcaps(FAR struct socket *psock);
-static void netlink_addref(FAR struct socket *psock);
-static int  netlink_bind(FAR struct socket *psock,
+static int  can_setup(FAR struct socket *psock, int protocol);
+static sockcaps_t can_sockcaps(FAR struct socket *psock);
+static void can_addref(FAR struct socket *psock);
+static int  can_bind(FAR struct socket *psock,
               FAR const struct sockaddr *addr, socklen_t addrlen);
-static int  netlink_getsockname(FAR struct socket *psock,
+static int  can_getsockname(FAR struct socket *psock,
               FAR struct sockaddr *addr, FAR socklen_t *addrlen);
-static int  netlink_getpeername(FAR struct socket *psock,
+static int  can_getpeername(FAR struct socket *psock,
               FAR struct sockaddr *addr, FAR socklen_t *addrlen);
-static int  netlink_listen(FAR struct socket *psock, int backlog);
-static int  netlink_connect(FAR struct socket *psock,
+static int  can_listen(FAR struct socket *psock, int backlog);
+static int  can_connect(FAR struct socket *psock,
               FAR const struct sockaddr *addr, socklen_t addrlen);
-static int  netlink_accept(FAR struct socket *psock,
-              FAR struct sockaddr *addr, FAR socklen_t *addrlen,
-              FAR struct socket *newsock);
-static int  netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
+static int  can_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
+              FAR socklen_t *addrlen, FAR struct socket *newsock);
+static int  can_poll_local(FAR struct socket *psock, FAR struct pollfd *fds,
               bool setup);
-static ssize_t netlink_send(FAR struct socket *psock,
+static ssize_t can_send(FAR struct socket *psock,
               FAR const void *buf, size_t len, int flags);
-static ssize_t netlink_sendto(FAR struct socket *psock, FAR const void *buf,
+static ssize_t can_sendto(FAR struct socket *psock, FAR const void *buf,
               size_t len, int flags, FAR const struct sockaddr *to,
               socklen_t tolen);
-static ssize_t netlink_recvfrom(FAR struct socket *psock, FAR void *buf,
-              size_t len, int flags, FAR struct sockaddr *from,
-              FAR socklen_t *fromlen);
-static int netlink_close(FAR struct socket *psock);
+#ifdef CONFIG_NET_CMSG
+static ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+                    int flags);
+#endif
+static int can_close(FAR struct socket *psock);
 
 /****************************************************************************
  * Public Data
  ****************************************************************************/
 
-const struct sock_intf_s g_netlink_sockif =
+const struct sock_intf_s g_can_sockif =
 {
-  netlink_setup,        /* si_setup */
-  netlink_sockcaps,     /* si_sockcaps */
-  netlink_addref,       /* si_addref */
-  netlink_bind,         /* si_bind */
-  netlink_getsockname,  /* si_getsockname */
-  netlink_getpeername,  /* si_getpeername */
-  netlink_listen,       /* si_listen */
-  netlink_connect,      /* si_connect */
-  netlink_accept,       /* si_accept */
-  netlink_poll,         /* si_poll */
-  netlink_send,         /* si_send */
-  netlink_sendto,       /* si_sendto */
+  can_setup,        /* si_setup */
+  can_sockcaps,     /* si_sockcaps */
+  can_addref,       /* si_addref */
+  can_bind,         /* si_bind */
+  can_getsockname,  /* si_getsockname */
+  can_getpeername,  /* si_getpeername */
+  can_listen,       /* si_listen */
+  can_connect,      /* si_connect */
+  can_accept,       /* si_accept */
+  can_poll_local,   /* si_poll */
+  can_send,         /* si_send */
+  can_sendto,       /* si_sendto */
 #ifdef CONFIG_NET_SENDFILE
-  NULL,                 /* si_sendfile */
+  NULL,             /* si_sendfile */
+#endif
+  can_recvfrom,     /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+  can_recvmsg,      /* si_recvmsg */
+  can_sendmsg,      /* si_sendmsg */
 #endif
-  netlink_recvfrom,     /* si_recvfrom */
-  netlink_close         /* si_close */
+  can_close         /* si_close */
 };
 
 /****************************************************************************
@@ -119,7 +109,77 @@ const struct sock_intf_s g_netlink_sockif =
  ****************************************************************************/
 
 /****************************************************************************
- * Name: netlink_setup
+ * Name: can_poll_eventhandler
+ *
+ * Description:
+ *   This function is called to perform the actual CAN receive operation
+ *   via the device interface layer. from can_input()
+ *
+ * Input Parameters:
+ *   dev      The structure of the network driver that caused the event
+ *   conn     The connection structure associated with the socket
+ *   flags    Set of events describing why the callback was invoked
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+static uint16_t can_poll_eventhandler(FAR struct net_driver_s *dev,
+                                      FAR void *conn,
+                                      FAR void *pvpriv, uint16_t flags)
+{
+  FAR struct can_poll_s *info = (FAR struct can_poll_s *)pvpriv;
+
+  DEBUGASSERT(!info || (info->psock && info->fds));
+
+  /* 'priv' might be null in some race conditions (?) */
+
+  if (info)
+    {
+      pollevent_t eventset = 0;
+
+      /* Check for data or connection availability events. */
+
+      if ((flags & CAN_NEWDATA) != 0)
+        {
+          eventset |= (POLLIN & info->fds->events);
+        }
+
+      /* Check for loss of connection events. */
+
+      if ((flags & NETDEV_DOWN) != 0)
+        {
+          eventset |= (POLLHUP | POLLERR);
+        }
+
+#if 0
+      /* A poll is a sign that we are free to send data. */
+
+      else if ((flags & CAN_POLL) != 0 &&
+                 psock_udp_cansend(info->psock) >= 0)
+        {
+          eventset |= (POLLOUT & info->fds->events);
+        }
+#endif
+
+      /* Awaken the caller of poll() is requested event occurred. */
+
+      if (eventset)
+        {
+          info->fds->revents |= eventset;
+          nxsem_post(info->fds->sem);
+        }
+    }
+
+  return flags;
+}
+
+/****************************************************************************
+ * Name: can_setup
  *
  * Description:
  *   Called for socket() to verify that the provided socket type and
@@ -137,7 +197,7 @@ const struct sock_intf_s g_netlink_sockif =
  *
  ****************************************************************************/
 
-static int netlink_setup(FAR struct socket *psock, int protocol)
+static int can_setup(FAR struct socket *psock, int protocol)
 {
   int domain = psock->s_domain;
   int type = psock->s_type;
@@ -148,24 +208,29 @@ static int netlink_setup(FAR struct socket *psock, int protocol)
 
   switch (protocol)
     {
-#ifdef CONFIG_NETLINK_ROUTE
-      case NETLINK_ROUTE:
+      case 0:            /* INET subsystem for netlib_ifup */
+      case CAN_RAW:      /* RAW sockets */
+      case CAN_BCM:      /* Broadcast Manager */
+      case CAN_TP16:     /* VAG Transport Protocol v1.6 */
+      case CAN_TP20:     /* VAG Transport Protocol v2.0 */
+      case CAN_MCNET:    /* Bosch MCNet */
+      case CAN_ISOTP:    /* ISO 15765-2 Transport Protocol */
+      case CAN_J1939:    /* SAE J1939 */
         break;
-#endif
 
       default:
         return -EPROTONOSUPPORT;
     }
 
-  /* Verify the socket type (domain should always be PF_NETLINK here) */
+  /* Verify the socket type (domain should always be PF_CAN here) */
 
-  if (domain == PF_NETLINK && (type == SOCK_RAW || type == SOCK_DGRAM))
+  if (domain == PF_CAN && (type == SOCK_RAW || type == SOCK_DGRAM))
     {
       /* Allocate the NetLink socket connection structure and save it in the
        * new socket instance.
        */
 
-      FAR struct netlink_conn_s *conn = netlink_alloc();
+      FAR struct can_conn_s *conn = can_alloc();
       if (conn == NULL)
         {
           /* Failed to reserve a connection structure */
@@ -173,6 +238,12 @@ static int netlink_setup(FAR struct socket *psock, int protocol)
           return -ENOMEM;
         }
 
+#ifdef CONFIG_NET_TIMESTAMP
+      /* Store psock in conn se we can read the SO_TIMESTAMP value */
+
+      conn->psock = psock;
+#endif
+
       /* Initialize the connection instance */
 
       conn->protocol = (uint8_t)protocol;
@@ -194,7 +265,7 @@ static int netlink_setup(FAR struct socket *psock, int protocol)
 }
 
 /****************************************************************************
- * Name: netlink_sockcaps
+ * Name: can_sockcaps
  *
  * Description:
  *   Return the bit encoded capabilities of this socket.
@@ -208,7 +279,7 @@ static int netlink_setup(FAR struct socket *psock, int protocol)
  *
  ****************************************************************************/
 
-static sockcaps_t netlink_sockcaps(FAR struct socket *psock)
+static sockcaps_t can_sockcaps(FAR struct socket *psock)
 {
   /* Permit vfcntl to set socket to non-blocking */
 
@@ -216,7 +287,7 @@ static sockcaps_t netlink_sockcaps(FAR struct socket *psock)
 }
 
 /****************************************************************************
- * Name: netlink_addref
+ * Name: can_addref
  *
  * Description:
  *   Increment the reference count on the underlying connection structure.
@@ -230,9 +301,9 @@ static sockcaps_t netlink_sockcaps(FAR struct socket *psock)
  *
  ****************************************************************************/
 
-static void netlink_addref(FAR struct socket *psock)
+static void can_addref(FAR struct socket *psock)
 {
-  FAR struct netlink_conn_s *conn;
+  FAR struct can_conn_s *conn;
 
   DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
 
@@ -242,10 +313,10 @@ static void netlink_addref(FAR struct socket *psock)
 }
 
 /****************************************************************************
- * Name: netlink_bind
+ * Name: can_bind
  *
  * Description:
- *   netlink_bind() gives the socket 'conn' the local address 'addr'. 'addr'
+ *   can_bind() gives the socket 'conn' the local address 'addr'. 'addr'
  *   is 'addrlen' bytes long. Traditionally, this is called "assigning a name
  *   to a socket." When a socket is created with socket, it exists in a name
  *   space (address family) but has no name assigned.
@@ -271,28 +342,34 @@ static void netlink_addref(FAR struct socket *psock)
  *
  ****************************************************************************/
 
-static int netlink_bind(FAR struct socket *psock,
-                        FAR const struct sockaddr *addr, socklen_t addrlen)
+static int can_bind(FAR struct socket *psock,
+                    FAR const struct sockaddr *addr, socklen_t addrlen)
 {
-  FAR struct sockaddr_nl *nladdr;
-  FAR struct netlink_conn_s *conn;
-
+  FAR struct sockaddr_can *canaddr;
+  FAR struct can_conn_s *conn;
   DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL &&
-              addrlen >= sizeof(struct sockaddr_nl));
+              addrlen >= sizeof(struct sockaddr_can));
 
   /* Save the address information in the connection structure */
 
-  nladdr = (FAR struct sockaddr_nl *)addr;
-  conn   = (FAR struct netlink_conn_s *)psock->s_conn;
+  canaddr = (FAR struct sockaddr_can *)addr;
+  conn    = (FAR struct can_conn_s *)psock->s_conn;
+
+  /* Bind CAN device to socket */
 
-  conn->pid    = nladdr->nl_pid ? nladdr->nl_pid : getpid();
-  conn->groups = nladdr->nl_groups;
+#ifdef CONFIG_NETDEV_IFINDEX
+  conn->dev = netdev_findbyindex(canaddr->can_ifindex);
+#else
+  char netdev_name[5] = "can0";
+  netdev_name[3] += canaddr->can_ifindex;
+  conn->dev = netdev_findbyname((const char *)&netdev_name);
+#endif
 
   return OK;
 }
 
 /****************************************************************************
- * Name: netlink_getsockname
+ * Name: can_getsockname
  *
  * Description:
  *   The getsockname() function retrieves the locally-bound name of the
@@ -313,36 +390,18 @@ static int netlink_bind(FAR struct socket *psock,
  *
  ****************************************************************************/
 
-static int netlink_getsockname(FAR struct socket *psock,
-                               FAR struct sockaddr *addr,
-                               FAR socklen_t *addrlen)
+static int can_getsockname(FAR struct socket *psock,
+                           FAR struct sockaddr *addr,
+                           FAR socklen_t *addrlen)
 {
-  FAR struct sockaddr_nl *nladdr;
-  FAR struct netlink_conn_s *conn;
-
-  DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL &&
-              addrlen != NULL && *addrlen >= sizeof(struct sockaddr_nl));
-
-  conn = (FAR struct netlink_conn_s *)psock->s_conn;
-
-  /* Return the address information in the address structure */
-
-  nladdr = (FAR struct sockaddr_nl *)addr;
-  memset(nladdr, 0, sizeof(struct sockaddr_nl));
-
-  nladdr->nl_family = AF_NETLINK;
-  nladdr->nl_pid    = conn->pid;
-  nladdr->nl_groups = conn->groups;
-
-  *addrlen = sizeof(struct sockaddr_nl);
-  return OK;
+  return -EAFNOSUPPORT;
 }
 
 /****************************************************************************
- * Name: netlink_getpeername
+ * Name: can_getpeername
  *
  * Description:
- *   The netlink_getpeername() function retrieves the remote-connected name
+ *   The can_getpeername() function retrieves the remote-connected name
  *   of the specified packet socket, stores this address in the sockaddr
  *   structure pointed to by the 'addr' argument, and stores the length of
  *   this address in the object pointed to by the 'addrlen' argument.
@@ -366,33 +425,15 @@ static int netlink_getsockname(FAR struct socket *psock,
  *
  ****************************************************************************/
 
-static int netlink_getpeername(FAR struct socket *psock,
-                               FAR struct sockaddr *addr,
-                               FAR socklen_t *addrlen)
+static int can_getpeername(FAR struct socket *psock,
+                           FAR struct sockaddr *addr,
+                           FAR socklen_t *addrlen)
 {
-  FAR struct sockaddr_nl *nladdr;
-  FAR struct netlink_conn_s *conn;
-
-  DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL &&
-              addrlen != NULL && *addrlen >= sizeof(struct sockaddr_nl));
-
-  conn = (FAR struct netlink_conn_s *)psock->s_conn;
-
-  /* Return the address information in the address structure */
-
-  nladdr = (FAR struct sockaddr_nl *)addr;
-  memset(nladdr, 0, sizeof(struct sockaddr_nl));
-
-  nladdr->nl_family = AF_NETLINK;
-  nladdr->nl_pid    = conn->dst_pid;
-  nladdr->nl_groups = conn->dst_groups;
-
-  *addrlen = sizeof(struct sockaddr_nl);
-  return OK;
+  return -EOPNOTSUPP;
 }
 
 /****************************************************************************
- * Name: netlink_listen
+ * Name: can_listen
  *
  * Description:
  *   To accept connections, a socket is first created with psock_socket(), a
@@ -417,19 +458,20 @@ static int netlink_getpeername(FAR struct socket *psock,
  *
  ****************************************************************************/
 
-static int netlink_listen(FAR struct socket *psock, int backlog)
+static int can_listen(FAR struct socket *psock, int backlog)
 {
   return -EOPNOTSUPP;
 }
 
 /****************************************************************************
- * Name: netlink_connect
+ * Name: can_connect
  *
  * Description:
- *   Perform a netlink connection
+ *   Perform a can connection
  *
  * Input Parameters:
- *   psock   A reference to the structure of the socket to be connected
+ *   psock   A reference to the socket structure of the socket
+ *           to be connected
  *   addr    The address of the remote server to connect to
  *   addrlen Length of address buffer
  *
@@ -440,32 +482,18 @@ static int netlink_listen(FAR struct socket *psock, int backlog)
  *
  ****************************************************************************/
 
-static int netlink_connect(FAR struct socket *psock,
-                           FAR const struct sockaddr *addr,
-                           socklen_t addrlen)
+static int can_connect(FAR struct socket *psock,
+                       FAR const struct sockaddr *addr,
+                       socklen_t addrlen)
 {
-  FAR struct sockaddr_nl *nladdr;
-  FAR struct netlink_conn_s *conn;
-
-  DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL &&
-              addrlen >= sizeof(struct sockaddr_nl));
-
-  /* Save the address information in the connection structure */
-
-  nladdr = (FAR struct sockaddr_nl *)addr;
-  conn   = (FAR struct netlink_conn_s *)psock->s_conn;
-
-  conn->dst_pid    = nladdr->nl_pid;
-  conn->dst_groups = nladdr->nl_groups;
-
-  return OK;
+  return -EOPNOTSUPP;
 }
 
 /****************************************************************************
- * Name: netlink_accept
+ * Name: can_accept
  *
  * Description:
- *   The netlink_accept function is used with connection-based socket
+ *   The can_accept function is used with connection-based socket
  *   types (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first
  *   connection request on the queue of pending connections, creates a new
  *   connected socket with mostly the same properties as 'sockfd', and
@@ -484,7 +512,7 @@ static int netlink_connect(FAR struct socket *psock,
  *   actual length of the address returned.
  *
  *   If no pending connections are present on the queue, and the socket is
- *   not marked as non-blocking, accept blocks the caller until a
+ *   not marked as non-blocking, inet_accept blocks the caller until a
  *   connection is present. If the socket is marked non-blocking and no
  *   pending connections are present on the queue, inet_accept returns
  *   EAGAIN.
@@ -505,63 +533,14 @@ static int netlink_connect(FAR struct socket *psock,
  *
  ****************************************************************************/
 
-static int netlink_accept(FAR struct socket *psock,
-                          FAR struct sockaddr *addr, FAR socklen_t *addrlen,
-                          FAR struct socket *newsock)
+static int can_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
+                      FAR socklen_t *addrlen, FAR struct socket *newsock)
 {
   return -EOPNOTSUPP;
 }
 
 /****************************************************************************
- * Name: netlink_response_available
- *
- * Description:
- *   Handle a Netlink response available notification.
- *
- * Input Parameters:
- *   Standard work handler parameters
- *
- * Returned Value:
- *   None
- *
- ****************************************************************************/
-
-static void netlink_response_available(FAR void *arg)
-{
-  FAR struct netlink_conn_s *conn = arg;
-
-  DEBUGASSERT(conn != NULL);
-
-  /* The following should always be true ... but maybe not in some race
-   * condition?
-   */
-
-  sched_lock();
-  net_lock();
-
-  if (conn->pollsem != NULL && conn->pollevent != NULL)
-    {
-      /* Wake up the poll() with POLLIN */
-
-       *conn->pollevent |= POLLIN;
-       nxsem_post(conn->pollsem);
-    }
-  else
-    {
-      nwarn("WARNING: Missing references in connection.\n");
-    }
-
-  /* Allow another poll() */
-
-  conn->pollsem   = NULL;
-  conn->pollevent = NULL;
-
-  net_unlock();
-  sched_unlock();
-}
-
-/****************************************************************************
- * Name: netlink_poll
+ * Name: can_poll_local
  *
  * Description:
  *   The standard poll() operation redirects operations on socket descriptors
@@ -583,97 +562,124 @@ static void netlink_response_available(FAR void *arg)
  *
  ****************************************************************************/
 
-static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
-                        bool setup)
+static int can_poll_local(FAR struct socket *psock, FAR struct pollfd *fds,
+                          bool setup)
 {
-  FAR struct netlink_conn_s *conn;
+  FAR struct can_conn_s *conn;
+  FAR struct can_poll_s *info;
+  FAR struct devif_callback_s *cb;
   int ret = OK;
 
   DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
-  conn = (FAR struct netlink_conn_s *)psock->s_conn;
+  conn = (FAR struct can_conn_s *)psock->s_conn;
+  info = conn->pollinfo;
+
+  /* FIXME add NETDEV_DOWN support */
 
   /* Check if we are setting up or tearing down the poll */
 
   if (setup)
     {
-      /* If POLLOUT is selected, return immediately (maybe) */
+      net_lock();
+
+      info->dev = conn->dev;
+
+      cb = can_callback_alloc(info->dev, conn);
+      if (cb == NULL)
+        {
+          ret = -EBUSY;
+          goto errout_with_lock;
+        }
+
+      /* Initialize the poll info container */
 
-      pollevent_t revents = POLLOUT;
+      info->psock  = psock;
+      info->fds    = fds;
+      info->cb     = cb;
 
-      /* If POLLIN is selected and a response is available, return
-       * immediately (maybe).
+      /* Initialize the callback structure.  Save the reference to the info
+       * structure as callback private data so that it will be available
+       * during callback processing.
        */
 
-      net_lock();
-      if (netlink_check_response(conn))
+      cb->flags    = NETDEV_DOWN;
+      cb->priv     = (FAR void *)info;
+      cb->event    = can_poll_eventhandler;
+
+      if ((fds->events & POLLOUT) != 0)
+        {
+          cb->flags |= CAN_POLL;
+        }
+
+      if ((fds->events & POLLIN) != 0)
         {
-          revents |= POLLIN;
+          cb->flags |= CAN_NEWDATA;
         }
 
-      /* But return ONLY if POLLIN and/or POLLIN are included in the
-       * requested event set.
+      /* Save the reference in the poll info structure as fds private as well
+       * for use during poll teardown as well.
        */
 
-      revents &= fds->events;
-      if (revents != 0)
+      fds->priv = (FAR void *)info;
+
+      /* Check for read data availability now */
+
+      if (!IOB_QEMPTY(&conn->readahead))
         {
-          fds->revents = revents;
-          nxsem_post(fds->sem);
-          net_unlock();
-          return OK;
+          /* Normal data may be read without blocking. */
+
+          fds->revents |= (POLLRDNORM & fds->events);
         }
 
-      /* Set up to be notified when a response is available if POLLIN is
-       * requested.
-       */
+    #if 0
+      if (psock_udp_cansend(psock) >= 0)
+        {
+          /* Normal data may be sent without blocking (at least one byte). */
 
-      if ((fds->events & POLLIN) != 0)
+          fds->revents |= (POLLWRNORM & fds->events);
+        }
+    #endif
+
+      /* Check if any requested events are already in effect */
+
+      if (fds->revents != 0)
         {
-          /* Some limitations:  There can be only a single outstanding POLLIN
-           * on the Netlink connection.
-           */
-
-          if (conn->pollsem != NULL || conn->pollevent != NULL)
-            {
-              nerr("ERROR: Multiple polls() on socket not supported.\n");
-              net_unlock();
-              return -EBUSY;
-            }
-
-          /* Set up the notification */
-
-          conn->pollsem    = fds->sem;
-          conn->pollevent  = &fds->revents;
-
-          ret = netlink_notifier_setup(netlink_response_available,
-                                       conn, conn);
-          if (ret < 0)
-            {
-              nerr("ERROR: netlink_notifier_setup() failed: %d\n", ret);
-              conn->pollsem   = NULL;
-              conn->pollevent = NULL;
-            }
+          /* Yes.. then signal the poll logic */
+
+          nxsem_post(fds->sem);
         }
 
+errout_with_lock:
       net_unlock();
     }
   else
     {
-      /* Cancel any response notifications */
+      info = (FAR struct can_poll_s *)fds->priv;
 
-      ret = netlink_notifier_teardown(conn);
-      conn->pollsem   = NULL;
-      conn->pollevent = NULL;
+      if (info != NULL)
+        {
+          /* Cancel any response notifications */
+
+          can_callback_free(info->dev, conn, info->cb);
+
+          /* Release the poll/select data slot */
+
+          info->fds->priv = NULL;
+
+          /* Then free the poll info container */
+
+          info->psock = NULL;
+        }
     }
 
   return ret;
 }
 
 /****************************************************************************
- * Name: netlink_send
+ * Name: can_send
  *
  * Description:
- *   The netlink_send() call may be used only when the socket is in
+ *   The can_send() call may be used only when the socket is in
  *   a connected state  (so that the intended recipient is known).
  *
  * Input Parameters:
@@ -689,34 +695,33 @@ static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
  *
  ****************************************************************************/
 
-static ssize_t netlink_send(FAR struct socket *psock, FAR const void *buf,
-                            size_t len, int flags)
+static ssize_t can_send(FAR struct socket *psock, FAR const void *buf,
+                        size_t len, int flags)
 {
-  FAR struct netlink_conn_s *conn;
-  struct sockaddr_nl nladdr;
-
-  DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL);
-
-  /* Get the underlying connection structure */
+  ssize_t ret;
 
-  conn = (FAR struct netlink_conn_s *)psock->s_conn;
+  /* Only SOCK_RAW is supported */
 
-  /* Format the address */
+  if (psock->s_type == SOCK_RAW)
+    {
+      /* Raw packet send */
 
-  nladdr.nl_family = AF_NETLINK;
-  nladdr.nl_pad    = 0;
-  nladdr.nl_pid    = conn->dst_pid;
-  nladdr.nl_groups = conn->dst_groups;
+      ret = psock_can_send(psock, buf, len);
+    }
+  else
+    {
+      /* EDESTADDRREQ.  Signifies that the socket is not connection-mode and
+       * no peer address is set.
+       */
 
-  /* Then let sendto() perform the actual send operation */
+      ret = -EDESTADDRREQ;
+    }
 
-  return netlink_sendto(psock, buf, len, flags,
-                        (FAR const struct sockaddr *)&nladdr,
-                        sizeof(struct sockaddr_nl));
+  return ret;
 }
 
 /****************************************************************************
- * Name: netlink_sendto
+ * Name: can_sendto
  *
  * Description:
  *   If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET)
@@ -725,7 +730,8 @@ static ssize_t netlink_send(FAR struct socket *psock, FAR const void *buf,
  *   returned when the socket was not actually connected.
  *
  * Input Parameters:
- *   psock    A reference to the structure of the socket to be connected
+ *   psock    A reference to the socket structure of the socket
+ *            to be connected
  *   buf      Data to send
  *   len      Length of data to send
  *   flags    Send flags (ignored)
@@ -739,119 +745,60 @@ static ssize_t netlink_send(FAR struct socket *psock, FAR const void *buf,
  *
  ****************************************************************************/
 
-static ssize_t netlink_sendto(FAR struct socket *psock, FAR const void *buf,
-                              size_t len, int flags,
-                              FAR const struct sockaddr *to, socklen_t tolen)
+static ssize_t can_sendto(FAR struct socket *psock, FAR const void *buf,
+                          size_t len, int flags,
+                          FAR const struct sockaddr *to, socklen_t tolen)
 {
-  FAR struct netlink_conn_s *conn;
-  FAR struct nlmsghdr *nlmsg;
-  int ret;
-
-  DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL &&
-              to != NULL && tolen >= sizeof(struct sockaddr_nl));
-
-  conn = (FAR struct netlink_conn_s *)psock->s_conn;
-
-  /* Get a reference to the netlink message */
-
-  nlmsg = (FAR struct nlmsghdr *)buf;
-  DEBUGASSERT(nlmsg->nlmsg_len >= sizeof(struct nlmsghdr));
-
-  switch (conn->protocol)
-    {
-#ifdef CONFIG_NETLINK_ROUTE
-      case NETLINK_ROUTE:
-        ret = netlink_route_sendto(conn, nlmsg, len, flags,
-                                   (FAR struct sockaddr_nl *)to,
-                                   tolen);
-        break;
-#endif
-
-      default:
-       ret = -EOPNOTSUPP;
-       break;
-    }
-
-  return ret;
+  nerr("ERROR: sendto() not supported for raw packet sockets\n");
+  return -EAFNOSUPPORT;
 }
 
 /****************************************************************************
- * Name: netlink_recvfrom
+ * Name: can_sendmsg
  *
  * Description:
- *   recvfrom() receives messages from a socket, and may be used to receive
- *   data on a socket whether or not it is connection-oriented.
- *
- *   If from is not NULL, and the underlying protocol provides the source
- *   address, this source address is filled in. The argument 'fromlen'
- *   initialized to the size of the buffer associated with from, and modified
- *   on return to indicate the actual size of the address stored there.
+ *   The can_sendmsg() send a CAN frame to psock
  *
  * Input Parameters:
- *   psock    A pointer to a NuttX-specific, internal socket structure
- *   buf      Buffer to receive data
- *   len      Length of buffer
- *   flags    Receive flags (ignored)
- *   from     Address of source (may be NULL)
- *   fromlen  The length of the address structure
+ *   psock - An instance of the internal socket structure.
+ *   msg   - CAN frame and optional CMSG
+ *   flags - Send flags (ignored)
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  On  error, a negated
+ *   errno value is returned (see send() for the list of appropriate error
+ *   values.
  *
  ****************************************************************************/
-
-static ssize_t netlink_recvfrom(FAR struct socket *psock, FAR void *buf,
-                                size_t len, int flags,
-                                FAR struct sockaddr *from,
-                                FAR socklen_t *fromlen)
+#ifdef CONFIG_NET_CMSG
+static ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+                    int flags)
 {
-  FAR struct netlink_response_s *entry;
-
-  DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL);
-  DEBUGASSERT(from == NULL ||
-              (fromlen != NULL && *fromlen >= sizeof(struct sockaddr_nl)));
+  ssize_t ret;
 
-  /* Find the response to this message.  The return value */
+  /* Only SOCK_RAW is supported */
 
-  entry = netlink_tryget_response(psock->s_conn);
-  if (entry == NULL)
+  if (psock->s_type == SOCK_RAW)
     {
-      /* No response is variable, but presumably, one is expected.  Check
-       * if the socket has been configured for non-blocking operation.
-       */
+      /* Raw packet send */
 
-      if (_SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0)
-        {
-          return -EAGAIN;
-        }
-
-      /* Wait for the response.  This should always succeed. */
-
-      entry = netlink_get_response(psock->s_conn);
-      DEBUGASSERT(entry != NULL);
-      if (entry == NULL)
-        {
-          return -EPIPE;
-        }
+      ret = psock_can_sendmsg(psock, msg);
     }
-
-  if (len > entry->msg.nlmsg_len)
+  else
     {
-      len = entry->msg.nlmsg_len;
-    }
-
-  /* Copy the payload to the user buffer */
-
-  memcpy(buf, &entry->msg, len);
-  kmm_free(entry);
+      /* EDESTADDRREQ.  Signifies that the socket is not connection-mode and
+       * no peer address is set.
+       */
 
-  if (from != NULL)
-    {
-      netlink_getpeername(psock, from, fromlen);
+      ret = -EDESTADDRREQ;
     }
 
-  return len;
+  return ret;
 }
+#endif
 
 /****************************************************************************
- * Name: netlink_close
+ * Name: can_close
  *
  * Description:
  *   Performs the close operation on a NetLink socket instance
@@ -866,12 +813,12 @@ static ssize_t netlink_recvfrom(FAR struct socket *psock, FAR void *buf,
  *
  ****************************************************************************/
 
-static int netlink_close(FAR struct socket *psock)
+static int can_close(FAR struct socket *psock)
 {
-  FAR struct netlink_conn_s *conn = psock->s_conn;
+  FAR struct can_conn_s *conn = psock->s_conn;
   int ret = OK;
 
-  /* Perform some pre-close operations for the NETLINK socket type. */
+  /* Perform some pre-close operations for the CAN socket type. */
 
   /* Is this the last reference to the connection structure (there
    * could be more if the socket was dup'ed).
@@ -879,16 +826,20 @@ static int netlink_close(FAR struct socket *psock)
 
   if (conn->crefs <= 1)
     {
+      /* Yes... inform user-space daemon of socket close. */
+
+#warning Missing logic
+
       /* Free the connection structure */
 
       conn->crefs = 0;
-      netlink_free(psock->s_conn);
+      can_free(psock->s_conn);
 
       if (ret < 0)
         {
           /* Return with error code, but free resources. */
 
-          nerr("ERROR: netlink_close failed: %d\n", ret);
+          nerr("ERROR: can_close failed: %d\n", ret);
           return ret;
         }
     }
@@ -902,4 +853,4 @@ static int netlink_close(FAR struct socket *psock)
   return ret;
 }
 
-#endif /* CONFIG_NET_NETLINK */
+#endif /* CONFIG_NET_CAN */
diff --git a/net/devif/Make.defs b/net/devif/Make.defs
index 714a0ce..492c7d8 100644
--- a/net/devif/Make.defs
+++ b/net/devif/Make.defs
@@ -66,6 +66,10 @@ ifeq ($(CONFIG_NET_PKT),y)
 NET_CSRCS += devif_pktsend.c
 endif
 
+ifeq ($(CONFIG_NET_CAN),y)
+NET_CSRCS += devif_cansend.c
+endif
+
 # Include network device interface build support
 
 DEPPATH += --dep-path devif
diff --git a/net/devif/devif.h b/net/devif/devif.h
index cbe1a00..1a95011 100644
--- a/net/devif/devif.h
+++ b/net/devif/devif.h
@@ -68,31 +68,32 @@
  *
  *   TCP_ACKDATA      IN: Signifies that the outstanding data was ACKed and
  *                        the socket layer should send out new data instead
- *                        of retransmitting the last data (TCP only)
+ *                        of retransmitting the last data. (TCP only)
  *                   OUT: Input state must be preserved on output.
  *
  *   TCP_NEWDATA      IN: Set to indicate that the peer has sent us new data.
- *   UDP_NEWDATA     OUT: Cleared (only) by the socket layer logic to indicate
- *   ICMP_NEWDATA         that the new data was consumed, suppressing further
- *   ICMPv6_NEWDATA       attempts to process the new data.
- *   PKT_NEWDATA
+ *   UDP_NEWDATA     OUT: Cleared (only) by the socket layer logic to
+ *   ICMP_NEWDATA         indicate that the new data was consumed,
+ *   ICMPv6_NEWDATA       suppressing further attempts to process the new
+ *   PKT_NEWDATA          data.
  *   BLUETOOTH_NEWDATA
  *   IEEE802154_NEWDATA
  *
  *   TCP_SNDACK       IN: Not used; always zero
- *                   OUT: Set by the socket layer if the new data was consumed
- *                        and an ACK should be sent in the response. (TCP only)
+ *                   OUT: Set by the socket layer if the new data was
+ *                        consumed and an ACK should be sent in the response.
+ *                        (TCP only)
  *
  *   TCP_REXMIT       IN: Tells the socket layer to retransmit the data that
  *                        was last sent. (TCP only)
  *                   OUT: Not used
  *
- *   TCP_POLL        IN:  Used for polling the socket layer.  This is provided
- *   UDP_POLL             periodically from the drivers to support (1) timed
- *   PKT_POLL             operations, and (2) to check if the socket layer has
- *   BLUETOOTH_POLL       data that it wants to send.  These are socket oriented
- *   IEEE802154_POLL      callbacks where the context depends on the specific
- *                        set
+ *   TCP_POLL        IN:  Used for polling the socket layer.  This is
+ *   UDP_POLL             provided periodically from the drivers to support
+ *   PKT_POLL             (1) timed operations, and (2) to check if the
+ *   BLUETOOTH_POLL       socket layer has data that it wants to send.
+ *   IEEE802154_POLL      These are socket oriented callbacks where the
+ *                        context depends on the specific set.
  *                   OUT: Not used
  *
  *   TCP_BACKLOG      IN: There is a new connection in the backlog list set
@@ -104,14 +105,15 @@
  *                   OUT: The socket layer signals that it wants to close the
  *                        connection. (TCP only)
  *
- *   TCP_ABORT        IN: The remote host has aborted the connection, thus the
- *                        connection has gone away. (TCP only)
+ *   TCP_ABORT        IN: The remote host has aborted the connection, thus
+ *                        the connection has gone away. (TCP only)
  *                   OUT: The socket layer signals that it wants to abort the
  *                        connection. (TCP only)
  *
- *   TCP_CONNECTED    IN: We have got a connection from a remote host and have
- *                        set up a new connection for it, or an active connection
- *                        has been successfully established. (TCP only)
+ *   TCP_CONNECTED    IN: We have got a connection from a remote host and
+ *                        have set up a new connection for it, or an active
+ *                        connection has been successfully established.
+ *                        (TCP only)
  *                   OUT: Not used
  *
  *   TCP_TIMEDOUT     IN: The connection has been aborted due to too many
@@ -121,37 +123,38 @@
  * Device Specific Events:  These are events that may be notified through
  * callback lists residing in the network device structure.
  *
- *   ARP_POLL         IN: Used for polling the socket layer.  This is provided
- *                        periodically from the drivers to support (1) timed
- *                        operations, and (2) to check if the ARP layer needs
- *                        to send an ARP request.  This is a device oriented
- *                        event, not associated with a socket.
+ *   ARP_POLL         IN: Used for polling the socket layer.  This is
+ *                        provided periodically from the drivers to support
+ *                        (1) timed operations, and (2) to check if the ARP
+ *                        layer needs to send an ARP request.  This is a
+ *                        device oriented event, not associated with a
+ *                        socket.
  *                   OUT: Not used
  *
- *   ICMP_POLL        IN: Used for polling the socket layer.  This is provided
- *                        periodically from the drivers to support (1) timed
- *                        operations, and (2) to check if the ICMP layer needs
- *                        to send an ARP request.  This is a device oriented
- *                        event, not associated with a socket.  This differs
- *                        from ICMPv6_POLL only in that the appdata pointer
- *                        is set differently
+ *   ICMP_POLL        IN: Used for polling the socket layer.  This is
+ *                        provided periodically from the drivers to support
+ *                        (1) timed operations, and (2) to check if the ICMP
+ *                        layer needs to send an ARP request.  This is a
+ *                        device oriented event, not associated with a
+ *                        socket.  This differs from ICMPv6_POLL only in that
+ *                        the appdata pointer is set differently.
  *                   OUT: Not used
  *
- *   ICMPv6_POLL      IN: Used for polling the socket layer.  This is provided
- *                        periodically from the drivers to support (1) timed
- *                        operations, and (2) to check if the ICMP layer needs
- *                        to send an ARP request.  This is a device oriented
- *                        event, not associated with a socket.  This differs
- *                        from ICMP_POLL only in that the appdata pointer
- *                        is set differently
+ *   ICMPv6_POLL      IN: Used for polling the socket layer.  This is
+ *                        provided periodically from the drivers to support
+ *                        (1) timed operations, and (2) to check if the ICMP
+ *                        layer needs to send an ARP request.  This is a
+ *                        device oriented event, not associated with a
+ *                        socket.  This differs from ICMP_POLL only in that
+ *                        the appdata pointer is set differently.
  *                   OUT: Not used
  *
  *   IPFWD_POLL       IN: Used for polling for forwarded packets layer.  This
- *                        is provided periodically from the drivers to support
- *                        to check if there is a packet waiting to be forward
- *                        on the device.  This is a device oriented event,
- *                        not associated with a socket.  The appdata pointer
- *                        The appdata pointer is not used in this case.
+ *                        is provided periodically from the drivers to
+ *                        support to check if there is a packet waiting to be
+ *                        forward on the device.  This is a device oriented
+ *                        event, not associated with a socket.  The appdata
+ *                        pointer is not used in this case.
  *                   OUT: Not used
  *
  *   NETDEV_DOWN:     IN: The network device has been taken down.
@@ -168,6 +171,7 @@
 #define BLUETOOTH_NEWDATA  TCP_NEWDATA
 #define IEEE802154_NEWDATA TCP_NEWDATA
 #define PKT_NEWDATA        TCP_NEWDATA
+#define CAN_NEWDATA        TCP_NEWDATA
 #define WPAN_NEWDATA       TCP_NEWDATA
 #define IPFWD_NEWDATA      TCP_NEWDATA
 #define TCP_SNDACK         (1 << 2)
@@ -175,6 +179,7 @@
 #define TCP_POLL           (1 << 4)
 #define UDP_POLL           TCP_POLL
 #define PKT_POLL           TCP_POLL
+#define CAN_POLL           TCP_POLL
 #define BLUETOOTH_POLL     TCP_POLL
 #define IEEE802154_POLL    TCP_POLL
 #define WPAN_POLL          TCP_POLL
@@ -492,11 +497,32 @@ void devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *buf,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_NET_PKT
+#if defined(CONFIG_NET_PKT)
 void devif_pkt_send(FAR struct net_driver_s *dev, FAR const void *buf,
                     unsigned int len);
 #endif
 
+/****************************************************************************
+ * Name: devif_can_send
+ *
+ * Description:
+ *   Called from socket logic in order to send a raw packet in response to
+ *   an xmit or poll request from the network interface driver.
+ *
+ *   This is almost identical to calling devif_send() except that the data to
+ *   be sent is copied into dev->d_buf (vs. dev->d_appdata), since there is
+ *   no header on the data.
+ *
+ * Assumptions:
+ *   This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_CAN)
+void devif_can_send(FAR struct net_driver_s *dev, FAR const void *buf,
+                    unsigned int len);
+#endif
+
 #undef EXTERN
 #ifdef __cplusplus
 }
diff --git a/net/local/local_sendpacket.c b/net/devif/devif_cansend.c
similarity index 55%
copy from net/local/local_sendpacket.c
copy to net/devif/devif_cansend.c
index 68dfac6..43570f2 100644
--- a/net/local/local_sendpacket.c
+++ b/net/devif/devif_cansend.c
@@ -1,7 +1,7 @@
 /****************************************************************************
- * net/local/local_sendpacket.c
+ * net/devif/devif_cansend.c
  *
- *   Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved.
+ *   Copyright (C) 2014 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <gn...@nuttx.org>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,131 +39,75 @@
 
 #include <nuttx/config.h>
 
-#include <sys/types.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <errno.h>
+#include <string.h>
 #include <assert.h>
 #include <debug.h>
 
-#include <nuttx/fs/fs.h>
+#include <nuttx/net/netdev.h>
 
-#include "local/local.h"
-
-#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL)
+#if defined(CONFIG_NET_CAN)
 
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
-#define LOCAL_PREAMBLE_SIZE 8
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
 
 /****************************************************************************
- * Private Data
+ * Private Function Prototypes
  ****************************************************************************/
 
-static const uint8_t g_preamble[LOCAL_PREAMBLE_SIZE] =
-{
-  LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE,
-  LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_END_BYTE
-};
+/****************************************************************************
+ * Public Constant Data
+ ****************************************************************************/
 
 /****************************************************************************
- * Private Functions
+ * Public Data
  ****************************************************************************/
 
 /****************************************************************************
- * Name: local_fifo_write
- *
- * Description:
- *   Write a data on the write-only FIFO.
- *
- * Input Parameters:
- *   filep    File structure of write-only FIFO.
- *   buf      Data to send
- *   len      Length of data to send
- *
- * Returned Value:
- *   Zero is returned on success; a negated errno value is returned on any
- *   failure.
- *
+ * Private Constant Data
  ****************************************************************************/
 
-static int local_fifo_write(FAR struct file *filep, FAR const uint8_t *buf,
-                            size_t len)
-{
-  ssize_t nwritten;
-
-  while (len > 0)
-    {
-      nwritten = file_write(filep, buf, len);
-      if (nwritten < 0)
-        {
-          if (nwritten != -EINTR)
-            {
-              nerr("ERROR: nx_write failed: %d\n", nwritten);
-              return (int)nwritten;
-            }
-
-          ninfo("Ignoring signal\n");
-        }
-      else
-        {
-          DEBUGASSERT(nwritten > 0 && nwritten <= len);
-          len -= nwritten;
-          buf += nwritten;
-        }
-    }
-
-  return OK;
-}
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
 
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: local_send_packet
+ * Name: devif_can_send
  *
  * Description:
- *   Send a packet on the write-only FIFO.
+ *   Called from socket logic in order to send a can packet in response to
+ *   an xmit or poll request from the network interface driver.
  *
- * Input Parameters:
- *   filep    File structure of write-only FIFO.
- *   buf      Data to send
- *   len      Length of data to send
+ *   This is almost identical to calling devif_send() except that the data to
+ *   be sent is copied into dev->d_buf (vs. dev->d_appdata), since there is
+ *   no header on the data.
  *
- * Returned Value:
- *   Zero is returned on success; a negated errno value is returned on any
- *   failure.
+ * Assumptions:
+ *   Called with the network locked.
  *
  ****************************************************************************/
 
-int local_send_packet(FAR struct file *filep, FAR const uint8_t *buf,
-                      size_t len)
+void devif_can_send(FAR struct net_driver_s *dev, FAR const void *buf,
+                    unsigned int len)
 {
-  uint16_t len16;
-  int ret;
-
-  /* Send the packet preamble */
+  DEBUGASSERT(dev && len > 0 && len < NETDEV_PKTSIZE(dev));
 
-  ret = local_fifo_write(filep, g_preamble, LOCAL_PREAMBLE_SIZE);
-  if (ret == OK)
-    {
-      /* Send the packet length */
+  /* Copy the data into the device packet buffer */
 
-      len16 = len;
-      ret = local_fifo_write(filep, (FAR const uint8_t *)&len16,
-                             sizeof(uint16_t));
-      if (ret == OK)
-        {
-          /* Send the packet data */
+  memcpy(dev->d_buf, buf, len);
 
-          ret = local_fifo_write(filep, buf, len);
-        }
-    }
+  /* Set the number of bytes to send */
 
-  return ret;
+  dev->d_len    = len;
+  dev->d_sndlen = len;
 }
 
-#endif /* CONFIG_NET && CONFIG_NET_LOCAL */
+#endif /* CONFIG_NET_CAN */
diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c
index 7c4fd04..ffffed4 100644
--- a/net/devif/devif_poll.c
+++ b/net/devif/devif_poll.c
@@ -50,6 +50,7 @@
 
 #include "devif/devif.h"
 #include "arp/arp.h"
+#include "can/can.h"
 #include "tcp/tcp.h"
 #include "udp/udp.h"
 #include "pkt/pkt.h"
@@ -233,6 +234,44 @@ static int devif_poll_pkt_connections(FAR struct net_driver_s *dev,
 #endif /* CONFIG_NET_PKT */
 
 /****************************************************************************
+ * Name: devif_poll_pkt_connections
+ *
+ * Description:
+ *   Poll all packet connections for available packets to send.
+ *
+ * Assumptions:
+ *   This function is called from the MAC device driver with the network
+ *   locked.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CAN
+static int devif_poll_can_connections(FAR struct net_driver_s *dev,
+                                      devif_poll_callback_t callback)
+{
+  FAR struct can_conn_s *can_conn = NULL;
+  int bstop = 0;
+
+  /* Traverse all of the allocated packet connections and
+   * perform the poll action
+   */
+
+  while (!bstop && (can_conn = can_nextconn(can_conn)))
+    {
+      /* Perform the packet TX poll */
+
+      can_poll(dev, can_conn);
+
+      /* Call back into the driver */
+
+      bstop = callback(dev);
+    }
+
+  return bstop;
+}
+#endif /* CONFIG_NET_PKT */
+
+/****************************************************************************
  * Name: devif_poll_bluetooth_connections
  *
  * Description:
@@ -646,6 +685,15 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback)
 
   if (!bstop)
 #endif
+#ifdef CONFIG_NET_CAN
+    {
+      /* Check for pending packet socket transfer */
+
+      bstop = devif_poll_can_connections(dev, callback);
+    }
+
+  if (!bstop)
+#endif
 #ifdef CONFIG_NET_BLUETOOTH
     {
       /* Check for pending PF_BLUETOOTH socket transfer */
diff --git a/net/icmp/icmp_sockif.c b/net/icmp/icmp_sockif.c
index 983eb71..2b1e179 100644
--- a/net/icmp/icmp_sockif.c
+++ b/net/icmp/icmp_sockif.c
@@ -102,6 +102,10 @@ const struct sock_intf_s g_icmp_sockif =
   NULL,             /* si_sendfile */
 #endif
   icmp_recvfrom,    /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+  NULL,             /* si_recvmsg */
+  NULL,             /* si_sendmsg */
+#endif
   icmp_close        /* si_close */
 };
 
@@ -280,7 +284,8 @@ static int icmp_connect(FAR struct socket *psock,
  * Input Parameters:
  *   psock    Reference to the listening socket structure
  *   addr     Receives the address of the connecting client
- *   addrlen  Input: allocated size of 'addr', Return: returned size of 'addr'
+ *   addrlen  Input: allocated size of 'addr',
+ *            Return: returned size of 'addr'
  *   newsock  Location to return the accepted socket information.
  *
  * Returned Value:
@@ -318,7 +323,8 @@ static int icmp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
  *
  ****************************************************************************/
 
-static int icmp_bind(FAR struct socket *psock, FAR const struct sockaddr *addr,
+static int icmp_bind(FAR struct socket *psock,
+                     FAR const struct sockaddr *addr,
                      socklen_t addrlen)
 {
   /* An ICMP socket cannot be bound to a local address */
@@ -364,10 +370,10 @@ static int icmp_getsockname(FAR struct socket *psock,
  * Name: icmp_getpeername
  *
  * Description:
- *   The icmp_getpeername() function retrieves the remote-connected name of the
- *   specified packet socket, stores this address in the sockaddr structure
- *   pointed to by the 'addr' argument, and stores the length of this
- *   address in the object pointed to by the 'addrlen' argument.
+ *   The icmp_getpeername() function retrieves the remote-connected name of
+ *   the specified packet socket, stores this address in the sockaddr
+ *   structure pointed to by the 'addr' argument, and stores the length of
+ *   this address in the object pointed to by the 'addrlen' argument.
  *
  *   If the actual length of the address is greater than the length of the
  *   supplied sockaddr structure, the stored address will be truncated.
diff --git a/net/icmpv6/icmpv6_sockif.c b/net/icmpv6/icmpv6_sockif.c
index c99d184..3dbb5c8 100644
--- a/net/icmpv6/icmpv6_sockif.c
+++ b/net/icmpv6/icmpv6_sockif.c
@@ -102,6 +102,10 @@ const struct sock_intf_s g_icmpv6_sockif =
   NULL,               /* si_sendfile */
 #endif
   icmpv6_recvfrom,    /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+  NULL,               /* si_recvmsg */
+  NULL,               /* si_sendmsg */
+#endif
   icmpv6_close        /* si_close */
 };
 
@@ -280,7 +284,8 @@ static int icmpv6_connect(FAR struct socket *psock,
  * Input Parameters:
  *   psock    Reference to the listening socket structure
  *   addr     Receives the address of the connecting client
- *   addrlen  Input: allocated size of 'addr', Return: returned size of 'addr'
+ *   addrlen  Input: allocated size of 'addr',
+ *            Return: returned size of 'addr'
  *   newsock  Location to return the accepted socket information.
  *
  * Returned Value:
@@ -318,8 +323,9 @@ static int icmpv6_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
  *
  ****************************************************************************/
 
-static int icmpv6_bind(FAR struct socket *psock, FAR const struct sockaddr *addr,
-                     socklen_t addrlen)
+static int icmpv6_bind(FAR struct socket *psock,
+                       FAR const struct sockaddr *addr,
+                       socklen_t addrlen)
 {
   /* An ICMPv6 socket cannot be bound to a local address */
 
@@ -330,10 +336,10 @@ static int icmpv6_bind(FAR struct socket *psock, FAR const struct sockaddr *addr
  * Name: icmpv6_getsockname
  *
  * Description:
- *   The icmpv6_getsockname() function retrieves the locally-bound name of the
- *   specified packet socket, stores this address in the sockaddr structure
- *   pointed to by the 'addr' argument, and stores the length of this
- *   address in the object pointed to by the 'addrlen' argument.
+ *   The icmpv6_getsockname() function retrieves the locally-bound name of
+ *   the specified packet socket, stores this address in the sockaddr
+ *   structure pointed to by the 'addr' argument, and stores the length of
+ *   this address in the object pointed to by the 'addrlen' argument.
  *
  *   If the actual length of the address is greater than the length of the
  *   supplied sockaddr structure, the stored address will be truncated.
@@ -364,10 +370,10 @@ static int icmpv6_getsockname(FAR struct socket *psock,
  * Name: icmpv6_getpeername
  *
  * Description:
- *   The icmpv6_getpeername() function retrieves the remote-connected name of the
- *   specified packet socket, stores this address in the sockaddr structure
- *   pointed to by the 'addr' argument, and stores the length of this
- *   address in the object pointed to by the 'addrlen' argument.
+ *   The icmpv6_getpeername() function retrieves the remote-connected name of
+ *   the specified packet socket, stores this address in the sockaddr
+ *   structure pointed to by the 'addr' argument, and stores the length of
+ *   this address in the object pointed to by the 'addrlen' argument.
  *
  *   If the actual length of the address is greater than the length of the
  *   supplied sockaddr structure, the stored address will be truncated.
@@ -483,8 +489,8 @@ static int icmpv6_netpoll(FAR struct socket *psock, FAR struct pollfd *fds,
 static ssize_t icmpv6_send(FAR struct socket *psock, FAR const void *buf,
                         size_t len, int flags)
 {
-  /* ICMPv6 sockets cannot be bound and, hence, cannot support any connection-
-   * oriented data transfer.
+  /* ICMPv6 sockets cannot be bound and, hence, cannot support any
+   * connection-oriented data transfer.
    */
 
   return -EDESTADDRREQ;
diff --git a/net/ieee802154/ieee802154_sockif.c b/net/ieee802154/ieee802154_sockif.c
index 216264a..eb5d6e5 100644
--- a/net/ieee802154/ieee802154_sockif.c
+++ b/net/ieee802154/ieee802154_sockif.c
@@ -107,6 +107,10 @@ const struct sock_intf_s g_ieee802154_sockif =
   NULL,                   /* si_sendfile */
 #endif
   ieee802154_recvfrom,    /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+  NULL,                   /* si_recvmsg */
+  NULL,                   /* si_sendmsg */
+#endif
   ieee802154_close        /* si_close */
 };
 
@@ -241,10 +245,10 @@ static void ieee802154_addref(FAR struct socket *psock)
  * Name: ieee802154_connect
  *
  * Description:
- *   ieee802154_connect() connects the local socket referred to by the structure
- *   'psock' to the address specified by 'addr'. The addrlen argument
- *   specifies the size of 'addr'.  The format of the address in 'addr' is
- *   determined by the address space of the socket 'psock'.
+ *   ieee802154_connect() connects the local socket referred to by the
+ *   structure 'psock' to the address specified by 'addr'. The addrlen
+ *   argument specifies the size of 'addr'.  The format of the address in
+ *   'addr' is determined by the address space of the socket 'psock'.
  *
  *   If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address
  *   to which datagrams are sent by default, and the only address from which
@@ -307,8 +311,8 @@ static int ieee802154_connect(FAR struct socket *psock,
  * Name: ieee802154_accept
  *
  * Description:
- *   The ieee802154_accept function is used with connection-based socket types
- *   (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first
+ *   The ieee802154_accept function is used with connection-based socket
+ *   types (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first
  *   connection request on the queue of pending connections, creates a new
  *   connected socket with mostly the same properties as 'sockfd', and
  *   allocates a new socket descriptor for the socket, which is returned. The
@@ -334,7 +338,8 @@ static int ieee802154_connect(FAR struct socket *psock,
  * Input Parameters:
  *   psock    Reference to the listening socket structure
  *   addr     Receives the address of the connecting client
- *   addrlen  Input: allocated size of 'addr', Return: returned size of 'addr'
+ *   addrlen  Input: allocated size of 'addr',
+ *            Return: returned size of 'addr'
  *   newsock  Location to return the accepted socket information.
  *
  * Returned Value:
@@ -376,7 +381,8 @@ static int ieee802154_accept(FAR struct socket *psock,
  ****************************************************************************/
 
 static int ieee802154_bind(FAR struct socket *psock,
-                           FAR const struct sockaddr *addr, socklen_t addrlen)
+                           FAR const struct sockaddr *addr,
+                           socklen_t addrlen)
 {
   FAR const struct sockaddr_ieee802154_s *iaddr;
   FAR struct radio_driver_s *radio;
@@ -446,10 +452,10 @@ static int ieee802154_bind(FAR struct socket *psock,
  * Name: ieee802154_getsockname
  *
  * Description:
- *   The ieee802154_getsockname() function retrieves the locally-bound name of the
- *   specified packet socket, stores this address in the sockaddr structure
- *   pointed to by the 'addr' argument, and stores the length of this
- *   address in the object pointed to by the 'addrlen' argument.
+ *   The ieee802154_getsockname() function retrieves the locally-bound name
+ *   of the specified packet socket, stores this address in the sockaddr
+ *   structure pointed to by the 'addr' argument, and stores the length of
+ *   this address in the object pointed to by the 'addrlen' argument.
  *
  *   If the actual length of the address is greater than the length of the
  *   supplied sockaddr structure, the stored address will be truncated.
@@ -508,10 +514,10 @@ static int ieee802154_getsockname(FAR struct socket *psock,
  * Name: ieee802154_getpeername
  *
  * Description:
- *   The ieee802154_getpeername() function retrieves the remote-connectd name of the
- *   specified packet socket, stores this address in the sockaddr structure
- *   pointed to by the 'addr' argument, and stores the length of this
- *   address in the object pointed to by the 'addrlen' argument.
+ *   The ieee802154_getpeername() function retrieves the remote-connectd name
+ *   of the specified packet socket, stores this address in the sockaddr
+ *   structure pointed to by the 'addr' argument, and stores the length of
+ *   this address in the object pointed to by the 'addrlen' argument.
  *
  *   If the actual length of the address is greater than the length of the
  *   supplied sockaddr structure, the stored address will be truncated.
@@ -676,7 +682,8 @@ static ssize_t ieee802154_send(FAR struct socket *psock, FAR const void *buf,
 
           ret = psock_ieee802154_sendto(psock, buf, len, flags,
                                         (FAR const struct sockaddr *)&to,
-                                        sizeof(struct sockaddr_ieee802154_s));
+                                        sizeof(
+                                          struct sockaddr_ieee802154_s));
         }
     }
   else
@@ -713,9 +720,11 @@ static ssize_t ieee802154_send(FAR struct socket *psock, FAR const void *buf,
  *
  ****************************************************************************/
 
-static ssize_t ieee802154_sendto(FAR struct socket *psock, FAR const void *buf,
+static ssize_t ieee802154_sendto(FAR struct socket *psock,
+                                 FAR const void *buf,
                                  size_t len, int flags,
-                                 FAR const struct sockaddr *to, socklen_t tolen)
+                                 FAR const struct sockaddr *to,
+                                 socklen_t tolen)
 {
   ssize_t ret;
 
diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c
index 9456510..488f2d1 100644
--- a/net/inet/inet_sockif.c
+++ b/net/inet/inet_sockif.c
@@ -117,6 +117,10 @@ static const struct sock_intf_s g_inet_sockif =
   inet_sendfile,    /* si_sendfile */
 #endif
   inet_recvfrom,    /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+  NULL,             /* si_recvmsg */
+  NULL,             /* si_sendmsg */
+#endif
   inet_close        /* si_close */
 };
 
diff --git a/net/local/local_sendpacket.c b/net/local/local_sendpacket.c
index 68dfac6..644dd31 100644
--- a/net/local/local_sendpacket.c
+++ b/net/local/local_sendpacket.c
@@ -47,6 +47,7 @@
 #include <debug.h>
 
 #include <nuttx/fs/fs.h>
+#include "devif/devif.h"
 
 #include "local/local.h"
 
diff --git a/net/local/local_sockif.c b/net/local/local_sockif.c
index f2bbcb1..c4f7531 100644
--- a/net/local/local_sockif.c
+++ b/net/local/local_sockif.c
@@ -110,6 +110,10 @@ const struct sock_intf_s g_local_sockif =
   NULL,              /* si_sendfile */
 #endif
   local_recvfrom,    /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+  NULL,              /* si_recvmsg */
+  NULL,              /* si_sendmsg */
+#endif
   local_close        /* si_close */
 };
 
@@ -161,7 +165,8 @@ static int local_sockif_alloc(FAR struct socket *psock)
  *   specific socket fields.
  *
  * Input Parameters:
- *   psock    A pointer to a user allocated socket structure to be initialized.
+ *   psock    A pointer to a user allocated socket structure
+ *            to be initialized.
  *   protocol (see sys/socket.h)
  *
  * Returned Value:
@@ -590,7 +595,8 @@ static int local_connect(FAR struct socket *psock,
  * Input Parameters:
  *   psock    Reference to the listening socket structure
  *   addr     Receives the address of the connecting client
- *   addrlen  Input: allocated size of 'addr', Return: returned size of 'addr'
+ *   addrlen  Input: allocated size of 'addr',
+ *            Return: returned size of 'addr'
  *   newsock  Location to return the accepted socket information.
  *
  * Returned Value:
@@ -717,7 +723,7 @@ static ssize_t local_send(FAR struct socket *psock, FAR const void *buf,
  * Name: local_sendto
  *
  * Description:
- *   Implements the sendto() operation for the case of the local, Unix socket.
+ *   Implements the sendto() operation for the case of the local Unix socket.
  *
  * Input Parameters:
  *   psock    A pointer to a NuttX-specific, internal socket structure
diff --git a/net/net_initialize.c b/net/net_initialize.c
index eb82777..bedc4e3 100644
--- a/net/net_initialize.c
+++ b/net/net_initialize.c
@@ -59,6 +59,7 @@
 #include "bluetooth/bluetooth.h"
 #include "ieee802154/ieee802154.h"
 #include "local/local.h"
+#include "can/can.h"
 #include "netlink/netlink.h"
 #include "igmp/igmp.h"
 #include "route/route.h"
@@ -158,6 +159,12 @@ void net_initialize(void)
   local_initialize();
 #endif
 
+#ifdef CONFIG_NET_CAN
+  /* Initialize SocketCAN support */
+
+  can_initialize();
+#endif
+
 #ifdef CONFIG_NET_NETLINK
   /* Initialize the Netlink IPC support */
 
diff --git a/net/netdev/Kconfig b/net/netdev/Kconfig
index 2b3f905..ce51c1f 100644
--- a/net/netdev/Kconfig
+++ b/net/netdev/Kconfig
@@ -16,6 +16,14 @@ config NETDEV_PHY_IOCTL
 	---help---
 		Enable support for ioctl() commands to access PHY registers
 
+config NETDEV_CAN_BITRATE_IOCTL
+	bool "Enable CAN bitrate ioctl()"
+	default n
+	select NETDEV_IOCTL
+	depends on NET_CAN
+	---help---
+		Enable support for ioctl() commands to change CAN bitrate
+		
 config NETDEV_WIRELESS_IOCTL
 	bool "Enable Wireless ioctl()"
 	default n
diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c
index 04c9b51..c169503 100644
--- a/net/netdev/netdev_ioctl.c
+++ b/net/netdev/netdev_ioctl.c
@@ -1088,6 +1088,54 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd,
             }
         }
         break;
+#endif  
+
+#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL)
+      case SIOCGCANBITRATE:  /* Get bitrate from a CAN controller */
+      case SIOCSCANBITRATE:  /* Set bitrate of a CAN controller */
+        {
+          dev = netdev_ifr_dev(req);
+          if (dev && dev->d_ioctl)
+            {
+              struct can_ioctl_data_s *can_bitrate_data =
+                            &req->ifr_ifru.ifru_can_data;
+              ret = dev->d_ioctl(dev, cmd,
+                            (unsigned long)(uintptr_t)can_bitrate_data);
+            }
+        }
+        break;
+#endif
+
+#ifdef CONFIG_NETDEV_IFINDEX
+      case SIOCGIFNAME:  /* Get interface name */
+        {
+          struct net_driver_s *dev = netdev_findbyindex(req->ifr_ifindex);
+          if (dev != NULL)
+            {
+              strncpy(req->ifr_name, dev->d_ifname, IFNAMSIZ);
+              ret = OK;
+            }
+          else
+            {
+              ret = -ENODEV;
+            }
+        }
+        break;
+
+      case SIOCGIFINDEX:  /* Index to name mapping */
+        {
+          struct net_driver_s *dev = netdev_findbyname(req->ifr_name);
+          if (dev != NULL)
+            {
+              req->ifr_ifindex = dev->d_ifindex;
+              ret = OK;
+            }
+          else
+            {
+              ret = -ENODEV;
+            }
+        }
+        break;
 #endif
 
       default:
diff --git a/net/netdev/netdev_register.c b/net/netdev/netdev_register.c
index 4b08efa..3694db5 100644
--- a/net/netdev/netdev_register.c
+++ b/net/netdev/netdev_register.c
@@ -37,6 +37,7 @@
 #include <nuttx/net/netdev.h>
 #include <nuttx/net/ethernet.h>
 #include <nuttx/net/bluetooth.h>
+#include <nuttx/net/can.h>
 
 #include "utils/utils.h"
 #include "igmp/igmp.h"
@@ -56,6 +57,7 @@
 #define NETDEV_WLAN_FORMAT  "wlan%d"
 #define NETDEV_WPAN_FORMAT  "wpan%d"
 #define NETDEV_WWAN_FORMAT  "wwan%d"
+#define NETDEV_CAN_FORMAT   "can%d"
 
 #if defined(CONFIG_DRIVERS_IEEE80211) /* Usually also has CONFIG_NET_ETHERNET */
 #  define NETDEV_DEFAULT_FORMAT NETDEV_WLAN_FORMAT
@@ -67,6 +69,8 @@
 #  define NETDEV_DEFAULT_FORMAT NETDEV_SLIP_FORMAT
 #elif defined(CONFIG_NET_TUN)
 #  define NETDEV_DEFAULT_FORMAT NETDEV_TUN_FORMAT
+#elif defined(CONFIG_NET_CAN)
+#  define NETDEV_DEFAULT_FORMAT NETDEV_CAN_FORMAT
 #else /* if defined(CONFIG_NET_LOOPBACK) */
 #  define NETDEV_DEFAULT_FORMAT NETDEV_LO_FORMAT
 #endif
@@ -277,6 +281,14 @@ int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype)
             break;
 #endif
 
+#ifdef CONFIG_NET_CAN
+          case NET_LL_CAN:  /* CAN bus */
+            dev->d_llhdrlen = 0;
+            dev->d_pktsize  = NET_CAN_PKTSIZE;
+            devfmt          = NETDEV_CAN_FORMAT;
+            break;
+#endif
+
 #ifdef CONFIG_NET_BLUETOOTH
           case NET_LL_BLUETOOTH:              /* Bluetooth */
             llhdrlen = BLUETOOTH_MAX_HDRLEN;  /* Determined at runtime */
diff --git a/net/netlink/netlink_sockif.c b/net/netlink/netlink_sockif.c
index 577d520..34b011a 100644
--- a/net/netlink/netlink_sockif.c
+++ b/net/netlink/netlink_sockif.c
@@ -111,6 +111,10 @@ const struct sock_intf_s g_netlink_sockif =
   NULL,                 /* si_sendfile */
 #endif
   netlink_recvfrom,     /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+  NULL,                 /* si_recvmsg */
+  NULL,                 /* si_sendmsg */
+#endif
   netlink_close         /* si_close */
 };
 
diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c
index e189ddc..dbf3e3c 100644
--- a/net/pkt/pkt_sockif.c
+++ b/net/pkt/pkt_sockif.c
@@ -108,6 +108,10 @@ const struct sock_intf_s g_pkt_sockif =
   NULL,            /* si_sendfile */
 #endif
   pkt_recvfrom,    /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+  NULL,            /* si_recvmsg */
+  NULL,            /* si_sendmsg */
+#endif
   pkt_close        /* si_close */
 };
 
diff --git a/net/socket/Kconfig b/net/socket/Kconfig
index c627ea5..f13e22d 100644
--- a/net/socket/Kconfig
+++ b/net/socket/Kconfig
@@ -37,6 +37,12 @@ config NET_UDPPROTO_OPTIONS
 	---help---
 		Enable or disable support for UDP protocol level socket options.
 
+config NET_CANPROTO_OPTIONS
+	bool
+	default n
+	---help---
+		Enable or disable support for CAN protocol level socket option
+
 if NET_SOCKOPTS
 
 config NET_SOLINGER
@@ -49,5 +55,23 @@ config NET_SOLINGER
 		Enable or disable support for the SO_LINGER socket option.  Requires
 		write buffer support.
 
+config NET_TIMESTAMP
+	bool "SO_TIMESTAMP socket option"
+	default n
+	depends on NET_CAN
+	select NET_CMSG
+	---help---
+		Enable or disable support for the SO_TIMESTAMP socket option. Currently only tested & implemented in SocketCAN but should work on all sockets
+
 endif # NET_SOCKOPTS
+
+config NET_CMSG
+	bool "Control messages (CMSG) support"
+	default n
+	---help---
+		Enable or disable support for control messages in the recvmsg() and
+		sendmsg() function. Control messages (also defined in POSIX 1003.1g 
+		as ancillary data object information). Includes additional 
+		information on the packet received or to be transmitted.
+
 endmenu # Socket Support
diff --git a/net/socket/Make.defs b/net/socket/Make.defs
index 47fb4d2..6bf79ed 100644
--- a/net/socket/Make.defs
+++ b/net/socket/Make.defs
@@ -74,3 +74,9 @@ endif
 
 DEPPATH += --dep-path socket
 VPATH += :socket
+
+# Support for control messages (CMSG)
+ifeq ($(CONFIG_NET_CMSG),y)
+SOCK_CSRCS += recvmsg.c
+SOCK_CSRCS += sendmsg.c
+endif
diff --git a/net/socket/getsockopt.c b/net/socket/getsockopt.c
index e7474ad..581edc0 100644
--- a/net/socket/getsockopt.c
+++ b/net/socket/getsockopt.c
@@ -278,6 +278,19 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
         }
         break;
 
+#ifdef CONFIG_NET_TIMESTAMP
+      case SO_TIMESTAMP:
+        {
+          if (*value_len != sizeof(int))
+            {
+              return -EINVAL;
+            }
+
+          *(FAR int *)value = (int)psock->s_timestamp;
+        }
+        break;
+#endif
+
       /* The following are not yet implemented
        * (return values other than {0,1})
        */
@@ -371,6 +384,12 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
        break;
 #endif
 
+      case SOL_CAN_RAW:/* CAN protocol socket options (see include/netpacket/can.h) */
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+       ret = can_getsockopt(psock, option, value, value_len);
+#endif
+       break;
+
       /* These levels are defined in sys/socket.h, but are not yet
        * implemented.
        */
diff --git a/net/socket/net_sockif.c b/net/socket/net_sockif.c
index 01e8368..cc956d8 100644
--- a/net/socket/net_sockif.c
+++ b/net/socket/net_sockif.c
@@ -47,6 +47,7 @@
 
 #include "inet/inet.h"
 #include "local/local.h"
+#include "can/can.h"
 #include "netlink/netlink.h"
 #include "pkt/pkt.h"
 #include "bluetooth/bluetooth.h"
@@ -104,6 +105,12 @@ net_sockif(sa_family_t family, int type, int protocol)
       break;
 #endif
 
+#ifdef CONFIG_NET_CAN
+    case PF_CAN:
+      sockif = &g_can_sockif;
+      break;
+#endif
+
 #ifdef CONFIG_NET_NETLINK
     case PF_NETLINK:
       sockif = &g_netlink_sockif;
diff --git a/net/socket/recvmsg.c b/net/socket/recvmsg.c
new file mode 100644
index 0000000..9ba5de3
--- /dev/null
+++ b/net/socket/recvmsg.c
@@ -0,0 +1,244 @@
+/****************************************************************************
+ * net/socket/recvmsg.c
+ *
+ *   Copyright (C) 2007-2009, 2011-2017, 2019 Gregory Nutt. All rights
+ *     reserved.
+ *   Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/cancelpt.h>
+#include <nuttx/net/net.h>
+
+#include "socket/socket.h"
+
+#ifdef CONFIG_NET_CMSG
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_recvmsg
+ *
+ * Description:
+ *   psock_recvfrom() receives messages from a socket, and may be used to
+ *   receive data on a socket whether or not it is connection-oriented.
+ *   This is an internal OS interface.  It is functionally equivalent to
+ *   recvfrom() except that:
+ *
+ *   - It is not a cancellation point,
+ *   - It does not modify the errno variable, and
+ *   - I accepts the internal socket structure as an input rather than an
+ *     task-specific socket descriptor.
+ *
+ * Input Parameters:
+ *   psock   - A pointer to a NuttX-specific, internal socket structure
+ *   msg      Buffer to receive msg
+ *   len     - Length of buffer
+ *   flags   - Receive flags
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  If no data is
+ *   available to be received and the peer has performed an orderly shutdown,
+ *   recv() will return 0.  Otherwise, on any failure, a negated errno value
+ *   is returned (see comments with send() for a list of appropriate errno
+ *   values).
+ *
+ ****************************************************************************/
+
+ssize_t psock_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+                       int flags)
+{
+  /* Verify that non-NULL pointers were passed */
+
+  if (msg == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if (msg->msg_iovlen != 1)
+    {
+      return -ENOTSUP;
+    }
+
+  /* Verify that the sockfd corresponds to valid, allocated socket */
+
+  if (psock == NULL || psock->s_crefs <= 0)
+    {
+      return -EBADF;
+    }
+
+  /* Let logic specific to this address family handle the recvfrom()
+   * operation.
+   */
+
+  DEBUGASSERT(psock->s_sockif != NULL &&
+              (psock->s_sockif->si_recvmsg != NULL ||
+               psock->s_sockif->si_recvfrom != NULL));
+
+  if (psock->s_sockif->si_recvmsg != NULL)
+    {
+      return psock->s_sockif->si_recvmsg(psock, msg, flags);
+    }
+  else
+    {
+      /* Socket doesn't implement si_recvmsg fallback to si_recvfrom */
+
+      FAR void *buf             = msg->msg_iov->iov_base;
+      FAR struct sockaddr *from = msg->msg_name;
+      FAR socklen_t *fromlen    = (FAR socklen_t *)&msg->msg_namelen;
+      size_t len                = msg->msg_iov->iov_len;
+
+      return psock->s_sockif->si_recvfrom(psock, buf, len, flags, from,
+                                          fromlen);
+    }
+}
+
+/****************************************************************************
+ * Name: nx_recvfrom
+ *
+ * Description:
+ *   nx_recvfrom() receives messages from a socket, and may be used to
+ *   receive data on a socket whether or not it is connection-oriented.
+ *   This is an internal OS interface.  It is functionally equivalent to
+ *   recvfrom() except that:
+ *
+ *   - It is not a cancellation point, and
+ *   - It does not modify the errno variable.
+ *
+ * Input Parameters:
+ *   sockfd  - Socket descriptor of socket
+ *   msg      Buffer to receive msg
+ *   len     - Length of buffer
+ *   flags   - Receive flags
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  If no data is
+ *   available to be received and the peer has performed an orderly shutdown,
+ *   recv() will return 0.  Otherwise, on any failure, a negated errno value
+ *   is returned (see comments with send() for a list of appropriate errno
+ *   values).
+ *
+ ****************************************************************************/
+
+ssize_t nx_recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
+{
+  FAR struct socket *psock;
+
+  /* Get the underlying socket structure */
+
+  psock = sockfd_socket(sockfd);
+
+  /* Then let psock_recvmsg() do all of the work */
+
+  return psock_recvmsg(psock, msg, flags);
+}
+
+/****************************************************************************
+ * Function: recvmsg
+ *
+ * Description:
+ *   The recvmsg() call is identical to recvfrom() with a NULL from
+ *   parameter.
+ *
+ * Parameters:
+ *   sockfd   Socket descriptor of socket
+ *   msg      Buffer to receive msg
+ *   len      Length of buffer
+ *   flags    Receive flags
+ *
+ * Returned Value:
+ *   On success, returns the number of characters received.  On  error,
+ *   -1 is returned, and errno is set appropriately:
+ *
+ *   EAGAIN
+ *     The socket is marked non-blocking and the receive operation would
+ *     block, or a receive timeout had been set and the timeout expired
+ *     before data was received.
+ *   EBADF
+ *     The argument sockfd is an invalid descriptor.
+ *   ECONNREFUSED
+ *     A remote host refused to allow the network connection (typically
+ *     because it is not running the requested service).
+ *   EFAULT
+ *     The receive buffer pointer(s) point outside the process's address
+ *     space.
+ *   EINTR
+ *     The receive was interrupted by delivery of a signal before any data
+ *     were available.
+ *   EINVAL
+ *     Invalid argument passed.
+ *   ENOMEM
+ *     Could not allocate memory.
+ *   ENOTCONN
+ *     The socket is associated with a connection-oriented protocol and has
+ *     not been connected.
+ *   ENOTSOCK
+ *     The argument sockfd does not refer to a socket.
+ *
+ ****************************************************************************/
+
+ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
+{
+  FAR struct socket *psock;
+  ssize_t ret;
+
+  /* recvfrom() is a cancellation point */
+
+  enter_cancellation_point();
+
+  /* Get the underlying socket structure */
+
+  psock = sockfd_socket(sockfd);
+
+  /* Let psock_recvfrom() do all of the work */
+
+  ret = psock_recvmsg(psock, msg, flags);
+  if (ret < 0)
+    {
+      _SO_SETERRNO(psock, -ret);
+      ret = ERROR;
+    }
+
+  leave_cancellation_point();
+  return ret;
+}
+
+#endif /* CONFIG_NET_CMSG */
diff --git a/net/socket/sendmsg.c b/net/socket/sendmsg.c
new file mode 100644
index 0000000..a188b3a
--- /dev/null
+++ b/net/socket/sendmsg.c
@@ -0,0 +1,243 @@
+/****************************************************************************
+ * net/socket/sendmsg.c
+ *
+ *   Copyright (C) 2007-2009, 2011-2017, 2019 Gregory Nutt. All rights
+ *     reserved.
+ *   Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/cancelpt.h>
+#include <nuttx/net/net.h>
+
+#include "socket/socket.h"
+
+#ifdef CONFIG_NET_CMSG
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_sendmsg
+ *
+ * Description:
+ *   psock_sendfrom() sends messages to a socket, and may be used to
+ *   send data on a socket whether or not it is connection-oriented.
+ *   This is an internal OS interface.  It is functionally equivalent to
+ *   sendfrom() except that:
+ *
+ *   - It is not a cancellation point,
+ *   - It does not modify the errno variable, and
+ *   - I accepts the internal socket structure as an input rather than an
+ *     task-specific socket descriptor.
+ *
+ * Input Parameters:
+ *   psock   - A pointer to a NuttX-specific, internal socket structure
+ *   msg     - Buffer to of the msg
+ *   len     - Length of buffer
+ *   flags   - Receive flags
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  If no data is
+ *   available to be received and the peer has performed an orderly shutdown,
+ *   send() will return 0.  Otherwise, on any failure, a negated errno value
+ *   is returned (see comments with send() for a list of appropriate errno
+ *   values).
+ *
+ ****************************************************************************/
+
+ssize_t psock_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+                       int flags)
+{
+  /* Verify that non-NULL pointers were passed */
+
+  if (msg == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if (msg->msg_iovlen != 1)
+    {
+      return -ENOTSUP;
+    }
+
+  /* Verify that the sockfd corresponds to valid, allocated socket */
+
+  if (psock == NULL || psock->s_crefs <= 0)
+    {
+      return -EBADF;
+    }
+
+  /* Let logic specific to this address family handle the sendfrom()
+   * operation.
+   */
+
+  DEBUGASSERT(psock->s_sockif != NULL &&
+              (psock->s_sockif->si_sendmsg != NULL ||
+               psock->s_sockif->si_sendto != NULL));
+
+  if (psock->s_sockif->si_sendmsg != NULL)
+    {
+      return psock->s_sockif->si_sendmsg(psock, msg, flags);
+    }
+  else
+    {
+      /* Socket doesn't implement si_sendmsg fallback to si_sendto */
+
+      FAR void *buf           = msg->msg_iov->iov_base;
+      FAR struct sockaddr *to = msg->msg_name;
+      socklen_t tolen         = msg->msg_namelen;
+      size_t len              = msg->msg_iov->iov_len;
+
+      return psock->s_sockif->si_sendto(psock, buf, len, flags, to, tolen);
+    }
+}
+
+/****************************************************************************
+ * Name: nx_sendfrom
+ *
+ * Description:
+ *   nx_sendfrom() receives messages from a socket, and may be used to
+ *   receive data on a socket whether or not it is connection-oriented.
+ *   This is an internal OS interface.  It is functionally equivalent to
+ *   sendfrom() except that:
+ *
+ *   - It is not a cancellation point, and
+ *   - It does not modify the errno variable.
+ *
+ * Input Parameters:
+ *   sockfd  - Socket descriptor of socket
+ *   msg      Buffer to receive msg
+ *   len     - Length of buffer
+ *   flags   - Receive flags
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  If no data is
+ *   available to be received and the peer has performed an orderly shutdown,
+ *   send() will return 0.  Otherwise, on any failure, a negated errno value
+ *   is returned (see comments with send() for a list of appropriate errno
+ *   values).
+ *
+ ****************************************************************************/
+
+ssize_t nx_sendmsg(int sockfd, FAR struct msghdr *msg, int flags)
+{
+  FAR struct socket *psock;
+
+  /* Get the underlying socket structure */
+
+  psock = sockfd_socket(sockfd);
+
+  /* Then let psock_sendmsg() do all of the work */
+
+  return psock_sendmsg(psock, msg, flags);
+}
+
+/****************************************************************************
+ * Function: sendmsg
+ *
+ * Description:
+ *   The sendmsg() call is identical to sendfrom() with a NULL from
+ *   parameter.
+ *
+ * Parameters:
+ *   sockfd   Socket descriptor of socket
+ *   msg      Buffer to receive msg
+ *   len      Length of buffer
+ *   flags    Receive flags
+ *
+ * Returned Value:
+ *   On success, returns the number of characters received.  On  error,
+ *   -1 is returned, and errno is set appropriately:
+ *
+ *   EAGAIN
+ *     The socket is marked non-blocking and the receive operation would
+ *     block, or a receive timeout had been set and the timeout expired
+ *     before data was received.
+ *   EBADF
+ *     The argument sockfd is an invalid descriptor.
+ *   ECONNREFUSED
+ *     A remote host refused to allow the network connection (typically
+ *     because it is not running the requested service).
+ *   EFAULT
+ *     The receive buffer pointer(s) point outside the process's address
+ *     space.
+ *   EINTR
+ *     The receive was interrupted by delivery of a signal before any data
+ *     were available.
+ *   EINVAL
+ *     Invalid argument passed.
+ *   ENOMEM
+ *     Could not allocate memory.
+ *   ENOTCONN
+ *     The socket is associated with a connection-oriented protocol and has
+ *     not been connected.
+ *   ENOTSOCK
+ *     The argument sockfd does not refer to a socket.
+ *
+ ****************************************************************************/
+
+ssize_t sendmsg(int sockfd, FAR struct msghdr *msg, int flags)
+{
+  FAR struct socket *psock;
+  ssize_t ret;
+
+  /* sendfrom() is a cancellation point */
+
+  enter_cancellation_point();
+
+  /* Get the underlying socket structure */
+
+  psock = sockfd_socket(sockfd);
+
+  /* Let psock_sendfrom() do all of the work */
+
+  ret = psock_sendmsg(psock, msg, flags);
+  if (ret < 0)
+    {
+      _SO_SETERRNO(psock, -ret);
+      ret = ERROR;
+    }
+
+  leave_cancellation_point();
+  return ret;
+}
+
+#endif /* CONFIG_NET_CMSG */
diff --git a/net/socket/setsockopt.c b/net/socket/setsockopt.c
index 211a1df..da4b923 100644
--- a/net/socket/setsockopt.c
+++ b/net/socket/setsockopt.c
@@ -279,6 +279,29 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
         }
         break;
 #endif
+
+#ifdef CONFIG_NET_TIMESTAMP
+      case SO_TIMESTAMP:  /* Generates a timestamp for each incoming packet */
+        {
+          /* Verify that option is at least the size of an integer. */
+
+          if (value_len < sizeof(FAR int32_t))
+            {
+              return -EINVAL;
+            }
+
+          /* Lock the network so that we have exclusive access to the socket
+           * options.
+           */
+
+          net_lock();
+
+          psock->s_timestamp = *((FAR int32_t *)value);
+
+          net_unlock();
+        }
+        break;
+#endif
       /* The following are not yet implemented */
 
       case SO_RCVBUF:     /* Sets receive buffer size */
@@ -399,6 +422,12 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
         break;
 #endif
 
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+      case SOL_CAN_RAW:   /* CAN protocol socket options (see include/netpacket/can.h) */
+        ret = can_setsockopt(psock, option, value, value_len);
+        break;
+#endif
+
       default:         /* The provided level is invalid */
         ret = -EINVAL;
         break;
diff --git a/net/socket/socket.h b/net/socket/socket.h
index 0f809ac..bd2a0ea 100644
--- a/net/socket/socket.h
+++ b/net/socket/socket.h
@@ -80,7 +80,7 @@
 
 /* This is the largest option value.  REVISIT: belongs in sys/socket.h */
 
-#define _SO_MAXOPT       (15)
+#define _SO_MAXOPT       (16)
 
 /* Macros to set, test, clear options */
 
diff --git a/net/utils/net_lock.c b/net/utils/net_lock.c
index da6784d..645a5cc 100644
--- a/net/utils/net_lock.c
+++ b/net/utils/net_lock.c
@@ -229,6 +229,57 @@ int net_lock(void)
 }
 
 /****************************************************************************
+ * Name: net_trylock
+ *
+ * Description:
+ *   Try to take the network lock only when it is currently not locked.
+ *   Otherwise, it locks the semaphore.  In either
+ *   case, the call returns without blocking.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   failured (probably -EAGAIN).
+ *
+ ****************************************************************************/
+
+int net_trylock(void)
+{
+#ifdef CONFIG_SMP
+  irqstate_t flags = enter_critical_section();
+#endif
+  pid_t me = getpid();
+  int ret = OK;
+
+  /* Does this thread already hold the semaphore? */
+
+  if (g_holder == me)
+    {
+      /* Yes.. just increment the reference count */
+
+      g_count++;
+    }
+  else
+    {
+      ret = nxsem_trywait(&g_netlock);
+      if (ret >= 0)
+        {
+          /* Now this thread holds the semaphore */
+
+          g_holder = me;
+          g_count  = 1;
+        }
+    }
+
+#ifdef CONFIG_SMP
+  leave_critical_section(flags);
+#endif
+  return ret;
+}
+
+/****************************************************************************
  * Name: net_unlock
  *
  * Description:


[incubator-nuttx] 03/04: Kinetis: Added FlexCAN driver with SocketCAN support

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 5f73dc89becb591d914deca874f8054ab7279fff
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Mon Jun 15 10:25:46 2020 +0200

    Kinetis: Added FlexCAN driver with SocketCAN support
---
 arch/arm/src/kinetis/Kconfig                    |   94 +-
 arch/arm/src/kinetis/Make.defs                  |    7 +
 arch/arm/src/kinetis/hardware/kinetis_flexcan.h |   30 +-
 arch/arm/src/kinetis/kinetis.h                  |   91 +-
 arch/arm/src/kinetis/kinetis_flexcan.c          | 1907 +++++++++++++++++++++++
 5 files changed, 2098 insertions(+), 31 deletions(-)

diff --git a/arch/arm/src/kinetis/Kconfig b/arch/arm/src/kinetis/Kconfig
index 8a945a4..ad64c49 100644
--- a/arch/arm/src/kinetis/Kconfig
+++ b/arch/arm/src/kinetis/Kconfig
@@ -317,6 +317,8 @@ config ARCH_FAMILY_K66
 	select KINETIS_HAVE_TPM1
 	select KINETIS_HAVE_TPM2
 	select KINETIS_HAVE_DMA
+	select KINETIS_HAVE_FLEXCAN0
+	select KINETIS_HAVE_FLEXCAN1
 
 menu "Kinetis Peripheral Support"
 
@@ -356,6 +358,14 @@ config KINETIS_HAVE_TPM2
 	bool
 	default n
 
+config KINETIS_HAVE_FLEXCAN0
+	bool
+	default n
+
+config KINETIS_HAVE_FLEXCAN1
+	bool
+	default n
+
 config KINETIS_TRACE
 	bool "Trace"
 	default n
@@ -502,15 +512,23 @@ config KINETIS_RNGB
 	select ARCH_HAVE_RNG
 	---help---
 		Support the random number generator(K6x only)
+		
+config KINETIS_FLEXCAN
+	bool
+	default n
 
 config KINETIS_FLEXCAN0
-	bool "FlexCAN0"
+	bool "FLEXCAN0"
+	select KINETIS_FLEXCAN
+	select NET_CAN_HAVE_TX_DEADLINE
 	default n
 	---help---
 		Support FlexCAN0
 
 config KINETIS_FLEXCAN1
-	bool "FlexCAN1"
+	bool "FLEXCAN1"
+	select KINETIS_FLEXCAN
+	select NET_CAN_HAVE_TX_DEADLINE
 	default n
 	---help---
 		Support FlexCAN1
@@ -930,7 +948,7 @@ config KINETIS_ENET_NORXER
 	---help---
 		If selected, then the MII/RMII RXER output will be configured as a
 		GPIO and pulled low.
-
+		
 choice
 	prompt "RMII Clock Source"
 	default KINETIS_EMAC_RMIICLKEXTAL
@@ -947,6 +965,76 @@ config KINETIS_EMAC_RMIICLK1588CLKIN
 endchoice # RMII Clock Source
 endmenu # Kinetis Ethernet Configuration
 
+menu "Kinetis FLEXCAN0 Configuration"
+	depends on KINETIS_FLEXCAN0
+
+config FLEXCAN0_BITRATE
+	int "CAN bitrate"
+	depends on !NET_CAN_CANFD
+	default 1000000
+	
+config FLEXCAN0_SAMPLEP
+	int "CAN sample point"
+	depends on !NET_CAN_CANFD
+	default 75
+	
+config FLEXCAN0_ARBI_BITRATE
+	int "CAN FD Arbitration phase bitrate"
+	depends on NET_CAN_CANFD
+	default 1000000
+	
+config FLEXCAN0_ARBI_SAMPLEP
+	int "CAN FD Arbitration phase sample point"
+	depends on NET_CAN_CANFD
+	default 80
+	
+config FLEXCAN0_DATA_BITRATE
+	int "CAN FD Arbitration phase bitrate"
+	depends on NET_CAN_CANFD
+	default 4000000
+	
+config FLEXCAN0_DATA_SAMPLEP
+	int "CAN FD Arbitration phase sample point"
+	depends on NET_CAN_CANFD
+	default 90
+	
+endmenu # KINETIS_FLEXCAN0
+
+menu "Kinetis FLEXCAN1 Configuration"
+	depends on KINETIS_FLEXCAN1
+
+config FLEXCAN1_BITRATE
+	int "CAN bitrate"
+	depends on !NET_CAN_CANFD
+	default 1000000
+	
+config FLEXCAN1_SAMPLEP
+	int "CAN sample point"
+	depends on !NET_CAN_CANFD
+	default 75
+	
+config FLEXCAN1_ARBI_BITRATE
+	int "CAN FD Arbitration phase bitrate"
+	depends on NET_CAN_CANFD
+	default 1000000
+	
+config FLEXCAN1_ARBI_SAMPLEP
+	int "CAN FD Arbitration phase sample point"
+	depends on NET_CAN_CANFD
+	default 80
+	
+config FLEXCAN1_DATA_BITRATE
+	int "CAN FD Arbitration phase bitrate"
+	depends on NET_CAN_CANFD
+	default 4000000
+	
+config FLEXCAN1_DATA_SAMPLEP
+	int "CAN FD Arbitration phase sample point"
+	depends on NET_CAN_CANFD
+	default 90
+	
+endmenu # KINETIS_FLEXCAN1
+
 menu "Kinetis SDHC Configuration"
 	depends on KINETIS_SDHC
 
diff --git a/arch/arm/src/kinetis/Make.defs b/arch/arm/src/kinetis/Make.defs
index d4164f7..aba8fe3 100644
--- a/arch/arm/src/kinetis/Make.defs
+++ b/arch/arm/src/kinetis/Make.defs
@@ -175,4 +175,11 @@ ifeq ($(CONFIG_NET),y)
 ifeq ($(CONFIG_KINETIS_ENET),y)
 CHIP_CSRCS += kinetis_enet.c
 endif
+
+ifeq ($(CONFIG_NET_CAN),y)
+ifeq ($(CONFIG_KINETIS_FLEXCAN),y)
+CHIP_CSRCS += kinetis_flexcan.c
+endif
+endif
+
 endif
diff --git a/arch/arm/src/kinetis/hardware/kinetis_flexcan.h b/arch/arm/src/kinetis/hardware/kinetis_flexcan.h
index 32f4fad..a7b198e 100644
--- a/arch/arm/src/kinetis/hardware/kinetis_flexcan.h
+++ b/arch/arm/src/kinetis/hardware/kinetis_flexcan.h
@@ -68,6 +68,8 @@
 #define KINETIS_CAN_RXFGMASK_OFFSET 0x0048 /* Rx FIFO Global Mask Register */
 #define KINETIS_CAN_RXFIR_OFFSET    0x004c /* Rx FIFO Information Register */
 
+#define KINETIS_CAN_MB_OFFSET       0x0080 /* CAN MB register */
+
 #define KINETIS_CAN_RXIMR_OFFSET(n) (0x0880+((n)<<2)) /* Rn Individual Mask Registers */
 #define KINETIS_CAN_RXIMR0_OFFSET   0x0880 /* R0 Individual Mask Registers */
 #define KINETIS_CAN_RXIMR1_OFFSET   0x0884 /* R1 Individual Mask Registers */
@@ -137,6 +139,7 @@
 #  define CAN_MCR_IDAM_FMTB        (1 << CAN_MCR_IDAM_SHIFT) /* Format B: Two full (or partial) IDs */
 #  define CAN_MCR_IDAM_FMTC        (2 << CAN_MCR_IDAM_SHIFT) /* Format C: Four partial IDs */
 #  define CAN_MCR_IDAM_FMTD        (3 << CAN_MCR_IDAM_SHIFT) /* Format D: All frames rejected */
+
                                              /* Bits 10-11: Reserved */
 #define CAN_MCR_AEN                (1 << 12) /* Bit 12: Abort Enable */
 #define CAN_MCR_LPRIOEN            (1 << 13) /* Bit 13: Local Priority Enable */
@@ -162,6 +165,7 @@
 
 #define CAN_CTRL1_ROPSEG_SHIFT     (0)       /* Bits 0-2: Propagation Segment */
 #define CAN_CTRL1_ROPSEG_MASK      (7 << CAN_CTRL1_ROPSEG_SHIFT)
+#define CAN_CTRL1_PROPSEG(x)       (((uint32_t)(((uint32_t)(x)) << 0)) & 0x7)
 #define CAN_CTRL1_LOM              (1 << 3)  /* Bit 3:  Listen-Only Mode */
 #define CAN_CTRL1_LBUF             (1 << 4)  /* Bit 4:  Lowest Buffer Transmitted First */
 #define CAN_CTRL1_TSYN             (1 << 5)  /* Bit 5:  Timer Sync */
@@ -176,18 +180,23 @@
 #define CAN_CTRL1_BOFFMSK          (1 << 15) /* Bit 15: Bus Off Mask */
 #define CAN_CTRL1_PSEG2_SHIFT      (16)       /* Bits 16-18: Phase Segment 2 */
 #define CAN_CTRL1_PSEG2_MASK       (7 << CAN_CTRL1_PSEG2_SHIFT)
+#define CAN_CTRL1_PSEG2(x)         (((uint32_t)(((uint32_t)(x)) << 16)) & 0x70000)
 #define CAN_CTRL1_PSEG1_SHIFT      (19)       /* Bits 19-21: Phase Segment 1 */
 #define CAN_CTRL1_PSEG1_MASK       (7 << CAN_CTRL1_PSEG1_SHIFT)
+#define CAN_CTRL1_PSEG1(x)         (((uint32_t)(((uint32_t)(x)) << 19)) & 0x380000)
 #define CAN_CTRL1_RJW_SHIFT        (22)       /* Bits 22-23: Resync Jump Width */
 #define CAN_CTRL1_RJW_MASK         (3 << CAN_CTRL1_RJW_SHIFT)
+#define CAN_CTRL1_RJW(x)           (((uint32_t)(((uint32_t)(x)) << 22)) & 0xC00000)
 #define CAN_CTRL1_PRESDIV_SHIFT    (24)       /* Bits 24-31: Prescaler Division Factor */
 #define CAN_CTRL1_PRESDIV_MASK     (0xff << CAN_CTRL1_PRESDIV_SHIFT)
+#define CAN_CTRL1_PRESDIV(x)       (((uint32_t)(((uint32_t)(x)) << 24)) & 0xFF000000)
 
 /* Free Running Timer */
 
 #define CAN_TIMER_SHIFT            (0)       /* Bits 0-15: Timer value */
 #define CAN_TIMER_MASK             (0xffff << CAN_TIMER_SHIFT)
                                              /* Bits 16-31: Reserved */
+
 /* Rx Mailboxes Global Mask Register (32 Rx Mailboxes Global Mask Bits) */
 
 #define CAN_RXMGMASK(n)            (1 << (n)) /* Bit n: Rx Mailboxe n Global Mask Bit */
@@ -207,6 +216,7 @@
 #define CAN_ECR_RXERRCNT_SHIFT     (8)       /* Bits 8-15: Receive Error Counter */
 #define CAN_ECR_RXERRCNT_MASK      (0xff << CAN_ECR_RXERRCNT_SHIFT)
                                              /* Bits 16-31: Reserved */
+
 /* Error and Status 1 Register */
 
 #define CAN_ESR1_WAKINT            (1 << 0)  /* Bit 0:  Wake-Up Interrupt */
@@ -231,7 +241,9 @@
 #define CAN_ESR1_RWRNINT           (1 << 16) /* Bit 16: Rx Warning Interrupt Flag */
 #define CAN_ESR1_TWRNINT           (1 << 17) /* Bit 17: Tx Warning Interrupt Flag */
 #define CAN_ESR1_SYNCH             (1 << 18) /* Bit 18: CAN Synchronization Status */
+
                                              /* Bits 19-31: Reserved */
+
 /* Interrupt Masks 2 Register */
 
 #define CAN_IMASK2(n)              (1 << (n)) /* Bit n: Buffer MBn Mask */
@@ -249,6 +261,7 @@
 #define CAN_IFLAG1(n)              (1 << (n)) /* Bit n: Buffer MBn Interrupt, n=0..4,8..31 */
 
 /* Control 2 Register */
+
                                              /* Bits 0-15: Reserved */
 #define CAN_CTRL2_EACEN            (1 << 16) /* Bit 16:  Entire Frame Arbitration Field Comparison Enable (Rx) */
 #define CAN_CTRL2_RRS              (1 << 17) /* Bit 17:  Remote Request Storing */
@@ -275,7 +288,9 @@
 #  define CAN_CTRL2_RFFN_128MB     (15 << CAN_CTRL2_RFFN_SHIFT)
 #define CAN_CTRL2_WRMFRZ           (1 << 28) /* Bit 28: Write-Access to Memory in Freeze mode */
                                              /* Bits 29-31: Reserved */
+
 /* Error and Status 2 Register */
+
                                              /* Bits 0-12: Reserved */
 #define CAN_ESR2_IMB               (1 << 13) /* Bit 13: Inactive Mailbox */
 #define CAN_ESR2_VPS               (1 << 14) /* Bit 14: Valid Priority Status */
@@ -283,6 +298,7 @@
 #define CAN_ESR2_LPTM_SHIFT        (16)      /* Bits 16-22: Lowest Priority Tx Mailbox */
 #define CAN_ESR2_LPTM_MASK         (0x7f << CAN_ESR2_LPTM_SHIFT)
                                              /* Bits 23-31: Reserved */
+
 /* CRC Register */
 
 #define CAN_CRCR_TXCRC_SHIFT       (0)       /* Bits 0-14: CRC Transmitted */
@@ -295,6 +311,7 @@
 /* Rx FIFO Global Mask Register (32 Rx FIFO Global Mask Bits) */
 
 /* Rx FIFO Information Register */
+
                                              /* Bits 9-31: Reserved */
 #define CAN_RXFIR_IDHIT_SHIFT      (0)       /* Bits 0-8: Identifier Acceptance Filter Hit Indicator */
 #define CAN_RXFIR_IDHIT_MASK       (0x1ff << CAN_RXFIR_IDHIT_SHIFT)
@@ -303,6 +320,15 @@
 
 #define CAN_RXIMR(n)               (1 << (n)) /* Bit n: Individual Mask Bits */
 
+/* CAN MB TX codes */
+#define CAN_TXMB_INACTIVE          0x8        /* MB is not active. */
+#define CAN_TXMB_ABORT             0x9        /* MB is aborted. */
+#define CAN_TXMB_DATAORREMOTE      0xC        /* MB is a TX Data Frame(when MB RTR = 0) or */
+                                              /* MB is a TX Remote Request Frame (when MB RTR = 1). */
+#define CAN_TXMB_TANSWER           0xE        /* MB is a TX Response Request Frame from */
+                                              /* an incoming Remote Request Frame. */
+#define CAN_TXMB_NOTUSED           0xF        /* Not used.*/
+
 /****************************************************************************************************
  * Public Types
  ****************************************************************************************************/
@@ -311,8 +337,4 @@
  * Public Data
  ****************************************************************************************************/
 
-/****************************************************************************************************
- * Public Functions
- ****************************************************************************************************/
-
 #endif /* __ARCH_ARM_SRC_KINETIS_HARDWARE_KINETIS_FLEXCAN_H */
diff --git a/arch/arm/src/kinetis/kinetis.h b/arch/arm/src/kinetis/kinetis.h
index 16290f6..cdabde5 100644
--- a/arch/arm/src/kinetis/kinetis.h
+++ b/arch/arm/src/kinetis/kinetis.h
@@ -62,6 +62,7 @@
 /* Configuration ********************************************************************/
 
 /* Bit-encoded input to kinetis_pinconfig() *****************************************/
+
 /* General form (32-bits, only 22 bits are unused in the encoding):
  *
  * oooo mmmv iiii ifd- ---- -ppp ---b bbbb
@@ -80,6 +81,7 @@
 #define _PIN_OPTIONS_MASK      (15 << _PIN_OPTIONS_SHIFT)
 
 /* Port Modes */
+
                                                        /* Unshifted versions: */
 #define PIN_MODE_ANALOG        (0)                     /*   000 Pin Disabled (Analog) */
 #define PIN_MODE_ALT1          (1)                     /*   001 Alternative 1 */
@@ -354,7 +356,7 @@ extern "C"
 
 void kinetis_clockconfig(void);
 
-/****************************************************************************
+/************************************************************************************
  * Name: kinetis_earlyserialinit
  *
  * Description:
@@ -362,13 +364,13 @@ void kinetis_clockconfig(void);
  *   the serial console will be available during bootup.  This must be called
  *   before arm_serialinit.
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef USE_EARLYSERIALINIT
 void kinetis_earlyserialinit(void);
 #endif
 
-/****************************************************************************
+/************************************************************************************
  * Name: kinetis_uart_earlyserialinit
  *
  * Description:
@@ -376,13 +378,13 @@ void kinetis_earlyserialinit(void);
  *   serial console will be available during bootup.  This must be called
  *   before arm_serialinit.
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef USE_EARLYSERIALINIT
 void kinetis_uart_earlyserialinit(void);
 #endif
 
-/****************************************************************************
+/************************************************************************************
  * Name: kinetis_lpuart_earlyserialinit
  *
  * Description:
@@ -390,7 +392,7 @@ void kinetis_uart_earlyserialinit(void);
  *   serial console will be available during bootup.  This must be called
  *   before arm_serialinit.
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef USE_EARLYSERIALINIT
 void kinetis_lpuart_earlyserialinit(void);
@@ -408,7 +410,7 @@ void kinetis_lpuart_earlyserialinit(void);
 
 void kinetis_lowsetup(void);
 
-/****************************************************************************
+/************************************************************************************
  * Name: kinetis_uart_serialinit
  *
  * Description:
@@ -421,13 +423,13 @@ void kinetis_lowsetup(void);
  * Returned Value:
  *   The next TTY number available for assignment
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef HAVE_UART_DEVICE
 unsigned int kinetis_uart_serialinit(unsigned int first);
 #endif
 
-/****************************************************************************
+/************************************************************************************
  * Name: kinetis_lpuart_serialinit
  *
  * Description:
@@ -440,43 +442,43 @@ unsigned int kinetis_uart_serialinit(unsigned int first);
  * Returned Value:
  *   The next TTY number available for assignment
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef HAVE_LPUART_DEVICE
 unsigned int kinetis_lpuart_serialinit(unsigned int first);
 #endif
 
-/****************************************************************************
+/************************************************************************************
  * Name: kinetis_uartreset
  *
  * Description:
  *   Reset a UART.
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef HAVE_UART_DEVICE
 void kinetis_uartreset(uintptr_t uart_base);
 #endif
 
-/****************************************************************************
+/************************************************************************************
  * Name: kinetis_lpuartreset
  *
  * Description:
  *   Reset a UART.
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef HAVE_LPUART_DEVICE
 void kinetis_lpuartreset(uintptr_t uart_base);
 #endif
 
-/****************************************************************************
+/************************************************************************************
  * Name: kinetis_uartconfigure
  *
  * Description:
  *   Configure a UART as a RS-232 UART.
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef HAVE_UART_DEVICE
 void kinetis_uartconfigure(uintptr_t uart_base, uint32_t baud, uint32_t clock,
@@ -485,13 +487,13 @@ void kinetis_uartconfigure(uintptr_t uart_base, uint32_t baud, uint32_t clock,
                            bool iflow, bool oflow);
 #endif
 
-/****************************************************************************
+/************************************************************************************
  * Name: kinetis_lpuartconfigure
  *
  * Description:
  *   Configure a UART as a RS-232 UART.
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef HAVE_LPUART_DEVICE
 void kinetis_lpuartconfigure(uintptr_t uart_base, uint32_t baud, uint32_t clock,
@@ -672,7 +674,7 @@ void kinetis_pindump(uint32_t pinset, const char *msg);
 
 void kinetis_clrpend(int irq);
 
-/****************************************************************************
+/************************************************************************************
  * Name: sdhc_initialize
  *
  * Description:
@@ -684,14 +686,14 @@ void kinetis_clrpend(int irq);
  * Returned Value:
  *   A reference to an SDIO interface structure.  NULL is returned on failures.
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef CONFIG_KINETIS_SDHC
 struct sdio_dev_s;
 FAR struct sdio_dev_s *sdhc_initialize(int slotno);
 #endif
 
-/****************************************************************************
+/************************************************************************************
  * Name: sdhc_mediachange
  *
  * Description:
@@ -708,13 +710,13 @@ FAR struct sdio_dev_s *sdhc_initialize(int slotno);
  * Returned Value:
  *   None
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef CONFIG_KINETIS_SDHC
 void sdhc_mediachange(FAR struct sdio_dev_s *dev, bool cardinslot);
 #endif
 
-/****************************************************************************
+/************************************************************************************
  * Name: sdio_wrprotect
  *
  * Description:
@@ -728,7 +730,7 @@ void sdhc_mediachange(FAR struct sdio_dev_s *dev, bool cardinslot);
  * Returned Value:
  *   None
  *
- ****************************************************************************/
+ ************************************************************************************/
 
 #ifdef CONFIG_KINETIS_SDHC
 void sdhc_wrprotect(FAR struct sdio_dev_s *dev, bool wrprotect);
@@ -738,5 +740,46 @@ void sdhc_wrprotect(FAR struct sdio_dev_s *dev, bool wrprotect);
 }
 #endif
 
+/************************************************************************************
+ * Name: kinetis_netinitialize
+ *
+ * Description:
+ *   Initialize the Ethernet controller and driver
+ *
+ * Input Parameters:
+ *   intf - In the case where there are multiple EMACs, this value
+ *          identifies which EMAC is to be initialized.
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ************************************************************************************/
+
+#ifdef CONFIG_KINETIS_ENET
+int kinetis_netinitialize(int intf);
+#endif
+
+/************************************************************************************
+ * Function: kinetis_caninitialize
+ *
+ * Description:
+ *   Initialize the CAN controller and driver
+ *
+ * Input Parameters:
+ *   intf - In the case where there are multiple CAN, this value
+ *          identifies which CAN is to be initialized.
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ************************************************************************************/
+#ifdef CONFIG_KINETIS_CAN
+int kinetis_caninitialize(int intf)
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __ARCH_ARM_SRC_KINETIS_KINETIS_H */
diff --git a/arch/arm/src/kinetis/kinetis_flexcan.c b/arch/arm/src/kinetis/kinetis_flexcan.c
new file mode 100644
index 0000000..1256f54
--- /dev/null
+++ b/arch/arm/src/kinetis/kinetis_flexcan.c
@@ -0,0 +1,1907 @@
+/****************************************************************************
+ * arch/arm/src/kinetis/kinetis_flexcan.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 <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/can.h>
+#include <nuttx/wdog.h>
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/signal.h>
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/can.h>
+
+#include "arm_arch.h"
+#include "chip.h"
+#include "kinetis_config.h"
+#include "hardware/kinetis_flexcan.h"
+#include "hardware/kinetis_pinmux.h"
+#include "hardware/kinetis_sim.h"
+#include "kinetis.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_NET_CMSG
+#include <sys/time.h>
+#endif
+
+#ifdef CONFIG_KINETIS_FLEXCAN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* If processing is not done at the interrupt level, then work queue support
+ * is required.
+ */
+
+#define CANWORK LPWORK
+
+/* CONFIG_KINETIS_FLEXCAN_NETHIFS determines the number of physical
+ * interfaces that will be supported.
+ */
+
+#define MASKSTDID                   0x000007ff
+#define MASKEXTID                   0x1fffffff
+#define FLAGEFF                     (1 << 31) /* Extended frame format */
+#define FLAGRTR                     (1 << 30) /* Remote transmission request */
+
+#define RXMBCOUNT                   5
+#define TXMBCOUNT                   2
+#define TOTALMBCOUNT                RXMBCOUNT + TXMBCOUNT
+
+#define IFLAG1_RX                   ((1 << RXMBCOUNT)-1)
+#define IFLAG1_TX                   (((1 << TXMBCOUNT)-1) << RXMBCOUNT)
+
+#define CAN_FIFO_NE                 (1 << 5)
+#define CAN_FIFO_OV                 (1 << 6)
+#define CAN_FIFO_WARN               (1 << 7)
+#define CAN_EFF_FLAG                0x80000000 /* EFF/SFF is set in the MSB */
+
+#define POOL_SIZE                   1
+
+#ifdef CONFIG_NET_CMSG
+#define MSG_DATA                    sizeof(struct timeval)
+#else
+#define MSG_DATA                    0
+#endif
+
+/* CAN bit timing values  */
+#define CLK_FREQ                    BOARD_EXTAL_FREQ
+#define PRESDIV_MAX                 256
+
+#define SEG_MAX                     8
+#define SEG_MIN                     1
+#define TSEG_MIN                    2
+#define TSEG1_MAX                   17
+#define TSEG2_MAX                   9
+#define NUMTQ_MAX                   26
+
+#define SEG_FD_MAX                  32
+#define SEG_FD_MIN                  1
+#define TSEG_FD_MIN                 2
+#define TSEG1_FD_MAX                39
+#define TSEG2_FD_MAX                9
+#define NUMTQ_FD_MAX                49
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+
+#  if !defined(CONFIG_SCHED_WORKQUEUE)
+#    error Work queue support is required
+#  endif
+
+#define TX_TIMEOUT_WQ
+#endif
+
+/* Interrupt flags for RX fifo */
+#define IFLAG1_RXFIFO               (CAN_FIFO_NE | CAN_FIFO_WARN | CAN_FIFO_OV)
+
+static int peak_tx_mailbox_index_ = 0;
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+union cs_e
+{
+  volatile uint32_t cs;
+  struct
+  {
+    volatile uint32_t time_stamp : 16;
+    volatile uint32_t dlc : 4;
+    volatile uint32_t rtr : 1;
+    volatile uint32_t ide : 1;
+    volatile uint32_t srr : 1;
+    volatile uint32_t res : 1;
+    volatile uint32_t code : 4;
+    volatile uint32_t res2 : 1;
+    volatile uint32_t esi : 1;
+    volatile uint32_t brs : 1;
+    volatile uint32_t edl : 1;
+  };
+};
+
+union id_e
+{
+  volatile uint32_t w;
+  struct
+  {
+    volatile uint32_t ext : 29;
+    volatile uint32_t resex : 3;
+  };
+  struct
+  {
+    volatile uint32_t res : 18;
+    volatile uint32_t std : 11;
+    volatile uint32_t resstd : 3;
+  };
+};
+
+union data_e
+{
+  volatile uint32_t w00;
+  struct
+  {
+    volatile uint32_t b03 : 8;
+    volatile uint32_t b02 : 8;
+    volatile uint32_t b01 : 8;
+    volatile uint32_t b00 : 8;
+  };
+};
+
+struct mb_s
+{
+  union cs_e cs;
+  union id_e id;
+#ifdef CONFIG_NET_CAN_CANFD
+  union data_e data[16];
+#else
+  union data_e data[2];
+#endif
+};
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+#define TX_ABORT -1
+#define TX_FREE 0
+#define TX_BUSY 1
+
+struct txmbstats
+{
+  struct timeval deadline;
+  uint32_t pending; /* -1 = abort, 0 = free, 1 = busy  */
+};
+#endif
+
+/* FlexCAN Device hardware configuration */
+
+struct flexcan_config_s
+{
+  uint32_t tx_pin;           /* GPIO configuration for TX */
+  uint32_t rx_pin;           /* GPIO configuration for RX */
+  uint32_t enable_pin;       /* Optional enable pin */
+  uint32_t enable_high;      /* Optional enable high/low */
+  uint32_t bus_irq;          /* BUS IRQ */
+  uint32_t error_irq;        /* ERROR IRQ */
+  uint32_t lprx_irq;         /* LPRX IRQ */
+  uint32_t mb_irq;           /* MB 0-15 IRQ */
+};
+
+struct flexcan_timeseg
+{
+  uint32_t bitrate;
+  int32_t samplep;
+  uint8_t propseg;
+  uint8_t pseg1;
+  uint8_t pseg2;
+  uint8_t presdiv;
+};
+
+/* FlexCAN device structures */
+
+#ifdef CONFIG_KINETIS_FLEXCAN0
+static const struct flexcan_config_s kinetis_flexcan0_config =
+{
+  .tx_pin      = PIN_CAN0_TX,
+  .rx_pin      = PIN_CAN0_RX,
+#ifdef PIN_CAN0_ENABLE
+  .enable_pin  = PIN_CAN0_ENABLE,
+  .enable_high = CAN0_ENABLE_OUT,
+#else
+  .enable_pin  = 0,
+  .enable_high = 0,
+#endif
+  .bus_irq     = KINETIS_IRQ_CAN0BO,
+  .error_irq   = KINETIS_IRQ_CAN0ERR,
+  .lprx_irq    = 0,
+  .mb_irq      = KINETIS_IRQ_CAN0MB,
+};
+#endif
+
+#ifdef CONFIG_KINETIS_FLEXCAN1
+static const struct flexcan_config_s kinetis_flexcan1_config =
+{
+  .tx_pin      = PIN_CAN1_TX,
+  .rx_pin      = PIN_CAN1_RX,
+#ifdef PIN_CAN1_ENABLE
+  .enable_pin  = PIN_CAN1_ENABLE,
+  .enable_high = CAN1_ENABLE_OUT,
+#else
+  .enable_pin  = 0,
+  .enable_high = 0,
+#endif
+  .bus_irq     = KINETIS_IRQ_CAN1BO,
+  .error_irq   = KINETIS_IRQ_CAN1ERR,
+  .lprx_irq    = 0,
+  .mb_irq      = KINETIS_IRQ_CAN1MB,
+};
+#endif
+
+#ifdef CONFIG_KINETIS_FLEXCAN2
+static const struct flexcan_config_s kinetis_flexcan2_config =
+{
+  .tx_pin    = PIN_CAN2_TX,
+  .rx_pin    = PIN_CAN2_RX,
+#ifdef PIN_CAN2_ENABLE
+  .enable_pin = PIN_CAN2_ENABLE,
+  .rx_pin     = CAN2_ENABLE_HIGH,
+#else
+  .enable_pin = 0,
+  .rx_pin     = 0,
+#endif
+  .bus_irq   = KINETIS_IRQ_CAN2_BUS,
+  .error_irq = KINETIS_IRQ_CAN2_ERROR,
+  .lprx_irq  = 0,
+  .mb_irq    = KINETIS_IRQ_CAN2_0_15,
+};
+#endif
+
+/* The kinetis_driver_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct kinetis_driver_s
+{
+  uint32_t base;                /* FLEXCAN base address */
+  bool bifup;                   /* true:ifup false:ifdown */
+#ifdef TX_TIMEOUT_WQ
+  WDOG_ID txtimeout[TXMBCOUNT]; /* TX timeout timer */
+#endif
+  struct work_s irqwork;        /* For deferring interrupt work to the wq */
+  struct work_s pollwork;       /* For deferring poll work to the work wq */
+#ifdef CONFIG_NET_CAN_CANFD
+  struct canfd_frame *txdesc;   /* A pointer to the list of TX descriptor */
+  struct canfd_frame *rxdesc;   /* A pointer to the list of RX descriptors */
+#else
+  struct can_frame *txdesc;     /* A pointer to the list of TX descriptor */
+  struct can_frame *rxdesc;     /* A pointer to the list of RX descriptors */
+#endif
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s dev;      /* Interface understood by the network */
+
+  struct mb_s *rx;
+  struct mb_s *tx;
+
+  struct flexcan_timeseg arbi_timing; /* Timing for arbitration phase */
+#ifdef CONFIG_NET_CAN_CANFD
+  struct flexcan_timeseg data_timing; /* Timing for data phase */
+#endif
+
+  const struct flexcan_config_s *config;
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+  struct txmbstats txmb[TXMBCOUNT];
+#endif
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_KINETIS_FLEXCAN0
+static struct kinetis_driver_s g_flexcan0;
+#endif
+
+#ifdef CONFIG_KINETIS_FLEXCAN1
+static struct kinetis_driver_s g_flexcan1;
+#endif
+
+#ifdef CONFIG_KINETIS_FLEXCAN2
+static struct kinetis_driver_s g_flexcan2;
+#endif
+
+#ifdef CONFIG_NET_CAN_CANFD
+static uint8_t g_tx_pool[(sizeof(struct canfd_frame)+MSG_DATA)*POOL_SIZE];
+static uint8_t g_rx_pool[(sizeof(struct canfd_frame)+MSG_DATA)*POOL_SIZE];
+#else
+static uint8_t g_tx_pool[sizeof(struct can_frame)*POOL_SIZE];
+static uint8_t g_rx_pool[sizeof(struct can_frame)*POOL_SIZE];
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_lsb
+ *
+ * Description:
+ *   Calculate position of lsb that's equal to 1
+ *
+ * Input Parameters:
+ *   value - The value to perform the operation on
+ *
+ * Returned Value:
+ *   location of lsb which is equal to 1, returns 32 when value is 0
+ *
+ ****************************************************************************/
+
+static inline uint32_t arm_lsb(unsigned int value)
+{
+  uint32_t ret;
+  volatile uint32_t rvalue = value;
+  __asm__ __volatile__ ("rbit %1,%0" : "=r" (rvalue) : "r" (rvalue));
+  __asm__ __volatile__ ("clz %0, %1" : "=r"(ret) : "r"(rvalue));
+  return ret;
+}
+
+/****************************************************************************
+ * Name: kinetis_bitratetotimeseg
+ *
+ * Description:
+ *   Convert bitrate to timeseg
+ *
+ * Input Parameters:
+ *   timeseg - structure to store bit timing
+ *   sp_tolerance - allowed difference in sample point from calculated
+ *                  bit timings (recommended value: 1)
+ *   can_fd - if set to calculate CAN FD bit timings, otherwise calculate
+ *            classical can timings
+ *
+ * Returned Value:
+ *   return 1 on succes, return 0 on failure
+ *
+ ****************************************************************************/
+
+uint32_t kinetis_bitratetotimeseg(struct flexcan_timeseg *timeseg,
+                                                int32_t sp_tolerance,
+                                                uint32_t can_fd)
+{
+  int32_t tmppresdiv;
+  int32_t numtq;
+  int32_t tmpsample;
+  int32_t tseg1;
+  int32_t tseg2;
+  int32_t tmppseg1;
+  int32_t tmppseg2;
+  int32_t tmppropseg;
+
+  const int32_t TSEG1MAX = (can_fd ? TSEG1_FD_MAX : TSEG1_MAX);
+  const int32_t TSEG2MAX = (can_fd ? TSEG2_FD_MAX : TSEG2_MAX);
+  const int32_t SEGMAX = (can_fd ? SEG_FD_MAX : SEG_MAX);
+  const int32_t NUMTQMAX = (can_fd ? NUMTQ_FD_MAX : NUMTQ_MAX);
+
+  for (tmppresdiv = 0; tmppresdiv < PRESDIV_MAX; tmppresdiv++)
+    {
+      numtq = (CLK_FREQ / ((tmppresdiv + 1) * timeseg->bitrate));
+
+      if (numtq == 0)
+        {
+          continue;
+        }
+
+      /* The number of time quanta in 1 bit time must be
+       * lower than the one supported
+       */
+
+      if ((CLK_FREQ / ((tmppresdiv + 1) * numtq) == timeseg->bitrate)
+          && (numtq >= 8) && (numtq < NUMTQMAX))
+        {
+          /* Compute time segments based on the value of the sampling point */
+
+          tseg1 = (numtq * timeseg->samplep / 100) - 1;
+          tseg2 = numtq - 1 - tseg1;
+
+          /* Adjust time segment 1 and time segment 2 */
+
+          while (tseg1 >= TSEG1MAX || tseg2 < TSEG_MIN)
+            {
+              tseg2++;
+              tseg1--;
+            }
+
+          tmppseg2 = tseg2 - 1;
+
+          /* Start from pseg1 = pseg2 and adjust until propseg is valid */
+
+          tmppseg1 = tmppseg2;
+          tmppropseg = tseg1 - tmppseg1 - 2;
+
+          while (tmppropseg <= 0)
+            {
+              tmppropseg++;
+              tmppseg1--;
+            }
+
+          while (tmppropseg >= SEGMAX)
+            {
+              tmppropseg--;
+              tmppseg1++;
+            }
+
+          if (((tseg1 >= TSEG1MAX) || (tseg2 >= TSEG2MAX) ||
+              (tseg2 < TSEG_MIN) || (tseg1 < TSEG_MIN)) ||
+              ((tmppropseg >= SEGMAX) || (tmppseg1 >= SEGMAX) ||
+                  (tmppseg2 < SEG_MIN) || (tmppseg2 >= SEGMAX)))
+            {
+              continue;
+            }
+
+          tmpsample = ((tseg1 + 1) * 100) / numtq;
+
+          if ((tmpsample - timeseg->samplep) <= sp_tolerance &&
+              (timeseg->samplep - tmpsample) <= sp_tolerance)
+            {
+              if (can_fd == 1)
+                {
+                  timeseg->propseg = tmppropseg + 1;
+                }
+              else
+                {
+                  timeseg->propseg = tmppropseg;
+                }
+              timeseg->pseg1 = tmppseg1;
+              timeseg->pseg2 = tmppseg2;
+              timeseg->presdiv = tmppresdiv;
+              timeseg->samplep = tmpsample;
+              return 1;
+            }
+        }
+    }
+
+  return 0;
+}
+
+/* Common TX logic */
+
+static bool kinetis_txringfull(FAR struct kinetis_driver_s *priv);
+static int  kinetis_transmit(FAR struct kinetis_driver_s *priv);
+static int  kinetis_txpoll(struct net_driver_s *dev);
+
+/* Helper functions */
+
+static void kinetis_setenable(uint32_t base, uint32_t enable);
+static void kinetis_setfreeze(uint32_t base, uint32_t freeze);
+static uint32_t kinetis_waitmcr_change(uint32_t base,
+                                       uint32_t mask,
+                                       uint32_t target_state);
+
+/* Interrupt handling */
+
+static void kinetis_receive(FAR struct kinetis_driver_s *priv,
+                            uint32_t flags);
+static void kinetis_txdone(FAR void *arg);
+
+static int  kinetis_flexcan_interrupt(int irq, FAR void *context,
+                                      FAR void *arg);
+
+/* Watchdog timer expirations */
+#ifdef TX_TIMEOUT_WQ
+static void kinetis_txtimeout_work(FAR void *arg);
+static void kinetis_txtimeout_expiry(int argc, uint32_t arg, ...);
+#endif
+
+/* NuttX callback functions */
+
+static int  kinetis_ifup(struct net_driver_s *dev);
+static int  kinetis_ifdown(struct net_driver_s *dev);
+
+static void kinetis_txavail_work(FAR void *arg);
+static int  kinetis_txavail(struct net_driver_s *dev);
+
+#ifdef CONFIG_NETDEV_IOCTL
+static int  kinetis_ioctl(struct net_driver_s *dev, int cmd,
+                          unsigned long arg);
+#endif
+
+/* Initialization */
+
+static int  kinetis_initialize(struct kinetis_driver_s *priv);
+static void kinetis_reset(struct kinetis_driver_s *priv);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: kinetis_txringfull
+ *
+ * Description:
+ *   Check if all of the TX descriptors are in use.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   true is the TX ring is full; false if there are free slots at the
+ *   head index.
+ *
+ ****************************************************************************/
+
+static bool kinetis_txringfull(FAR struct kinetis_driver_s *priv)
+{
+  uint32_t mbi = 0;
+
+  while (mbi < TXMBCOUNT)
+    {
+      if (priv->tx[mbi].cs.code != CAN_TXMB_DATAORREMOTE)
+        {
+          return 0;
+        }
+
+      mbi++;
+    }
+
+  return 1;
+}
+
+/****************************************************************************
+ * Function: kinetis_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int kinetis_transmit(FAR struct kinetis_driver_s *priv)
+{
+  /* Attempt to write frame */
+
+  uint32_t mbi = 0;
+  if ((getreg32(priv->base + KINETIS_CAN_ESR2_OFFSET) &
+      (CAN_ESR2_IMB | CAN_ESR2_VPS)) ==
+      (CAN_ESR2_IMB | CAN_ESR2_VPS))
+    {
+      mbi  = ((getreg32(priv->base + KINETIS_CAN_ESR2_OFFSET) &
+        CAN_ESR2_LPTM_MASK) >> CAN_ESR2_LPTM_SHIFT);
+      mbi -= RXMBCOUNT;
+    }
+
+  uint32_t mb_bit = 1 << (RXMBCOUNT + mbi);
+
+  while (mbi < TXMBCOUNT)
+    {
+      if (priv->tx[mbi].cs.code != CAN_TXMB_DATAORREMOTE)
+        {
+          putreg32(mb_bit, priv->base + KINETIS_CAN_IFLAG1_OFFSET);
+          break;
+        }
+
+      mb_bit <<= 1;
+      mbi++;
+    }
+
+  if (mbi == TXMBCOUNT)
+    {
+      nwarn("No TX MB available mbi %i\r\n", mbi);
+      return 0;       /* No transmission for you! */
+    }
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+  int32_t timeout = 0;
+  struct timespec ts;
+  clock_systimespec(&ts);
+
+  if (priv->dev.d_sndlen > priv->dev.d_len)
+    {
+      struct timeval *tv =
+             (struct timeval *)(priv->dev.d_buf + priv->dev.d_len);
+      priv->txmb[mbi].deadline = *tv;
+      timeout  = (tv->tv_sec - ts.tv_sec)*CLK_TCK
+                 + ((tv->tv_usec - ts.tv_nsec / 1000)*CLK_TCK) / 1000000;
+      if (timeout < 0)
+        {
+          return 0;       /* No transmission for you! */
+        }
+    }
+  else
+    {
+      /* Default TX deadline defined in NET_CAN_RAW_DEFAULT_TX_DEADLINE */
+
+      if (CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE > 0)
+        {
+          timeout = ((CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE / 1000000)
+              *CLK_TCK);
+          priv->txmb[mbi].deadline.tv_sec = ts.tv_sec +
+              CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE / 1000000;
+          priv->txmb[mbi].deadline.tv_usec = (ts.tv_nsec / 1000) +
+              CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE % 1000000;
+        }
+      else
+        {
+          priv->txmb[mbi].deadline.tv_sec = 0;
+          priv->txmb[mbi].deadline.tv_usec = 0;
+        }
+    }
+#endif
+
+  peak_tx_mailbox_index_ =
+    (peak_tx_mailbox_index_ > mbi ? peak_tx_mailbox_index_ : mbi);
+
+  union cs_e cs;
+  cs.code = CAN_TXMB_DATAORREMOTE;
+  struct mb_s *mb = &priv->tx[mbi];
+  mb->cs.code = CAN_TXMB_INACTIVE;
+
+  if (priv->dev.d_len == sizeof(struct can_frame))
+    {
+      struct can_frame *frame = (struct can_frame *)priv->dev.d_buf;
+
+      if (frame->can_id & CAN_EFF_FLAG)
+        {
+          cs.ide = 1;
+          mb->id.ext = frame->can_id & MASKEXTID;
+        }
+      else
+        {
+          mb->id.std = frame->can_id & MASKSTDID;
+        }
+
+      cs.rtr = frame->can_id & FLAGRTR ? 1 : 0;
+      cs.dlc = frame->can_dlc;
+
+      mb->data[0].w00 = __builtin_bswap32(*(uint32_t *)&frame->data[0]);
+      mb->data[1].w00 = __builtin_bswap32(*(uint32_t *)&frame->data[4]);
+    }
+#ifdef CONFIG_NET_CAN_CANFD
+  else /* CAN FD frame */
+    {
+      struct canfd_frame *frame = (struct canfd_frame *)priv->dev.d_buf;
+
+      cs.edl = 1; /* CAN FD Frame */
+
+      if (frame->can_id & CAN_EFF_FLAG)
+        {
+          cs.ide = 1;
+          mb->id.ext = frame->can_id & MASKEXTID;
+        }
+      else
+        {
+          mb->id.std = frame->can_id & MASKSTDID;
+        }
+
+      cs.rtr = frame->can_id & FLAGRTR ? 1 : 0;
+
+      cs.dlc = len_to_can_dlc[frame->len];
+
+      uint32_t *frame_data_word = (uint32_t *)&frame->data[0];
+
+      for (int i = 0; i < (frame->len + 4 - 1) / 4; i++)
+        {
+          mb->data[i].w00 = __builtin_bswap32(frame_data_word[i]);
+        }
+    }
+#endif
+
+  mb->cs = cs; /* Go. */
+
+  uint32_t regval;
+  regval = getreg32(priv->base + KINETIS_CAN_IMASK1_OFFSET);
+  regval |= mb_bit;
+  putreg32(regval, priv->base + KINETIS_CAN_IMASK1_OFFSET);
+
+  /* Increment statistics */
+
+  NETDEV_TXPACKETS(&priv->dev);
+
+#ifdef TX_TIMEOUT_WQ
+  /* Setup the TX timeout watchdog (perhaps restarting the timer) */
+
+  if (timeout > 0)
+    {
+      wd_start(priv->txtimeout[mbi], timeout + 1, kinetis_txtimeout_expiry,
+                1, (wdparm_t)priv);
+    }
+#endif
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: kinetis_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send timesout and the interface is reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   May or may not be called from an interrupt handler.  In either case,
+ *   global interrupts are disabled, either explicitly or indirectly through
+ *   interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int kinetis_txpoll(struct net_driver_s *dev)
+{
+  FAR struct kinetis_driver_s *priv =
+    (FAR struct kinetis_driver_s *)dev->d_private;
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  if (priv->dev.d_len > 0)
+    {
+      if (!devif_loopback(&priv->dev))
+        {
+          /* Send the packet */
+
+          kinetis_transmit(priv);
+
+          /* Check if there is room in the device to hold another packet. If
+           * not, return a non-zero value to terminate the poll.
+           */
+
+          if (kinetis_txringfull(priv))
+            {
+              return -EBUSY;
+            }
+        }
+    }
+
+  /* If zero is returned, the polling will continue until all connections
+   * have been examined.
+   */
+
+  return 0;
+}
+
+/****************************************************************************
+ * Function: kinetis_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void kinetis_receive(FAR struct kinetis_driver_s *priv,
+                            uint32_t flags)
+{
+  uint32_t mb_index;
+  struct mb_s *rf;
+
+  while ((mb_index = arm_lsb(flags)) != 32)
+    {
+      rf = &priv->rx[mb_index];
+
+      /* Read the frame contents */
+
+#ifdef CONFIG_NET_CAN_CANFD
+      if (rf->cs.edl) /* CAN FD frame */
+        {
+        struct canfd_frame *frame = (struct canfd_frame *)priv->rxdesc;
+
+          if (rf->cs.ide)
+            {
+              frame->can_id = MASKEXTID & rf->id.ext;
+              frame->can_id |= FLAGEFF;
+            }
+          else
+            {
+              frame->can_id = MASKSTDID & rf->id.std;
+            }
+
+          if (rf->cs.rtr)
+            {
+              frame->can_id |= FLAGRTR;
+            }
+
+          frame->len = can_dlc_to_len[rf->cs.dlc];
+
+          uint32_t *frame_data_word = (uint32_t *)&frame->data[0];
+
+          for (int i = 0; i < (frame->len + 4 - 1) / 4; i++)
+            {
+              frame_data_word[i] = __builtin_bswap32(rf->data[i].w00);
+            }
+
+          /* Clear MB interrupt flag */
+
+          putreg32(1 << mb_index,
+                   priv->base + KINETIS_CAN_IFLAG1_OFFSET);
+
+          /* Copy the buffer pointer to priv->dev..  Set amount of data
+           * in priv->dev.d_len
+           */
+
+          priv->dev.d_len = sizeof(struct canfd_frame);
+          priv->dev.d_buf = (uint8_t *)frame;
+        }
+      else /* CAN 2.0 Frame */
+#endif
+        {
+        struct can_frame *frame = (struct can_frame *)priv->rxdesc;
+
+          if (rf->cs.ide)
+            {
+              frame->can_id = MASKEXTID & rf->id.ext;
+              frame->can_id |= FLAGEFF;
+            }
+          else
+            {
+              frame->can_id = MASKSTDID & rf->id.std;
+            }
+
+          if (rf->cs.rtr)
+            {
+              frame->can_id |= FLAGRTR;
+            }
+
+          frame->can_dlc = rf->cs.dlc;
+
+          *(uint32_t *)&frame->data[0] = __builtin_bswap32(rf->data[0].w00);
+          *(uint32_t *)&frame->data[4] = __builtin_bswap32(rf->data[1].w00);
+
+          /* Clear MB interrupt flag */
+
+          putreg32(1 << mb_index,
+                   priv->base + KINETIS_CAN_IFLAG1_OFFSET);
+
+          /* Copy the buffer pointer to priv->dev..  Set amount of data
+           * in priv->dev.d_len
+           */
+
+          priv->dev.d_len = sizeof(struct can_frame);
+          priv->dev.d_buf = (uint8_t *)frame;
+        }
+
+      /* Send to socket interface */
+
+      NETDEV_RXPACKETS(&priv->dev);
+
+      can_input(&priv->dev);
+
+      /* Point the packet buffer back to the next Tx buffer that will be
+       * used during the next write.  If the write queue is full, then
+       * this will point at an active buffer, which must not be written
+       * to.  This is OK because devif_poll won't be called unless the
+       * queue is not full.
+       */
+
+      priv->dev.d_buf = (uint8_t *)priv->txdesc;
+
+      flags &= ~(1 << mb_index);
+
+      /* Reread interrupt flags and process them in this loop */
+
+      if (flags == 0)
+        {
+          flags  = getreg32(priv->base + KINETIS_CAN_IFLAG1_OFFSET);
+          flags &= IFLAG1_RX;
+        }
+    }
+}
+
+/****************************************************************************
+ * Function: kinetis_txdone
+ *
+ * Description:
+ *   An interrupt was received indicating that the last TX packet(s) is done
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by the watchdog logic.
+ *   We are not in an interrupt context so that we can lock the network.
+ *
+ ****************************************************************************/
+
+static void kinetis_txdone(FAR void *arg)
+{
+  FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)arg;
+  uint32_t flags;
+
+  flags  = getreg32(priv->base + KINETIS_CAN_IFLAG1_OFFSET);
+  flags &= IFLAG1_TX;
+
+  #warning Missing logic
+
+  /* FIXME First Process Error aborts */
+
+  /* Process TX completions */
+
+  uint32_t mb_bit = 1 << RXMBCOUNT;
+  for (uint32_t mbi = 0; flags && mbi < TXMBCOUNT; mbi++)
+    {
+      if (flags & mb_bit)
+        {
+          putreg32(mb_bit, priv->base + KINETIS_CAN_IFLAG1_OFFSET);
+          flags &= ~mb_bit;
+          NETDEV_TXDONE(&priv->dev);
+#ifdef TX_TIMEOUT_WQ
+          /* We are here because a transmission completed, so the
+           * corresponding watchdog can be canceled.
+           */
+
+          wd_cancel(priv->txtimeout[mbi]);
+#endif
+        }
+
+      mb_bit <<= 1;
+    }
+
+  /* There should be space for a new TX in any event.  Poll the network for
+   * new XMIT data
+   */
+
+  net_lock();
+  devif_poll(&priv->dev, kinetis_txpoll);
+  net_unlock();
+  up_enable_irq(priv->config->mb_irq);
+}
+
+/****************************************************************************
+ * Function: kinetis_flexcan_interrupt
+ *
+ * Description:
+ *   Three interrupt sources will vector this this function:
+ *   1. CAN MB transmit interrupt handler
+ *   2. CAN MB receive interrupt handler
+ *   3.
+ *
+ * Input Parameters:
+ *   irq     - Number of the IRQ that generated the interrupt
+ *   context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int kinetis_flexcan_interrupt(int irq, FAR void *context,
+                                     FAR void *arg)
+{
+  FAR struct kinetis_driver_s *priv = (struct kinetis_driver_s *)arg;
+
+  if (irq == priv->config->mb_irq)
+    {
+      uint32_t flags;
+      flags  = getreg32(priv->base + KINETIS_CAN_IFLAG1_OFFSET);
+      flags &= IFLAG1_RX;
+
+      if (flags)
+        {
+          /* Process immediately since scheduling a workqueue is too slow
+           * which causes us to drop CAN frames
+           */
+
+          kinetis_receive(priv, flags);
+        }
+
+      flags  = getreg32(priv->base + KINETIS_CAN_IFLAG1_OFFSET);
+      flags &= IFLAG1_TX;
+
+      if (flags)
+        {
+          /* Disable further CAN interrupts. here can be no race
+           * condition here.
+           */
+
+          up_disable_irq(priv->config->mb_irq);
+          work_queue(CANWORK, &priv->irqwork, kinetis_txdone, priv, 0);
+        }
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: kinetis_txtimeout_work
+ *
+ * Description:
+ *   Perform TX timeout related work from the worker thread
+ *
+ * Input Parameters:
+ *   arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+#ifdef TX_TIMEOUT_WQ
+
+static void kinetis_txtimeout_work(FAR void *arg)
+{
+  FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)arg;
+
+  struct timespec ts;
+  struct timeval *now = (struct timeval *)&ts;
+  clock_systimespec(&ts);
+  now->tv_usec = ts.tv_nsec / 1000; /* timespec to timeval conversion */
+
+  /* The watchdog timed out, yet we still check mailboxes in case the
+   * transmit function transmitted a new frame
+   */
+
+  for (int mbi = 0; mbi < TXMBCOUNT; mbi++)
+    {
+      if (priv->txmb[mbi].deadline.tv_sec != 0
+          && (now->tv_sec > priv->txmb[mbi].deadline.tv_sec
+          || now->tv_usec > priv->txmb[mbi].deadline.tv_usec))
+        {
+          NETDEV_TXTIMEOUTS(&priv->dev);
+          struct mb_s *mb = &priv->tx[mbi];
+          mb->cs.code = CAN_TXMB_ABORT;
+          priv->txmb[mbi].pending = TX_ABORT;
+        }
+    }
+}
+
+/****************************************************************************
+ * Function: kinetis_txtimeout_expiry
+ *
+ * Description:
+ *   Our TX watchdog timed out.  Called from the timer interrupt handler.
+ *   The last TX never completed.  Reset the hardware and start again.
+ *
+ * Input Parameters:
+ *   argc - The number of available arguments
+ *   arg  - The first argument
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Global interrupts are disabled by the watchdog logic.
+ *
+ ****************************************************************************/
+
+static void kinetis_txtimeout_expiry(int argc, uint32_t arg, ...)
+{
+  FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)arg;
+
+  /* Schedule to perform the TX timeout processing on the worker thread
+   */
+
+  work_queue(CANWORK, &priv->irqwork, kinetis_txtimeout_work, priv, 0);
+}
+
+#endif
+
+static void kinetis_setenable(uint32_t base, uint32_t enable)
+{
+  uint32_t regval;
+
+  if (enable)
+    {
+      regval  = getreg32(base + KINETIS_CAN_MCR_OFFSET);
+      regval &= ~(CAN_MCR_MDIS);
+      putreg32(regval, base + KINETIS_CAN_MCR_OFFSET);
+    }
+  else
+    {
+      regval  = getreg32(base + KINETIS_CAN_MCR_OFFSET);
+      regval |= CAN_MCR_MDIS;
+      putreg32(regval, base + KINETIS_CAN_MCR_OFFSET);
+    }
+
+  kinetis_waitmcr_change(base, CAN_MCR_LPMACK, 1);
+}
+
+static void kinetis_setfreeze(uint32_t base, uint32_t freeze)
+{
+  uint32_t regval;
+  if (freeze)
+    {
+      /* Enter freeze mode */
+
+      regval  = getreg32(base + KINETIS_CAN_MCR_OFFSET);
+      regval |= (CAN_MCR_HALT | CAN_MCR_FRZ);
+      putreg32(regval, base + KINETIS_CAN_MCR_OFFSET);
+    }
+  else
+    {
+      /* Exit freeze mode */
+
+      regval  = getreg32(base + KINETIS_CAN_MCR_OFFSET);
+      regval &= ~(CAN_MCR_HALT | CAN_MCR_FRZ);
+      putreg32(regval, base + KINETIS_CAN_MCR_OFFSET);
+    }
+}
+
+static uint32_t kinetis_waitmcr_change(uint32_t base, uint32_t mask,
+                                       uint32_t target_state)
+{
+  const unsigned timeout = 1000;
+  for (unsigned wait_ack = 0; wait_ack < timeout; wait_ack++)
+    {
+      const bool state = (getreg32(base + KINETIS_CAN_MCR_OFFSET) & mask)
+          != 0;
+      if (state == target_state)
+        {
+          return true;
+        }
+
+      up_udelay(10);
+    }
+
+  return false;
+}
+
+static uint32_t kinetis_waitfreezeack_change(uint32_t base,
+                                             uint32_t target_state)
+{
+  return kinetis_waitmcr_change(base, CAN_MCR_FRZACK, target_state);
+}
+
+/****************************************************************************
+ * Function: kinetis_ifup
+ *
+ * Description:
+ *   NuttX Callback: Bring up the Ethernet interface when an IP address is
+ *   provided
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int kinetis_ifup(struct net_driver_s *dev)
+{
+  FAR struct kinetis_driver_s *priv =
+    (FAR struct kinetis_driver_s *)dev->d_private;
+
+  if (!kinetis_initialize(priv))
+    {
+      nerr("initialize failed");
+      return -1;
+    }
+
+  priv->bifup = true;
+
+#ifdef CONFIG_NET_CAN_CANFD
+  priv->txdesc = (struct canfd_frame *)&g_tx_pool;
+  priv->rxdesc = (struct canfd_frame *)&g_rx_pool;
+#else
+  priv->txdesc = (struct can_frame *)&g_tx_pool;
+  priv->rxdesc = (struct can_frame *)&g_rx_pool;
+#endif
+
+  priv->dev.d_buf = (uint8_t *)priv->txdesc;
+
+  /* Set interrupts */
+
+  up_enable_irq(priv->config->bus_irq);
+  up_enable_irq(priv->config->error_irq);
+  if (priv->config->lprx_irq > 0)
+    {
+      up_enable_irq(priv->config->lprx_irq);
+    }
+
+  up_enable_irq(priv->config->mb_irq);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: kinetis_ifdown
+ *
+ * Description:
+ *   NuttX Callback: Stop the interface.
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int kinetis_ifdown(struct net_driver_s *dev)
+{
+  FAR struct kinetis_driver_s *priv =
+    (FAR struct kinetis_driver_s *)dev->d_private;
+
+  kinetis_reset(priv);
+
+  priv->bifup = false;
+  return OK;
+}
+
+/****************************************************************************
+ * Function: kinetis_txavail_work
+ *
+ * Description:
+ *   Perform an out-of-cycle poll on the worker thread.
+ *
+ * Input Parameters:
+ *   arg - Reference to the NuttX driver state structure (cast to void*)
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called on the higher priority worker thread.
+ *
+ ****************************************************************************/
+
+static void kinetis_txavail_work(FAR void *arg)
+{
+  FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)arg;
+
+  /* Ignore the notification if the interface is not yet up */
+
+  net_lock();
+  if (priv->bifup)
+    {
+      /* Check if there is room in the hardware to hold another outgoing
+       * packet.
+       */
+
+      if (!kinetis_txringfull(priv))
+        {
+          /* No, there is space for another transfer.  Poll the network for
+           * new XMIT data.
+           */
+
+          devif_poll(&priv->dev, kinetis_txpoll);
+        }
+    }
+
+  net_unlock();
+}
+
+/****************************************************************************
+ * Function: kinetis_txavail
+ *
+ * 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.
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called in normal user mode
+ *
+ ****************************************************************************/
+
+static int kinetis_txavail(struct net_driver_s *dev)
+{
+  FAR struct kinetis_driver_s *priv =
+    (FAR struct kinetis_driver_s *)dev->d_private;
+
+  /* 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(&priv->pollwork))
+    {
+      /* Schedule to serialize the poll on the worker thread. */
+
+      kinetis_txavail_work(priv);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: kinetis_ioctl
+ *
+ * Description:
+ *   PHY ioctl command handler
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *   cmd  - ioctl command
+ *   arg  - Argument accompanying the command
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL
+static int kinetis_ioctl(struct net_driver_s *dev, int cmd,
+                         unsigned long arg)
+{
+  FAR struct kinetis_driver_s *priv =
+      (FAR struct kinetis_driver_s *)dev->d_private;
+
+  int ret;
+
+  switch (cmd)
+    {
+      case SIOCGCANBITRATE: /* Get bitrate from a CAN controller */
+        {
+          struct can_ioctl_data_s *req =
+              (struct can_ioctl_data_s *)((uintptr_t)arg);
+          req->arbi_bitrate = priv->arbi_timing.bitrate / 1000; /* kbit/s */
+          req->arbi_samplep = priv->arbi_timing.samplep;
+#ifdef CONFIG_NET_CAN_CANFD
+          req->data_bitrate = priv->data_timing.bitrate / 1000; /* kbit/s */
+          req->data_samplep = priv->data_timing.samplep;
+#else
+          req->data_bitrate = 0;
+          req->data_samplep = 0;
+#endif
+          ret = OK;
+        }
+        break;
+
+      case SIOCSCANBITRATE: /* Set bitrate of a CAN controller */
+        {
+          struct can_ioctl_data_s *req =
+              (struct can_ioctl_data_s *)((uintptr_t)arg);
+
+          struct flexcan_timeseg arbi_timing;
+          arbi_timing.bitrate = req->arbi_bitrate * 1000;
+          arbi_timing.samplep = req->arbi_samplep;
+
+          if (kinetis_bitratetotimeseg(&arbi_timing, 10, 0))
+            {
+              ret = OK;
+            }
+          else
+            {
+              ret = -EINVAL;
+            }
+
+#ifdef CONFIG_NET_CAN_CANFD
+          struct flexcan_timeseg data_timing;
+          data_timing.bitrate = req->data_bitrate * 1000;
+          data_timing.samplep = req->data_samplep;
+
+          if (ret == OK && kinetis_bitratetotimeseg(&data_timing, 10, 1))
+            {
+              ret = OK;
+            }
+          else
+            {
+              ret = -EINVAL;
+            }
+#endif
+
+          if (ret == OK)
+            {
+              /* Reset CAN controller and start with new timings */
+
+              priv->arbi_timing = arbi_timing;
+#ifdef CONFIG_NET_CAN_CANFD
+              priv->data_timing = data_timing;
+#endif
+              kinetis_ifup(dev);
+            }
+        }
+        break;
+
+      default:
+        ret = -ENOTTY;
+        break;
+    }
+
+  return ret;
+}
+#endif /* CONFIG_NETDEV_IOCTL */
+
+/****************************************************************************
+ * Function: kinetis_initalize
+ *
+ * Description:
+ *   Initialize FLEXCAN device
+ *
+ * Input Parameters:
+ *   priv - Reference to the private FLEXCAN driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int kinetis_initialize(struct kinetis_driver_s *priv)
+{
+  uint32_t regval;
+  uint32_t i;
+
+  /* initialize CAN device */
+
+  kinetis_setenable(priv->base, 0);
+
+  /* Set SYS_CLOCK src */
+
+  regval  = getreg32(priv->base + KINETIS_CAN_CTRL1_OFFSET);
+  regval &= ~CAN_CTRL1_CLKSRC;
+  putreg32(regval, priv->base + KINETIS_CAN_CTRL1_OFFSET);
+
+  kinetis_setenable(priv->base, 1);
+
+  kinetis_reset(priv);
+
+  /* Enter freeze mode */
+
+  kinetis_setfreeze(priv->base, 1);
+  if (!kinetis_waitfreezeack_change(priv->base, 1))
+    {
+      ninfo("FLEXCAN: freeze fail\r\n");
+      return -1;
+    }
+
+#ifndef CONFIG_NET_CAN_CANFD
+  regval  = getreg32(priv->base + KINETIS_CAN_CTRL1_OFFSET);
+  regval |= CAN_CTRL1_PRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
+            CAN_CTRL1_PROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
+            CAN_CTRL1_PSEG1(priv->arbi_timing.pseg1) |   /* Phase buffer segment 1 */
+            CAN_CTRL1_PSEG2(priv->arbi_timing.pseg2) |   /* Phase buffer segment 2 */
+            CAN_CTRL1_RJW(1);      /* Resynchronization jump width */
+  putreg32(regval, priv->base + KINETIS_CAN_CTRL1_OFFSET);
+
+#else
+  regval  = getreg32(priv->base + KINETIS_CAN_CBT_OFFSET);
+  regval |= CAN_CBT_BTF |         /* Enable extended bit timing
+                                   * configurations for CAN-FD for setting up
+                                   * separately nominal and data phase */
+            CAN_CBT_EPRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
+            CAN_CBT_EPROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
+            CAN_CBT_EPSEG1(priv->arbi_timing.pseg1) |   /* Phase buffer segment 1 */
+            CAN_CBT_EPSEG2(priv->arbi_timing.pseg2) |   /* Phase buffer segment 2 */
+            CAN_CBT_ERJW(1);      /* Resynchronization jump width */
+  putreg32(regval, priv->base + KINETIS_CAN_CBT_OFFSET);
+
+  /* Enable CAN FD feature */
+
+  regval  = getreg32(priv->base + KINETIS_CAN_MCR_OFFSET);
+  regval |= CAN_MCR_FDEN;
+  putreg32(regval, priv->base + KINETIS_CAN_MCR_OFFSET);
+
+  regval  = getreg32(priv->base + KINETIS_CAN_FDCBT_OFFSET);
+  regval |= CAN_FDCBT_FPRESDIV(priv->data_timing.presdiv) |  /* Prescaler divisor factor of 1 */
+            CAN_FDCBT_FPROPSEG(priv->data_timing.propseg) | /* Propagation
+                                                             * segment (only register that doesn't add 1) */
+            CAN_FDCBT_FPSEG1(priv->data_timing.pseg1) |    /* Phase buffer segment 1 */
+            CAN_FDCBT_FPSEG2(priv->data_timing.pseg2) |    /* Phase buffer segment 2 */
+            CAN_FDCBT_FRJW(priv->data_timing.pseg2);       /* Resynchorinzation jump width same as PSEG2 */
+  putreg32(regval, priv->base + KINETIS_CAN_FDCBT_OFFSET);
+
+  /* Additional CAN-FD configurations */
+
+  regval  = getreg32(priv->base + KINETIS_CAN_FDCTRL_OFFSET);
+
+  regval |= CAN_FDCTRL_FDRATE |     /* Enable bit rate switch in data phase of frame */
+            CAN_FDCTRL_TDCEN |      /* Enable transceiver delay compensation */
+            CAN_FDCTRL_TDCOFF(5) |  /* Setup 5 cycles for data phase sampling delay */
+            CAN_FDCTRL_MBDSR0(3);   /* Setup 64 bytes per message buffer (7 MB's) */
+  putreg32(regval, priv->base + KINETIS_CAN_FDCTRL_OFFSET);
+
+  regval  = getreg32(priv->base + KINETIS_CAN_CTRL2_OFFSET);
+  regval |= CAN_CTRL2_ISOCANFDEN;
+  putreg32(regval, priv->base + KINETIS_CAN_CTRL2_OFFSET);
+#endif
+
+  for (i = TXMBCOUNT; i < TOTALMBCOUNT; i++)
+    {
+      priv->rx[i].id.w = 0x0;
+
+      /* FIXME sometimes we get a hard fault here */
+    }
+
+  putreg32(0x0, priv->base + KINETIS_CAN_RXFGMASK_OFFSET);
+
+  for (i = 0; i < TOTALMBCOUNT; i++)
+    {
+      putreg32(0, priv->base + KINETIS_CAN_RXIMR_OFFSET(i));
+    }
+
+  for (i = 0; i < RXMBCOUNT; i++)
+    {
+      ninfo("Set MB%i to receive %p\r\n", i, &priv->rx[i]);
+      priv->rx[i].cs.edl = 0x1;
+      priv->rx[i].cs.brs = 0x1;
+      priv->rx[i].cs.esi = 0x0;
+      priv->rx[i].cs.code = 4;
+      priv->rx[i].cs.srr = 0x0;
+      priv->rx[i].cs.ide = 0x1;
+      priv->rx[i].cs.rtr = 0x0;
+    }
+
+  putreg32(IFLAG1_RX, priv->base + KINETIS_CAN_IFLAG1_OFFSET);
+  putreg32(IFLAG1_RX, priv->base + KINETIS_CAN_IMASK1_OFFSET);
+
+  /* Exit freeze mode */
+
+  kinetis_setfreeze(priv->base, 0);
+  if (!kinetis_waitfreezeack_change(priv->base, 0))
+    {
+      ninfo("FLEXCAN: unfreeze fail\r\n");
+      return -1;
+    }
+
+  return 1;
+}
+
+/****************************************************************************
+ * Function: kinetis_reset
+ *
+ * Description:
+ *   Put the EMAC in the non-operational, reset state
+ *
+ * Input Parameters:
+ *   priv - Reference to the private FLEXCAN driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void kinetis_reset(struct kinetis_driver_s *priv)
+{
+  uint32_t regval;
+  uint32_t i;
+
+  regval  = getreg32(priv->base + KINETIS_CAN_MCR_OFFSET);
+  regval |= CAN_MCR_SOFTRST;
+  putreg32(regval, priv->base + KINETIS_CAN_MCR_OFFSET);
+
+  if (!kinetis_waitmcr_change(priv->base, CAN_MCR_SOFTRST, 0))
+    {
+      nerr("Reset failed");
+      return;
+    }
+
+  regval  = getreg32(priv->base + KINETIS_CAN_MCR_OFFSET);
+  regval &= ~(CAN_MCR_SUPV);
+  putreg32(regval, priv->base + KINETIS_CAN_MCR_OFFSET);
+
+  /* Initialize all MB rx and tx */
+
+  for (i = 0; i < TOTALMBCOUNT; i++)
+    {
+      ninfo("MB %i %p\r\n", i, &priv->rx[i]);
+      ninfo("MB %i %p\r\n", i, &priv->rx[i].id.w);
+      priv->rx[i].cs.cs = 0x0;
+      priv->rx[i].id.w = 0x0;
+      priv->rx[i].data[0].w00 = 0x0;
+      priv->rx[i].data[1].w00 = 0x0;
+    }
+
+  regval  = getreg32(priv->base + KINETIS_CAN_MCR_OFFSET);
+  regval |= CAN_MCR_SLFWAK | CAN_MCR_WRNEN | CAN_MCR_SRXDIS |
+            CAN_MCR_IRMQ | CAN_MCR_AEN |
+            (((TOTALMBCOUNT - 1) << CAN_MCR_MAXMB_SHIFT) &
+            CAN_MCR_MAXMB_MASK);
+  putreg32(regval, priv->base + KINETIS_CAN_MCR_OFFSET);
+
+  regval  = CAN_CTRL2_RRS | CAN_CTRL2_EACEN;
+  putreg32(regval, priv->base + KINETIS_CAN_CTRL2_OFFSET);
+
+  for (i = 0; i < TOTALMBCOUNT; i++)
+    {
+      putreg32(0, priv->base + KINETIS_CAN_RXIMR_OFFSET(i));
+    }
+
+  /* Filtering catchall */
+
+  putreg32(0x3fffffff, priv->base + KINETIS_CAN_RX14MASK_OFFSET);
+  putreg32(0x3fffffff, priv->base + KINETIS_CAN_RX15MASK_OFFSET);
+  putreg32(0x3fffffff, priv->base + KINETIS_CAN_RXMGMASK_OFFSET);
+  putreg32(0x0, priv->base + KINETIS_CAN_RXFGMASK_OFFSET);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: kinetis_caninitialize
+ *
+ * Description:
+ *   Initialize the CAN controller and driver
+ *
+ * Input Parameters:
+ *   intf - In the case where there are multiple CAN, this value
+ *          identifies which CAN is to be initialized.
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+int kinetis_caninitialize(int intf)
+{
+  struct kinetis_driver_s *priv;
+  int ret;
+  uint32_t regval;
+
+  switch (intf)
+    {
+#ifdef CONFIG_KINETIS_FLEXCAN0
+    case 0:
+      priv               = &g_flexcan0;
+      memset(priv, 0, sizeof(struct kinetis_driver_s));
+      priv->base         = KINETIS_CAN0_BASE;
+      priv->config       = &kinetis_flexcan0_config;
+
+      /* Default bitrate configuration */
+
+#  ifdef CONFIG_NET_CAN_CANFD
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_ARBI_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN0_ARBI_SAMPLEP;
+      priv->data_timing.bitrate = CONFIG_FLEXCAN0_DATA_BITRATE;
+      priv->data_timing.samplep = CONFIG_FLEXCAN0_DATA_SAMPLEP;
+#  else
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN0_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN0_SAMPLEP;
+#  endif
+      regval = getreg32(KINETIS_SIM_SCGC6);
+      regval |= SIM_SCGC6_FLEXCAN0;
+      putreg32(regval, KINETIS_SIM_SCGC6);
+      break;
+#endif
+
+#ifdef CONFIG_KINETIS_FLEXCAN1
+    case 1:
+      priv         = &g_flexcan1;
+      memset(priv, 0, sizeof(struct kinetis_driver_s));
+      priv->base   = KINETIS_CAN1_BASE;
+      priv->config = &kinetis_flexcan1_config;
+
+      /* Default bitrate configuration */
+
+#  ifdef CONFIG_NET_CAN_CANFD
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_ARBI_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN1_ARBI_SAMPLEP;
+      priv->data_timing.bitrate = CONFIG_FLEXCAN1_DATA_BITRATE;
+      priv->data_timing.samplep = CONFIG_FLEXCAN1_DATA_SAMPLEP;
+#  else
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN1_SAMPLEP;
+#  endif
+      regval = getreg32(KINETIS_SIM_SCGC3);
+      regval |= SIM_SCGC3_FLEXCAN1;
+      putreg32(regval, KINETIS_SIM_SCGC3);
+      break;
+#endif
+
+#ifdef CONFIG_KINETIS_FLEXCAN2
+    case 2:
+      priv         = &g_flexcan2;
+      memset(priv, 0, sizeof(struct kinetis_driver_s));
+      priv->base   = KINETIS_CAN2_BASE;
+      priv->config = &kinetis_flexcan2_config;
+
+      /* Default bitrate configuration */
+
+#  ifdef CONFIG_NET_CAN_CANFD
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_ARBI_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN2_ARBI_SAMPLEP;
+      priv->data_timing.bitrate = CONFIG_FLEXCAN2_DATA_BITRATE;
+      priv->data_timing.samplep = CONFIG_FLEXCAN2_DATA_SAMPLEP;
+#  else
+      priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_BITRATE;
+      priv->arbi_timing.samplep = CONFIG_FLEXCAN2_SAMPLEP;
+#  endif
+      break;
+#endif
+
+    default:
+      return -ENODEV;
+    }
+
+  if (!kinetis_bitratetotimeseg(&priv->arbi_timing, 1, 0))
+    {
+      nerr("ERROR: Invalid CAN timings please try another sample point "
+           "or refer to the reference manual\n");
+      return -1;
+    }
+
+#ifdef CONFIG_NET_CAN_CANFD
+  if (!kinetis_bitratetotimeseg(&priv->data_timing, 1, 1))
+    {
+      nerr("ERROR: Invalid CAN data phase timings please try another "
+           "sample point or refer to the reference manual\n");
+      return -1;
+    }
+#endif
+
+  kinetis_pinconfig(priv->config->tx_pin);
+  kinetis_pinconfig(priv->config->rx_pin);
+  if (priv->config->enable_pin > 0)
+    {
+      kinetis_pinconfig(priv->config->enable_pin);
+      kinetis_gpiowrite(priv->config->enable_pin, priv->config->enable_high);
+    }
+
+  /* Attach the flexcan interrupt handler */
+
+  if (irq_attach(priv->config->bus_irq, kinetis_flexcan_interrupt, priv))
+    {
+      /* We could not attach the ISR to the interrupt */
+
+      nerr("ERROR: Failed to attach CAN bus IRQ\n");
+      return -EAGAIN;
+    }
+
+  if (irq_attach(priv->config->error_irq, kinetis_flexcan_interrupt, priv))
+    {
+      /* We could not attach the ISR to the interrupt */
+
+      nerr("ERROR: Failed to attach CAN error IRQ\n");
+      return -EAGAIN;
+    }
+
+  if (priv->config->lprx_irq > 0)
+    {
+      if (irq_attach(priv->config->lprx_irq,
+                     kinetis_flexcan_interrupt, priv))
+        {
+          /* We could not attach the ISR to the interrupt */
+
+          nerr("ERROR: Failed to attach CAN LPRX IRQ\n");
+          return -EAGAIN;
+        }
+    }
+
+  if (irq_attach(priv->config->mb_irq, kinetis_flexcan_interrupt, priv))
+    {
+      /* We could not attach the ISR to the interrupt */
+
+      nerr("ERROR: Failed to attach CAN OR'ed Message buffer (0-15) IRQ\n");
+      return -EAGAIN;
+    }
+
+  /* Initialize the driver structure */
+
+  priv->dev.d_ifup    = kinetis_ifup;      /* I/F up (new IP address) callback */
+  priv->dev.d_ifdown  = kinetis_ifdown;    /* I/F down callback */
+  priv->dev.d_txavail = kinetis_txavail;   /* New TX data callback */
+#ifdef CONFIG_NETDEV_IOCTL
+  priv->dev.d_ioctl   = kinetis_ioctl;     /* Support CAN ioctl() calls */
+#endif
+  priv->dev.d_private = (void *)priv;      /* Used to recover private state from dev */
+
+#ifdef TX_TIMEOUT_WQ
+  for (int i = 0; i < TXMBCOUNT; i++)
+    {
+      priv->txtimeout[i] = wd_create();    /* Create TX timeout timer */
+    }
+
+#endif
+  priv->rx            = (struct mb_s *)(priv->base + KINETIS_CAN_MB_OFFSET);
+  priv->tx            = (struct mb_s *)(priv->base + KINETIS_CAN_MB_OFFSET +
+                          (sizeof(struct mb_s) * RXMBCOUNT));
+
+  /* Put the interface in the down state.  This usually amounts to resetting
+   * the device and/or calling kinetis_ifdown().
+   */
+
+  ninfo("callbacks done\r\n");
+
+  kinetis_ifdown(&priv->dev);
+
+  /* Register the device with the OS so that socket IOCTLs can be performed */
+
+  netdev_register(&priv->dev, NET_LL_CAN);
+
+  UNUSED(ret);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: arm_netinitialize
+ *
+ * Description:
+ *   Initialize the first network interface.  If there are more than one
+ *   interface in the chip, then board-specific logic will have to provide
+ *   this function to determine which, if any, Ethernet controllers should
+ *   be initialized.
+ *
+ ****************************************************************************/
+
+#if !defined(CONFIG_NETDEV_LATEINIT)
+void arm_netinitialize(void)
+{
+#ifdef CONFIG_KINETIS_FLEXCAN0
+  kinetis_caninitialize(0);
+#endif
+
+#ifdef CONFIG_KINETIS_FLEXCAN1
+  kinetis_caninitialize(1);
+#endif
+
+#ifdef CONFIG_KINETIS_FLEXCAN2
+  kinetis_caninitialize(2);
+#endif
+}
+#endif
+
+#endif /* CONFIG_KINETIS_FLEXCAN */