summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-10-21 15:52:23 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-10-21 15:52:23 -0600
commit7be7e670323816f671e6bed7ec282251754602b3 (patch)
treeb6e00d008008b19fd2c9b13ab332b7835ea6c343
parent7cdfdd72aeed9499a474a9623219b610d9ce2c09 (diff)
downloadpx4-nuttx-7be7e670323816f671e6bed7ec282251754602b3.tar.gz
px4-nuttx-7be7e670323816f671e6bed7ec282251754602b3.tar.bz2
px4-nuttx-7be7e670323816f671e6bed7ec282251754602b3.zip
SAMA5: Beginning of a CAN driver
-rw-r--r--nuttx/ChangeLog3
-rw-r--r--nuttx/arch/arm/src/sama5/chip/sam_can.h6
-rw-r--r--nuttx/arch/arm/src/sama5/sam_can.c1331
-rw-r--r--nuttx/arch/arm/src/sama5/sam_can.h113
4 files changed, 1452 insertions, 1 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 7bb02fb47..c1de17d56 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -5841,3 +5841,6 @@
warnings from GCC (2013-10-21).
* arch/arm/src/sama5/chip/sam_can.h: SAMA5D3X CAN register definition
header file (2013-10-21)
+ * arch/arm/src/sama5/sam_can.c and .h: Framework for a SAMA5 CAN drvier.
+ Initial checkin is the STM32 CAN driver with name changes (2013-10-21).
+
diff --git a/nuttx/arch/arm/src/sama5/chip/sam_can.h b/nuttx/arch/arm/src/sama5/chip/sam_can.h
index 3c55cd8c2..04e45736b 100644
--- a/nuttx/arch/arm/src/sama5/chip/sam_can.h
+++ b/nuttx/arch/arm/src/sama5/chip/sam_can.h
@@ -47,7 +47,8 @@
* Pre-processor Definitions
************************************************************************************/
-#define SAM_CAN_NMAILBOXES 8
+#define SAM_CAN_NMAILBOXES 8
+#define SAM_CAN_MAXPERCLK 66000000
/* CAN Register Offsets *************************************************************/
@@ -163,6 +164,7 @@
#define CAN_INT_MB5 (1 << 5) /* Bit 5: Mailbox 5 Event */
#define CAN_INT_MB6 (1 << 6) /* Bit 6: Mailbox 6 Event */
#define CAN_INT_MB7 (1 << 7) /* Bit 7: Mailbox 7 Event */
+#define CAN_INT_MBALL (0x000000ff)
#define CAN_INT_ERRA (1 << 16) /* Bit 16: Error Active Mode */
#define CAN_INT_WARN (1 << 17) /* Bit 17: Warning Limit */
@@ -200,6 +202,8 @@
#define CAN_BR_BRP_MASK (0x7f << CAN_BR_BRP_SHIFT)
# define CAN_BR_BRP(n) ((uint32_t)(n) << CAN_BR_BRP_SHIFT)
#define CAN_BR_SMP (1 << 24) /* Bit 24: Sampling Mode */
+# define CAN_BR_ONCE (0) /* Bit 24: 0:Bit stream sampled once at sample point */
+# define CAN_BR_THREE CAN_BR_SMP /* Bit 24: 1:Sampling three times */
/* Timer Register */
diff --git a/nuttx/arch/arm/src/sama5/sam_can.c b/nuttx/arch/arm/src/sama5/sam_can.c
new file mode 100644
index 000000000..dc76e0e96
--- /dev/null
+++ b/nuttx/arch/arm/src/sama5/sam_can.c
@@ -0,0 +1,1331 @@
+/************************************************************************************
+ * arch/arm/src/sama5/sam_can.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * References:
+ *
+ * SAMA5D3 Series Data Sheet
+ * Atmel NoOS sample code.
+ *
+ * The Atmel sample code has a BSD compatibile license that requires this
+ * copyright notice:
+ *
+ * Copyright (c) 2012, Atmel Corporation
+ *
+ * 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, Atmel, 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 <stdio.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arch/board/board.h>
+#include <nuttx/arch.h>
+#include <nuttx/can.h>
+
+#include "up_internal.h"
+#include "up_arch.h"
+
+#include "os_internal.h"
+
+#include "chip/sam_pinmap.h"
+#include "sam_periphclks.h"
+#include "sam_pio.h"
+#include "sam_can.h"
+
+#if defined(CONFIG_CAN) && (defined(CONFIG_SAMA5_CAN0) || defined(CONFIG_SAMA5_CAN1))
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Delays *******************************************************************/
+/* Time out for INAK bit */
+
+#define INAK_TIMEOUT 65535
+
+/* Mailboxes ****************************************************************/
+
+/* Bit timing ***************************************************************/
+
+/* Clocking */
+
+#if BOARD_MCK_FREQUENCY <= SAM_CAN_MAXPERCLK
+# define CAN_FREQUENCY BOARD_MCK_FREQUENCY
+# define CAN_PCR_DIV PMC_PCR_DIV1
+#elif (BOARD_MCK_FREQUENCY >> 1) <= SAM_CAN_MAXPERCLK
+# define CAN_FREQUENCY (BOARD_MCK_FREQUENCY >> 1)
+# define CAN_PCR_DIV PMC_PCR_DIV2
+#elif (BOARD_MCK_FREQUENCY >> 2) <= SAM_CAN_MAXPERCLK
+# define CAN_FREQUENCY (BOARD_MCK_FREQUENCY >> 2)
+# define CAN_PCR_DIV PMC_PCR_DIV4
+#elif (BOARD_MCK_FREQUENCY >> 3) <= SAM_CAN_MAXPERCLK
+# define CAN_FREQUENCY (BOARD_MCK_FREQUENCY >> 3)
+# define CAN_PCR_DIV PMC_PCR_DIV8
+#else
+# error Cannot realize ADC input frequency
+#endif
+
+#define CAN_BIT_QUANTA (CONFIG_CAN_TSEG1 + CONFIG_CAN_TSEG2 + 1)
+
+/* Debug ********************************************************************/
+/* Non-standard debug that may be enabled just for testing CAN */
+
+#ifdef CONFIG_DEBUG_CAN
+# define candbg dbg
+# define canvdbg vdbg
+# define canlldbg lldbg
+# define canllvdbg llvdbg
+#else
+# define candbg(x...)
+# define canvdbg(x...)
+# define canlldbg(x...)
+# define canllvdbg(x...)
+#endif
+
+#if !defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_CAN)
+# undef CONFIG_CAN_REGDEBUG
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct sam_can_s
+{
+ uint8_t port; /* CAN port number (1 or 2) */
+ uint8_t pid; /* CAN periperal ID/IRQ number */
+ xcpt_t handler; /* CAN interrupt handler */
+ uintptr_t base; /* Base address of the CAN control registers */
+ uint32_t baud; /* Configured baud */
+ pio_pinset_t rxpinset; /* RX pin configuration */
+ pio_pinset_t txpinset; /* TX pin configuration */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* CAN Register access */
+
+static uint32_t can_getreg(struct sam_can_s *priv, int offset);
+static void can_putreg(struct sam_can_s *priv, int offset, uint32_t regval);
+#ifdef CONFIG_CAN_REGDEBUG
+static void can_dumpctrlregs(struct sam_can_s *priv, FAR const char *msg);
+static void can_dumpmbregs(struct sam_can_s *priv, FAR const char *msg);
+#else
+# define can_dumpctrlregs(priv,msg)
+# define can_dumpmbregs(priv,msg)
+#endif
+
+/* CAN driver methods */
+
+static void can_reset(FAR struct can_dev_s *dev);
+static int can_setup(FAR struct can_dev_s *dev);
+static void can_shutdown(FAR struct can_dev_s *dev);
+static void can_rxint(FAR struct can_dev_s *dev, bool enable);
+static void can_txint(FAR struct can_dev_s *dev, bool enable);
+static int can_ioctl(FAR struct can_dev_s *dev, int cmd, unsigned long arg);
+static int can_remoterequest(FAR struct can_dev_s *dev, uint16_t id);
+static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg);
+static bool can_txready(FAR struct can_dev_s *dev);
+static bool can_txempty(FAR struct can_dev_s *dev);
+
+/* CAN interrupt handling */
+
+static void can_interrupt(struct sam_can_s *priv);
+#ifdef CONFIG_SAMA5_CAN0
+static int can0_interrupt(int irq, void *context);
+#endif
+#ifdef CONFIG_SAMA5_CAN1
+static int can1_interrupt(int irq, void *context);
+#endif
+#if defined(CONFIG_CAN) && (defined() || defined())
+
+/* Initialization */
+
+static int can_bittiming(struct sam_can_s *priv);
+static int can_hwinitialize(struct sam_can_s *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct can_ops_s g_canops =
+{
+ .co_reset = can_reset,
+ .co_setup = can_setup,
+ .co_shutdown = can_shutdown,
+ .co_rxint = can_rxint,
+ .co_txint = can_txint,
+ .co_ioctl = can_ioctl,
+ .co_remoterequest = can_remoterequest,
+ .co_send = can_send,
+ .co_txready = can_txready,
+ .co_txempty = can_txempty,
+};
+
+#ifdef CONFIG_SAMA5_CAN0
+static const struct sam_can_s g_can0priv =
+{
+ .port = 0,
+ .pid = SAM_PID_CAN0,
+ .handler = can0_interrupt,
+ .base = SAM_CAN0_VBASE,
+ .baud = CONFIG_CAN0_BAUD,
+ .rxpinset = PIO_CAN0_RX;
+ .txpinset = PIO_CAN0_TX;
+};
+
+static struct can_dev_s g_can0dev =
+{
+ .cd_ops = &g_canops,
+ .cd_priv = (void *)&g_can0priv,
+};
+#endif
+
+#ifdef CONFIG_SAMA5_CAN1
+static const struct sam_can_s g_can1priv =
+{
+ .port = 1,
+ .pid = SAM_PID_CAN1,
+ .handler = can1_interrupt,
+ .base = SAM_CAN1_VBASE,
+ .baud = CONFIG_CAN1_BAUD,
+ .rxpinset = PIO_CAN1_RX;
+ .txpinset = PIO_CAN1_TX;
+};
+
+static struct can_dev_s g_can1dev =
+{
+ .cd_ops = &g_canops,
+ .cd_priv = (void *)&g_can1priv,
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_getreg
+ *
+ * Description:
+ * Read the value of a CAN register.
+ *
+ * Input Parameters:
+ * priv - A reference to the CAN block status
+ * offset - The offset to the register to read
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_CAN_REGDEBUG
+static uint32_t can_getreg(struct sam_can_s *priv, int offset)
+{
+ static uintptr_t prevaddr = 0;
+ static uint32_t preval = 0;
+ static unsigned int count = 0;
+ uintptr_t regaddr;
+ uint32_t regval;
+
+ /* Read the value from the register */
+
+ regaddr = priv->base + offset;
+ regval = getreg32(regaddr);
+
+ /* Is this the same value that we read from the same register last time?
+ * Are we polling the register? If so, suppress some of the output.
+ */
+
+ if (regaddr == prevaddr && regval == preval)
+ {
+ if (count == 0xffffffff || ++count > 3)
+ {
+ if (count == 4)
+ {
+ lldbg("...\n");
+ }
+ return regval;
+ }
+ }
+
+ /* No this is a new address or value */
+
+ else
+ {
+ /* Did we print "..." for the previous value? */
+
+ if (count > 3)
+ {
+ /* Yes.. then show how many times the value repeated */
+
+ lldbg("[repeats %d more times]\n", count-3);
+ }
+
+ /* Save the new address, value, and count */
+
+ prevaddr = regaddr;
+ preval = regval;
+ count = 1;
+ }
+
+ /* Show the register value read */
+
+ lldbg("%08x->%08x\n", addr, regval);
+ return regval;
+}
+
+#else
+static uint32_t can_getreg(struct sam_can_s *priv, int offset)
+{
+ return getreg32(priv->base + offset);
+}
+
+#endif
+
+/****************************************************************************
+ * Name: can_putreg
+ *
+ * Description:
+ * Set the value of a CAN register.
+ *
+ * Input Parameters:
+ * priv - A reference to the CAN block status
+ * offset - The offset to the register to write
+ * regval - The value to write to the register
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_CAN_REGDEBUG
+static void can_putreg(struct sam_can_s *priv, int offset, uint32_t regval)
+{
+ uintptr_t regaddr = priv->base + offset;
+
+ /* Show the register value being written */
+
+ lldbg("%08x<-%08x\n", regaddr, regval);
+
+ /* Write the value */
+
+ putreg32(regval, regaddr);
+}
+
+#else
+static void can_putreg(struct sam_can_s *priv, int offset, uint32_t regval)
+{
+ putreg32(regval, priv->base + offset);
+}
+
+#endif
+
+/****************************************************************************
+ * Name: can_dumpctrlregs
+ *
+ * Description:
+ * Dump the contents of all CAN control registers
+ *
+ * Input Parameters:
+ * priv - A reference to the CAN block status
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_CAN_REGDEBUG
+static void can_dumpctrlregs(struct sam_can_s *priv, FAR const char *msg)
+{
+ if (msg)
+ {
+ canlldbg("Control Registers: %s\n", msg);
+ }
+ else
+ {
+ canlldbg("Control Registers:\n");
+ }
+
+ /* CAN control and status registers */
+
+ lldbg(" MR: %08x IMR: %08x SR: %08x\n",
+ getreg32(priv->base + SAM_CAN_MR_OFFSET),
+ getreg32(priv->base + SAM_CAN_IMR_OFFSET),
+ getreg32(priv->base + SAM_CAN_SR_OFFSET));
+
+ lldbg(" BR: %08x TIM: %08x TIMESTP: %08x\n",
+ getreg32(priv->base + SAM_CAN_BR_OFFSET),
+ getreg32(priv->base + SAM_CAN_TIM_OFFSET),
+ getreg32(priv->base + SAM_CAN_TIMESTP_OFFSET));
+
+ lldbg(" ECR: %08x WPMR: %08x WPSR: %08x\n",
+ getreg32(priv->base + SAM_CAN_ECR_OFFSET),
+ getreg32(priv->base + SAM_CAN_TCR_OFFSET),
+ getreg32(priv->base + SAM_CAN_ACR_OFFSET));
+}
+#endif
+
+/****************************************************************************
+ * Name: can_dumpmbregs
+ *
+ * Description:
+ * Dump the contents of all CAN mailbox registers
+ *
+ * Input Parameters:
+ * priv - A reference to the CAN block status
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_CAN_REGDEBUG
+static void can_dumpmbregs(struct sam_can_s *priv, FAR const char *msg)
+{
+ uintptr_t mbbase;
+ int i;
+
+ if (msg)
+ {
+ canlldbg("Mailbox Registers: %s\n", msg);
+ }
+ else
+ {
+ canlldbg("Mailbox Registers:\n");
+ }
+
+ for (i = 0; i < SAM_CAN_NMAILBOXES; i++)
+ {
+ mbbase = priv->base + SAM_CAN_MBn_OFFSET(i);
+ lldbg(" MB%d:\n", i);
+
+ /* CAN mailbox registers */
+
+ lldbg(" MMR: %08x MAM: %08x MID: %08x MFID: %08x\n",
+ getreg32(mbbase + SAM_CAN_MMR_OFFSET),
+ getreg32(mbbase + SAM_CAN_MAM_OFFSET),
+ getreg32(mbbase + SAM_CAN_MID_OFFSET),
+ getreg32(mbbase + SAM_CAN_MFID_OFFSET));
+
+ lldbg(" MSR: %08x MDL: %08x MDH: %08x\n",
+ getreg32(mbbase + SAM_CAN_MSR_OFFSET),
+ getreg32(mbbase + SAM_CAN_MDL_OFFSET),
+ getreg32(mbbase + SAM_CAN_MDH_OFFSET));
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: can_reset
+ *
+ * Description:
+ * Reset the CAN device. Called early to initialize the hardware. This
+ * function is called, before can_setup() and on error conditions.
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void can_reset(FAR struct can_dev_s *dev)
+{
+ FAR struct sam_can_s *priv = dev->cd_priv;
+ uint32_t regval;
+ uint32_t regbit = 0;
+ irqstate_t flags;
+
+ canllvdbg("CAN%d\n", priv->port);
+
+ /* Get the bits in the AHB1RSTR register needed to reset this CAN device */
+
+#ifdef CONFIG_SAMA5_CAN0
+ if (priv->port == 1)
+ {
+#warning Missing logic
+ }
+ else
+#endif
+#ifdef CONFIG_SAMA5_CAN1
+ if (priv->port == 2)
+ {
+#warning Missing logic
+ }
+ else
+#endif
+ {
+ canlldbg("Unsupported port %d\n", priv->port);
+ return;
+ }
+
+ /* Disable interrupts momentary to stop any ongoing CAN event processing and
+ * to prevent any concurrent access to the AHB1RSTR register.
+ */
+
+ flags = irqsave();
+
+ /* Reset the CAN */
+#warning Missing logic
+
+ irqrestore(flags);
+}
+
+/****************************************************************************
+ * Name: can_setup
+ *
+ * Description:
+ * Configure the CAN. This method is called the first time that the CAN
+ * device is opened. This will occur when the port is first opened.
+ * This setup includes configuring and attaching CAN interrupts.
+ * All CAN interrupts are disabled upon return.
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int can_setup(FAR struct can_dev_s *dev)
+{
+ FAR struct sam_can_s *priv = dev->cd_priv;
+ int ret;
+
+ canllvdbg("CAN%d pid: %d\n", priv->port, priv->pid);
+
+ /* CAN hardware initialization */
+
+ ret = can_hwinitialize(priv);
+ if (ret < 0)
+ {
+ canlldbg("CAN%d H/W initialization failed: %d\n", priv->port, ret);
+ return ret;
+ }
+
+ can_dumpctrlregs(priv, "After cell initialization");
+ can_dumpmbregs(priv, NULL);
+
+ /* Attach the CAN interrupt handler */
+
+ ret = irq_attach(priv->pid, priv->handler);
+ if (ret < 0)
+ {
+ canlldbg("Failed to attach CAN%d IRQ (%d)", priv->port, priv->pid);
+ return ret;
+ }
+
+ /* Enable the interrupts at the NVIC. Interrupts arestill disabled in
+ * the CAN module. Since we coming out of reset here, there should be
+ * no pending interrupts.
+ */
+
+ up_enable_irq(priv->pid);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: can_shutdown
+ *
+ * Description:
+ * Disable the CAN. This method is called when the CAN device is closed.
+ * This method reverses the operation the setup method.
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void can_shutdown(FAR struct can_dev_s *dev)
+{
+ FAR struct sam_can_s *priv = dev->cd_priv;
+
+ canllvdbg("CAN%d\n", priv->port);
+
+ /* Disable the CAN interrupts */
+
+ up_disable_irq(priv->pid);
+
+ /* Detach the CAN interrupt handler */
+
+ irq_detach(priv->pid);
+
+ /* And reset the hardware */
+
+ can_reset(dev);
+}
+
+/****************************************************************************
+ * Name: can_rxint
+ *
+ * Description:
+ * Call to enable or disable RX interrupts.
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void can_rxint(FAR struct can_dev_s *dev, bool enable)
+{
+ FAR struct sam_can_s *priv = dev->cd_priv;
+
+ canllvdbg("CAN%d enable: %d\n", priv->port, enable);
+
+ /* Enable/disable the message pending interrupt */
+
+ if (enable)
+ {
+ sam_putreg(xxxx, SAM_CAN_IER_OFFSET);
+#warning Missing logic
+ }
+ else
+ {
+ sam_putreg(xxxx, SAM_CAN_IDR_OFFSET);
+#warning Missing logic
+ }
+}
+
+/****************************************************************************
+ * Name: can_txint
+ *
+ * Description:
+ * Call to enable or disable TX interrupts.
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void can_txint(FAR struct can_dev_s *dev, bool enable)
+{
+ FAR struct sam_can_s *priv = dev->cd_priv;
+
+ canllvdbg("CAN%d enable: %d\n", priv->port, enable);
+
+ /* Support only disabling the transmit mailbox interrupt */
+#warning Missing logic
+
+ if (enable)
+ {
+ sam_putreg(xxxx, SAM_CAN_IER_OFFSET);
+#warning Missing logic
+ }
+ else
+ {
+ sam_putreg(xxxx, SAM_CAN_IDR_OFFSET);
+#warning Missing logic
+ }
+}
+
+/****************************************************************************
+ * Name: can_ioctl
+ *
+ * Description:
+ * All ioctl calls will be routed through this method
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int can_ioctl(FAR struct can_dev_s *dev, int cmd, unsigned long arg)
+{
+ /* No CAN ioctls are supported */
+
+ return -ENOTTY;
+}
+
+/****************************************************************************
+ * Name: can_remoterequest
+ *
+ * Description:
+ * Send a remote request
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int can_remoterequest(FAR struct can_dev_s *dev, uint16_t id)
+{
+#warning "Remote request not implemented"
+ return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: can_send
+ *
+ * Description:
+ * Send one can message.
+ *
+ * One CAN-message consists of a maximum of 10 bytes. A message is
+ * composed of at least the first 2 bytes (when there are no data bytes).
+ *
+ * Byte 0: Bits 0-7: Bits 3-10 of the 11-bit CAN identifier
+ * Byte 1: Bits 5-7: Bits 0-2 of the 11-bit CAN identifier
+ * Bit 4: Remote Tranmission Request (RTR)
+ * Bits 0-3: Data Length Code (DLC)
+ * Bytes 2-10: CAN data
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
+{
+ FAR struct sam_can_s *priv = dev->cd_priv;
+ FAR uint8_t *ptr;
+ uint32_t regval;
+ uint32_t tmp;
+ int dlc;
+ int txmb;
+
+ canllvdbg("CAN%d ID: %d DLC: %d\n", priv->port, msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc);
+
+ /* Select one empty transmit mailbox */
+
+#warning Missing logic
+ {
+ canlldbg("ERROR: No available mailbox\n");
+ return -EBUSY;
+ }
+
+ /* Set up the ID, standard 11-bit or extended 29-bit. */
+
+#ifdef CONFIG_CAN_EXTID
+ if (msg->cm_hdr.ch_extid)
+ {
+ DEBUGASSERT(msg->cm_hdr.ch_id < (1 << 29));
+#warning Missing logic
+ }
+ else
+ {
+ DEBUGASSERT(msg->cm_hdr.ch_id < (1 << 11));
+#warning Missing logic
+ }
+#else
+#warning Missing logic
+#endif
+
+ /* Set up the DLC */
+
+ dlc = msg->cm_hdr.ch_dlc;
+#warning Missing logic
+
+ /* Set up the data fields */
+
+ ptr = msg->cm_data;
+ regval = 0;
+
+ if (dlc > 0)
+ {
+#warning Missing logic
+
+ if (dlc > 1)
+ {
+#warning Missing logic
+
+ if (dlc > 2)
+ {
+#warning Missing logic
+
+ if (dlc > 3)
+ {
+#warning Missing logic
+ }
+ }
+ }
+ }
+
+ regval = 0;
+ if (dlc > 4)
+ {
+#warning Missing logic
+
+ if (dlc > 5)
+ {
+#warning Missing logic
+
+ if (dlc > 6)
+ {
+#warning Missing logic
+
+ if (dlc > 7)
+ {
+#warning Missing logic
+ }
+ }
+ }
+ }
+
+ /* Enable the transmit mailbox empty interrupt (may already be enabled) */
+#warning Missing logic
+
+ /* Request transmission */
+#warning Missing logic
+
+ can_dumpmbregs(priv, "After send");
+ return OK;
+}
+
+/****************************************************************************
+ * Name: can_txready
+ *
+ * Description:
+ * Return true if the CAN hardware can accept another TX message.
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * True if the CAN hardware is ready to accept another TX message.
+ *
+ ****************************************************************************/
+
+static bool can_txready(FAR struct can_dev_s *dev)
+{
+ FAR struct sam_can_s *priv = dev->cd_priv;
+
+ /* Return true if any mailbox is available */
+#warning Missing logic
+
+ return false;
+}
+
+/****************************************************************************
+ * Name: can_txempty
+ *
+ * Description:
+ * Return true if all message have been sent. If for example, the CAN
+ * hardware implements FIFOs, then this would mean the transmit FIFO is
+ * empty. This method is called when the driver needs to make sure that
+ * all characters are "drained" from the TX hardware before calling
+ * co_shutdown().
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * True if there are no pending TX transfers in the CAN hardware.
+ *
+ ****************************************************************************/
+
+static bool can_txempty(FAR struct can_dev_s *dev)
+{
+ FAR struct sam_can_s *priv = dev->cd_priv;
+
+ /* Return true if all mailboxes are available */
+#warning Missing logic
+
+ return false;
+}
+
+/****************************************************************************
+ * Name: can_interrupt
+ *
+ * Description:
+ * Common CAN interrupt handler
+ *
+ * Input Parameters:
+ * priv - CAN-specific private data
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void can_interrupt(struct sam_can_s *priv)
+{
+ uint32_t sr;
+ uint32_t imr;
+ uint32_t pending;
+ uint32_t regval;
+
+ /* Get the set of pending interrupts */
+
+ sr = can_getreg(priv, SAM_CAN_SR_OFFSET);
+ imr = can_getreg(priv, SAM_CAN_IMR_OFFSET);
+ pending = sr & imr;
+
+ /* There are two different types of interrupts. One type of interrupt is a
+ * message-object related interrupt, the other is a system interrupt that
+ * handles errors or system-related interrupt sources.
+ */
+
+ /* Check for message related interrupts
+ *
+ * - Data registers in the mailbox object are available to the
+ * application. In Receive Mode, a new message was received. In Transmit
+ * Mode, a message was transmitted successfully.
+ * - A sent transmission was aborted.
+ */
+
+ if ((pending & CAN_INT_MBALL) != 0)
+ {
+#warning Missing logic
+ }
+
+ /* Check for system interrupts
+ *
+ * - Bus off interrupt: The CAN module enters the bus off state.
+ * - Error passive interrupt: The CAN module enters Error Passive Mode.
+ * - Error Active Mode: The CAN module is neither in Error Passive Mode
+ * nor in Bus Off mode.
+ * - Warn Limit interrupt: The CAN module is in Error-active Mode, but at
+ * least one of its error counter value exceeds 96.
+ * - Wake-up interrupt: This interrupt is generated after a wake-up and a
+ * bus synchronization.
+ * - Sleep interrupt: This interrupt is generated after a Low-power Mode
+ * enable once all pending messages in transmission have been sent.
+ * - Internal timer counter overflow interrupt: This interrupt is
+ * generated when the internal timer rolls over.
+ * - Timestamp interrupt: This interrupt is generated after the reception
+ * or the transmission of a start of frame or an end of frame. The value
+ * of the internal counter is copied in the CAN_TIMESTP register.
+ */
+
+ if ((pending & ~CAN_INT_MBALL) != 0)
+ {
+#warning Missing logic
+ }
+}
+
+/****************************************************************************
+ * Name: can0_interrupt
+ *
+ * Description:
+ * CAN0 interrupt handler
+ *
+ * Input Parameters:
+ * irq - The IRQ number of the interrupt.
+ * context - The register state save array at the time of the interrupt.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SAMA5_CAN0
+static int can0_interrupt(int irq, void *context)
+{
+ can_interrupt(&g_can0dev);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: can0_interrupt
+ *
+ * Description:
+ * CAN0 interrupt handler
+ *
+ * Input Parameters:
+ * irq - The IRQ number of the interrupt.
+ * context - The register state save array at the time of the interrupt.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SAMA5_CAN1
+static int can1_interrupt(int irq, void *context)
+{
+ can_interrupt(&g_can1dev);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: can_bittiming
+ *
+ * Description:
+ * Set the CAN baudrate register (BR) based on the configured BAUD.
+ *
+ * Definitions:
+ *
+ * TIME QUANTUM. The TIME QUANTUM (Tq) is a fixed unit of time derived
+ * from the MCK period. The total number of TIME QUANTA in a bit time is
+ * programmable from 8 to 25.
+ *
+ * INFORMATION PROCESSING TIME. The Information Processing Time (IPT)
+ * is the time required for the logic to determine the bit level of a
+ * sampled bit. The IPT begins at the sample point, is measured in Tq
+ * and is fixed at 2 Tq for the Atmel CAN.
+ *
+ * SAMPLE POINT. The SAMPLE POINT is the point in time at which the
+ * bus level is read and interpreted as the value of that respective
+ * bit. Its location is at the end of PHASE_SEG1.
+ *
+ * The CAN protocol specification partitions the nominal bit time into
+ * four different segments:
+ *
+ * 1. Synchronization segment (SYNC_SEG): a bit change is expected to occur
+ * within this time segment. It has a fixed length of one time quantum
+ * (1 x tCAN).
+ * 2. Propogation segment (PROP_SEG): This part of the bit time is used
+ * to compensate for the physical delay times within the network. It is
+ * twice the sum of the signal’s propagation time on the bus line, the
+ * input comparator delay, and the output driver delay. It is
+ * programmable to be 1 to 8 Tq long. This parameter is defined in the
+ * PROPAG field of the CAN Baudrate Register.
+ * 3. Phase segment 1 (PHASE_SEG1): defines the location of the sample
+ * point. Phase Segment 1 is programmable to be 1-8 Tq long.
+ * 4. Phase segement 2 (PHASE_SEG2): defines the location of the transmit
+ * point.Phase Segment 2 length has to be at least as long as the
+ * Information Processing Time (IPT) and may not be more than the
+ * length of Phase Segment 1 (since Phase Segment 2 also begins at the
+ * sample point and is the last segment in the bit time).
+ *
+ * The Phase-Buffer-Segments are used to compensate for edge phase errors.
+ * These segments can be lengthened (PHASE SEG1) or shortened (PHASE SEG2)
+ * by resynchronization:
+ *
+ * SJW: ReSynchronization Jump Width. The ReSynchronization Jump Width
+ * defines the limit to the amount of lengthening or shortening of the
+ * Phase Segments. SJW is programmable to be the minimum of PHASE SEG1
+ * and 4 Tq.
+ *
+ * In the CAN controller, the length of a bit on the CAN bus is determined
+ * by the parameters (BRP, PROPAG, PHASE1 and PHASE2).
+ *
+ * Tbit = Tcsc + Tprs + Tphs1 + Tphs2
+ *
+ * Pictorially:
+ *
+ * |<----------------------- NOMINAL BIT TIME ------------------------>|
+ * |<- SYNC_SEG ->|<- PROP_SEG ->|<-- PHASE_SEG1 -->|<-- PHASE_SEG2 -->|
+ * |<--- Tcsc --->|<--- Tprs --->|<---- Tphs1 ----->|<---- Tphs2 ----->|
+ * |<--- 1 Tq --->|<-- 1-8 Tq -->|<---- 1-8 Tq ---->|<--- <= Tphs1 --->|
+ *
+ * Where
+ * Tcsc is the duration of the SYNC_SEG segment
+ * Tprs is the duration of the PROP_SEG segment
+ * Tphs1 is the duration of the PHASE_SEG1 segment
+ * Tphs2 is the duration of the PHASE_SEG2 segment
+ * Tq is the "Time Quantum"
+ *
+ * Relationships:
+ *
+ * baud = 1 / Tbit
+ * Tbit = Tq + Tprs + Tphs1 + Tphs2
+ * Tq = (BRP + 1) / MCK
+ * Tprs = Tq * (PROPAG + 1)
+ * Tphs1 = Tq * (PHASE1 + 1)
+ * Tphs2 = Tq * (PHASE2 + 1)
+ *
+ * Input Parameter:
+ * priv - A reference to the CAN block status
+ *
+ * Returned Value:
+ * Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int can_bittiming(struct sam_can_s *priv)
+{
+ uint32_t regval;
+ uint32_t brp;
+ uint32_t propag;
+ uint32_t phase1;
+ uint32_t phase2;
+ uint32_t sjw;
+ uint32_t t1t2;
+ uint8_t tq;
+
+ /* Select the time quantum
+ *
+ * REVISIT: We could probably do a better job than this.
+ */
+
+ if (priv->baud >= 1000)
+ {
+ tq = 8;
+ }
+ else
+ {
+ tq = 16;
+ }
+
+ /* Calculate the baudrate prescaler (BRP). This depends only on the
+ * selected Tq value, the desired BAUD and the CAN peripheral clock
+ * frequency.
+ *
+ * Tq = (BRP + 1) / CAN_FRQUENCY
+ * Tbit = Nquanta * (BRP + 1) / CAN_FREQUENCY
+ * baud = CAN_FREQUENCY / (Nquanta * (brp + 1))
+ * brp = CAN_FREQUENCY / (baud * nquanta) - 1
+ */
+
+ brp = (CAN_FREQUENCY / (priv->baud * 1000 * tq)) - 1;
+ if (brp == 0)
+ {
+ /* The BRP field must be within the range 1 - 0x7f */
+
+ candbg("CAN%d: baud %d too high\n", priv->port, priv->baud);
+ return -EINVAL;
+ }
+
+ /* Propagation delay:
+ *
+ * Delay Bus Driver - 50ns
+ * Delay Receiver - 30ns
+ * Delay Bus Line (20m) - 110ns
+ */
+
+ propag = tq * priv->baud * 2 * (50 + 30 + 110) / 1000000
+ if ((propag >= 1)
+ {
+ propag--;
+ }
+ else
+ {
+ propag = 0;
+ }
+
+ /* This the time of the first two segments */
+
+ t1t2 = tq - 1 - (propag + 1);
+
+ /* Calcuate phase1 and phase2 */
+
+ phase1 = (t1t2 >> 1) - 1;
+ phase2 = tphase1;
+
+ if ((t1t2 & 1) != 0)
+ {
+ phase2++;
+ }
+
+ /* Calculate SJW */
+
+ if (1 > (4 / (phase1 + 1)))
+ {
+ sjw = 3;
+ }
+ else
+ {
+ sjw = phase1;
+ }
+
+ if ((propag + phase1 + phase2) != (uint32_t)(tq - 4))
+ {
+ candbg("CAN%d: Could not realize baud %d\n", priv->port, priv->baud);
+ return -EINVAL;
+ }
+
+ regval = CAN_BR_PHASE2(phase2) | CAN_BR_PHASE1(phase1) |
+ CAN_BR_PROPAG(propag) | CAN_BR_SJW(sjw) | CAN_BR_BRP(brp) |
+ CAN_BR_ONCE;
+ can_putreg(priv, SAM_CAN_BR_OFFSET);
+}
+
+/****************************************************************************
+ * Name: can_hwinitialize
+ *
+ * Description:
+ * CAN cell initialization
+ *
+ * Input Parameter:
+ * priv - A pointer to the private data structure for this CAN block
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int can_hwinitialize(struct sam_can_s *priv)
+{
+ volatile uint32_t timeout;
+ uint32_t regval;
+ int ret;
+
+ canllvdbg("CAN%d\n", priv->port);
+
+ /* Configure CAN pins */
+
+ sam_configpio(priv->rxpinset);
+ sam_configpio(priv->txpinset);
+
+ /* Set the maximum CAN peripheral clock frequency */
+
+ regval = PMC_PCR_PID(priv->pid) | PMC_PCR_CMD | CAN_PCR_DIV | PMC_PCR_EN;
+ sam_adc_putreg(priv, SAM_PMC_PCR, regval);
+
+ /* Enable peripheral clocking */
+
+ sam_enableperiph1(priv->pid);
+
+ /* Exit from sleep mode */
+#warning Missing Logic
+
+ /* Configure CAN behavior. Priority driven request order, not message ID. */
+#warning Missing Logic
+
+ /* Enter initialization mode */
+#warning Missing Logic
+
+ /* Wait until initialization mode is acknowledged */
+
+ for (timeout = INAK_TIMEOUT; timeout > 0; timeout--)
+ {
+#warning Missing Logic
+ }
+
+ /* Check for a timeout */
+#warning Missing Logic
+
+ /* Disable the following modes:
+ *
+ * - Time triggered communication mode
+ * - Automatic bus-off management
+ * - Automatic wake-up mode
+ * - No automatic retransmission
+ * - Receive FIFO locked mode
+ * - Transmit FIFO priority
+ */
+#warning Missing Logic
+
+ /* Configure bit timing. */
+
+ ret = can_bittiming(priv);
+ if (ret < 0)
+ {
+ canlldbg("ERROR: Failed to set bit timing: %d\n", ret);
+ return ret;
+ }
+
+ /* Exit initialization mode */
+#warning Missing Logic
+
+ /* Wait until the initialization mode exit is acknowledged */
+
+ for (timeout = INAK_TIMEOUT; timeout > 0; timeout--)
+ {
+#warning Missing Logic
+ }
+
+ /* Check for a timeout */
+#warning Missing Logic
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_caninitialize
+ *
+ * Description:
+ * Initialize the selected CAN port
+ *
+ * Input Parameter:
+ * Port number (for hardware that has mutiple CAN interfaces)
+ *
+ * Returned Value:
+ * Valid CAN device structure reference on succcess; a NULL on failure
+ *
+ ****************************************************************************/
+
+FAR struct can_dev_s *sam_caninitialize(int port)
+{
+ struct can_dev_s *dev = NULL;
+
+ canvdbg("CAN%d\n", port);
+
+ /* NOTE: Peripherical clocking for CAN0 and/or CAN1 was already provided
+ * by sam_clockconfig() early in the reset sequence.
+ */
+
+#ifdef CONFIG_SAMA5_CAN0
+ if (port == 0)
+ {
+ /* Select the CAN0 device structure */
+
+ dev = &g_can0dev;
+ }
+ else
+#endif
+#ifdef CONFIG_SAMA5_CAN1
+ if (port == 1)
+ {
+ /* Select the CAN1 device structure */
+
+ dev = &g_can1dev;
+ }
+ else
+#endif
+ {
+ candbg("ERROR: Unsupported port %d\n", port);
+ return NULL;
+ }
+
+ return dev;
+}
+
+#endif /* CONFIG_CAN && (CONFIG_SAMA5_CAN0 || CONFIG_SAMA5_CAN1) */
+
diff --git a/nuttx/arch/arm/src/sama5/sam_can.h b/nuttx/arch/arm/src/sama5/sam_can.h
new file mode 100644
index 000000000..6ac429a77
--- /dev/null
+++ b/nuttx/arch/arm/src/sama5/sam_can.h
@@ -0,0 +1,113 @@
+/************************************************************************************
+ * arch/arm/src/sama5/sam_can.h
+ *
+ * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@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_SAMA5_SAM_CAN_H
+#define __ARCH_ARM_SRC_SAMA5_SAM_CAN_H
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "chip.h"
+#include "chip/sam_can.h"
+
+#include <nuttx/can.h>
+
+#if defined(CONFIG_CAN) && (defined(CONFIG_SAMA5_CAN0) || defined(CONFIG_SAMA5_CAN1))
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+/* Configuration ********************************************************************/
+
+/* CAN BAUD */
+
+#if defined(CONFIG_SAMA5_CAN0) && !defined(CONFIG_CAN0_BAUD)
+# error "CONFIG_CAN0_BAUD is not defined"
+#endif
+
+#if defined(CONFIG_SAMA5_CAN1) && !defined(CONFIG_CAN1_BAUD)
+# error "CONFIG_CAN1_BAUD is not defined"
+#endif
+
+/************************************************************************************
+ * Public Types
+ ************************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+/************************************************************************************
+ * Public Data
+ ************************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+/****************************************************************************
+ * Name: sama5_caninitialize
+ *
+ * Description:
+ * Initialize the selected CAN port
+ *
+ * Input Parameter:
+ * Port number: 0=CAN0, 1=CAN1
+ *
+ * Returned Value:
+ * Valid CAN device structure reference on succcess; a NULL on failure
+ *
+ ****************************************************************************/
+
+struct can_dev_s;
+FAR struct can_dev_s *sama5_caninitialize(int port);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_CAN && (CONFIG_SAMA5_CAN0 || CONFIG_SAMA5_CAN1) */
+#endif /* __ARCH_ARM_SRC_SAMA5_SAM_CAN_H */