From adeb19339ca592e979c93c58929fd5739a7a8316 Mon Sep 17 00:00:00 2001
From: Dylan Laduranty <dylan.laduranty@mesotic.com>
Date: Mon, 21 Jan 2019 17:05:04 +0100
Subject: [PATCH] cpu/saml1x: add support for saml10/saml11 MCUs

---
 cpu/saml1x/Makefile             |  10 ++
 cpu/saml1x/Makefile.features    |   1 +
 cpu/saml1x/Makefile.include     |   4 +
 cpu/saml1x/cpu.c                |  71 ++++++++++
 cpu/saml1x/doc.txt              |   9 ++
 cpu/saml1x/include/periph_cpu.h |  42 ++++++
 cpu/saml1x/periph/Makefile      |   1 +
 cpu/saml1x/periph/pm.c          |  51 +++++++
 cpu/saml1x/periph/rtc.c         | 236 ++++++++++++++++++++++++++++++++
 cpu/saml1x/periph/rtt.c         | 149 ++++++++++++++++++++
 cpu/saml1x/periph/timer.c       | 231 +++++++++++++++++++++++++++++++
 cpu/saml1x/vectors.c            | 125 +++++++++++++++++
 12 files changed, 930 insertions(+)
 create mode 100644 cpu/saml1x/Makefile
 create mode 100644 cpu/saml1x/Makefile.features
 create mode 100644 cpu/saml1x/Makefile.include
 create mode 100644 cpu/saml1x/cpu.c
 create mode 100644 cpu/saml1x/doc.txt
 create mode 100644 cpu/saml1x/include/periph_cpu.h
 create mode 100644 cpu/saml1x/periph/Makefile
 create mode 100644 cpu/saml1x/periph/pm.c
 create mode 100644 cpu/saml1x/periph/rtc.c
 create mode 100644 cpu/saml1x/periph/rtt.c
 create mode 100644 cpu/saml1x/periph/timer.c
 create mode 100644 cpu/saml1x/vectors.c

diff --git a/cpu/saml1x/Makefile b/cpu/saml1x/Makefile
new file mode 100644
index 0000000000..8794dfbc47
--- /dev/null
+++ b/cpu/saml1x/Makefile
@@ -0,0 +1,10 @@
+# define the module that is build
+MODULE = cpu
+
+# add a list of subdirectories, that should also be build
+DIRS = periph $(RIOTCPU)/cortexm_common $(RIOTCPU)/sam0_common
+
+# (file triggers compiler bug. see #5775)
+SRC_NOLTO += vectors.c
+
+include $(RIOTBASE)/Makefile.base
diff --git a/cpu/saml1x/Makefile.features b/cpu/saml1x/Makefile.features
new file mode 100644
index 0000000000..52f4483551
--- /dev/null
+++ b/cpu/saml1x/Makefile.features
@@ -0,0 +1 @@
+include $(RIOTCPU)/sam0_common/Makefile.features
diff --git a/cpu/saml1x/Makefile.include b/cpu/saml1x/Makefile.include
new file mode 100644
index 0000000000..9da8c0ba5d
--- /dev/null
+++ b/cpu/saml1x/Makefile.include
@@ -0,0 +1,4 @@
+export CPU_ARCH = cortex-m23
+
+include $(RIOTCPU)/sam0_common/Makefile.include
+include $(RIOTMAKE)/arch/cortexm.inc.mk
diff --git a/cpu/saml1x/cpu.c b/cpu/saml1x/cpu.c
new file mode 100644
index 0000000000..f3ee82c2eb
--- /dev/null
+++ b/cpu/saml1x/cpu.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 Mesotic SAS
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_saml1x
+ * @{
+ *
+ * @file        cpu.c
+ * @brief       Implementation of the CPU initialization for Microchip
+ *              SAML10/SAML11 MCUs
+ *
+ * @author      Dylan Laduranty <dylan.laduranty@mesotic.com>
+ * @}
+ */
+
+#include "cpu.h"
+#include "periph/init.h"
+#include "board.h"
+
+static void _gclk_setup(int gclk, uint32_t reg)
+{
+    GCLK->GENCTRL[gclk].reg = reg;
+    while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(gclk)) {}
+}
+
+/**
+ * @brief Initialize the CPU, set IRQ priorities, clocks
+ */
+void cpu_init(void)
+{
+    /* initialize the Cortex-M core */
+    cortexm_init();
+
+    /* turn on only needed APB peripherals */
+    MCLK->APBAMASK.reg = MCLK_APBAMASK_MCLK
+                         | MCLK_APBAMASK_OSCCTRL
+                         | MCLK_APBAMASK_GCLK
+#ifdef MODULE_PERIPH_GPIO_IRQ
+                         | MCLK_APBAMASK_EIC
+#endif
+#ifdef MODULE_PERIPH_GPIO
+                         | MCLK_APBAMASK_PORT
+#endif
+                         ;
+
+    /* Software reset the GCLK module to ensure it is re-initialized correctly */
+    GCLK->CTRLA.reg = GCLK_CTRLA_SWRST;
+    while (GCLK->CTRLA.reg & GCLK_CTRLA_SWRST) {}
+    while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_SWRST) {}
+
+    /* set OSC16M to 16MHz */
+    OSCCTRL->OSC16MCTRL.bit.FSEL = 3;
+    OSCCTRL->OSC16MCTRL.bit.ONDEMAND = 0;
+    OSCCTRL->OSC16MCTRL.bit.RUNSTDBY = 0;
+
+    /* Setup GCLK generators */
+    _gclk_setup(0, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M);
+
+#ifdef MODULE_PERIPH_PM
+    /* enable power managemet module */
+    MCLK->APBAMASK.reg |= MCLK_APBAMASK_PM;
+#endif
+
+    /* trigger static peripheral initialization */
+    periph_init();
+}
diff --git a/cpu/saml1x/doc.txt b/cpu/saml1x/doc.txt
new file mode 100644
index 0000000000..9abaf68470
--- /dev/null
+++ b/cpu/saml1x/doc.txt
@@ -0,0 +1,9 @@
+/**
+ * @defgroup        cpu_saml1x Microchip SAML10/SAML11
+ * @ingroup         cpu
+ * @brief           Microchip SAML1x Cortex-M23 MCU specific implementation.
+ *
+ * This module contains Microchip SAML10/SAML11 specific code and definition.
+ *
+ * @see cpu_saml1x
+ */
diff --git a/cpu/saml1x/include/periph_cpu.h b/cpu/saml1x/include/periph_cpu.h
new file mode 100644
index 0000000000..1b3ab8337b
--- /dev/null
+++ b/cpu/saml1x/include/periph_cpu.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 Mesotic SAS
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup         cpu_saml1x
+ * @brief           CPU specific definitions for internal peripheral handling
+ * @{
+ *
+ * @file
+ * @brief           CPU specific definitions for internal peripheral handling
+ *
+ * @author          Dylan Laduranty <dylan.laduranty@mesotic.com>
+ */
+
+#ifndef PERIPH_CPU_H
+#define PERIPH_CPU_H
+
+#include "periph_cpu_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Mapping of pins to EXTI lines, -1 means not EXTI possible
+ */
+static const int8_t exti_config[1][32] = {
+    { 0,  1,  2,  3,  4,  5,  6,  7, -1, 0,  1,  2, -1, -1, 3, 4,
+      5,  6,  7,  0, -1, -1,  1,  2,  3, 4, -1,  5, -1, -1, 6, 7},
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PERIPH_CPU_H */
+/** @} */
diff --git a/cpu/saml1x/periph/Makefile b/cpu/saml1x/periph/Makefile
new file mode 100644
index 0000000000..a36df249ac
--- /dev/null
+++ b/cpu/saml1x/periph/Makefile
@@ -0,0 +1 @@
+include $(RIOTMAKE)/periph.mk
diff --git a/cpu/saml1x/periph/pm.c b/cpu/saml1x/periph/pm.c
new file mode 100644
index 0000000000..e6525e888c
--- /dev/null
+++ b/cpu/saml1x/periph/pm.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_saml21
+ * @ingroup     drivers_periph_pm
+ * @{
+ *
+ * @file
+ * @brief       Implementation of the kernels power management interface
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * @}
+ */
+
+#include "periph/pm.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+void pm_set(unsigned mode)
+{
+    if (mode < PM_NUM_MODES) {
+        uint32_t _mode;
+
+        switch (mode) {
+            case 0:
+                DEBUG("pm_set(): setting STANDBY mode.\n");
+                _mode = PM_SLEEPCFG_SLEEPMODE_STANDBY;
+                break;
+            default: /* Falls through */
+            case 1:
+                DEBUG("pm_set(): setting IDLE mode.\n");
+                _mode = PM_SLEEPCFG_SLEEPMODE_IDLE;
+                break;
+        }
+
+        /* write sleep configuration */
+        PM->SLEEPCFG.bit.SLEEPMODE = _mode;
+        /* make sure value has been set */
+        while (PM->SLEEPCFG.bit.SLEEPMODE != _mode) {}
+    }
+
+    cortexm_sleep(0);
+}
diff --git a/cpu/saml1x/periph/rtc.c b/cpu/saml1x/periph/rtc.c
new file mode 100644
index 0000000000..56046dfb1f
--- /dev/null
+++ b/cpu/saml1x/periph/rtc.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2014 Baptiste CLENET
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_saml21
+ * @ingroup     drivers_periph_rtc
+ * @{
+ * @file
+ * @brief       Low-level RTC driver implementation
+ * @author      Baptiste Clenet <bapclenet@gmail.com>
+ * @autor       ported to SAML21 by FWX <FWX@dialine.fr>
+ * @}
+ */
+
+#include <time.h>
+#include "cpu.h"
+#include "periph/rtc.h"
+#include "periph_conf.h"
+
+/* SAML21 rev B needs an extra bit, which in rev A defaults to 1, but isn't
+ * visible. Thus define it here. */
+#ifndef RTC_MODE2_CTRLA_CLOCKSYNC
+#define RTC_MODE2_CTRLA_CLOCKSYNC_Pos   15
+#define RTC_MODE2_CTRLA_CLOCKSYNC       (0x1ul << RTC_MODE2_CTRLA_CLOCKSYNC_Pos)
+#endif
+
+typedef struct {
+    rtc_alarm_cb_t cb;        /**< callback called from RTC interrupt */
+    void *arg;                /**< argument passed to the callback */
+} rtc_state_t;
+
+static rtc_state_t rtc_callback;
+
+/* At 1Hz, RTC goes till 63 years (2^5, see 17.8.22 in datasheet)
+* reference_year is set to 100 (offset) to be in our current time (2000)
+* Thanks to this, the user will be able to set time in 2000's*/
+static uint16_t reference_year = 100;
+
+void rtc_init(void)
+{
+    /* Turn on power manager for RTC */
+    MCLK->APBAMASK.reg |= MCLK_APBAMASK_RTC | MCLK_APBAMASK_OSC32KCTRL;
+    /* DISABLE RTC MASTER */
+    rtc_poweroff();
+
+
+#if EXTERNAL_OSC32_SOURCE
+
+    /* RTC uses External 32,768KHz Oscillator */
+    OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_XTALEN
+                            | OSC32KCTRL_XOSC32K_EN1K
+                            | OSC32KCTRL_XOSC32K_RUNSTDBY
+                            | OSC32KCTRL_XOSC32K_ENABLE;
+
+    /* Wait XOSC32K Ready */
+    while (OSC32KCTRL->STATUS.bit.XOSC32KRDY==0);
+
+    /* RTC source clock is external oscillator at 1kHz */
+    OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K;
+
+#endif /* EXTERNAL_OSC32_SOURCE */
+
+#if INTERNAL_OSC32_SOURCE
+ uint32_t * pCalibrationArea;
+ uint32_t osc32kcal;
+
+    /* Read OSC32KCAL, calibration data for OSC32 !!! */
+    pCalibrationArea = (uint32_t*) NVMCTRL_OTP5;
+    osc32kcal = ( (*pCalibrationArea) & 0x1FC0 ) >> 6;
+
+    /* RTC use Low Power Internal Oscillator at 1kHz */
+    OSC32KCTRL->OSC32K.reg = OSC32KCTRL_OSC32K_RUNSTDBY
+                           | OSC32KCTRL_OSC32K_EN1K
+                           | OSC32KCTRL_OSC32K_CALIB(osc32kcal)
+                           | OSC32KCTRL_OSC32K_ENABLE;
+
+    /* Wait OSC32K Ready */
+    while (OSC32KCTRL->STATUS.bit.OSC32KRDY==0);
+
+    /* RTC uses internal 32,768KHz Oscillator */
+    OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_OSC1K;
+
+
+#endif /* INTERNAL_OSC32_SOURCE */
+
+#if ULTRA_LOW_POWER_INTERNAL_OSC_SOURCE
+
+    /* RTC uses Ultra Low Power internal 32,768KHz Oscillator */
+    OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_ULP1K;
+
+#endif /* ULTRA_LOW_POWER_INTERNAL_OSC_SOURCE */
+
+    /* Software Reset the RTC */
+    RTC->MODE2.CTRLA.bit.SWRST = 1;
+    /* Wait end of reset */
+    while (RTC->MODE2.CTRLA.bit.SWRST);
+
+    /* RTC config with RTC_MODE2_CTRL_CLKREP = 0 (24h) */
+    RTC->MODE2.CTRLA.reg = RTC_MODE2_CTRLA_PRESCALER_DIV1024 |  /* CLK_RTC_CNT = 1KHz / 1024 -> 1Hz */
+                           RTC_MODE2_CTRLA_CLOCKSYNC         |  /* Clock Read Synchronization Enable */
+                           RTC_MODE2_CTRLA_MODE_CLOCK;          /* Mode 2: Clock/Calendar */
+
+    /* Clear interrupt flags */
+    RTC->MODE2.INTFLAG.reg |= RTC_MODE2_INTFLAG_OVF;
+    RTC->MODE2.INTFLAG.reg |= RTC_MODE2_INTFLAG_ALARM0;
+
+    rtc_poweron();
+}
+
+int rtc_set_time(struct tm *time)
+{
+    if ((time->tm_year < reference_year) || (time->tm_year > reference_year + 63)) {
+        return -1;
+    }
+    else {
+        while (RTC->MODE2.SYNCBUSY.bit.CLOCK);
+        RTC->MODE2.CLOCK.reg = RTC_MODE2_CLOCK_YEAR(time->tm_year - reference_year)
+                             | RTC_MODE2_CLOCK_MONTH(time->tm_mon + 1)
+                             | RTC_MODE2_CLOCK_DAY(time->tm_mday)
+                             | RTC_MODE2_CLOCK_HOUR(time->tm_hour)
+                             | RTC_MODE2_CLOCK_MINUTE(time->tm_min)
+                             | RTC_MODE2_CLOCK_SECOND(time->tm_sec);
+        while (RTC->MODE2.SYNCBUSY.bit.CLOCK);
+    }
+   return 0;
+}
+
+int rtc_get_time(struct tm *time)
+{
+ RTC_MODE2_CLOCK_Type clock;
+
+    /* Read register in one time */
+    clock.reg = RTC->MODE2.CLOCK.reg;
+
+    time->tm_year = clock.bit.YEAR + reference_year;
+    if ((time->tm_year < reference_year) || (time->tm_year > (reference_year + 63))) {
+        return -1;
+    }
+    time->tm_mon = clock.bit.MONTH - 1;
+    time->tm_mday = clock.bit.DAY;
+    time->tm_hour = clock.bit.HOUR;
+    time->tm_min = clock.bit.MINUTE;
+    time->tm_sec = clock.bit.SECOND;
+    return 0;
+}
+
+int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
+{
+    rtc_clear_alarm();
+    if ((time->tm_year < reference_year) || (time->tm_year > (reference_year + 63))) {
+        return -2;
+    }
+    else {
+        RTC->MODE2.Mode2Alarm[0].ALARM.reg = RTC_MODE2_ALARM_YEAR(time->tm_year - reference_year)
+                                           | RTC_MODE2_ALARM_MONTH(time->tm_mon + 1)
+                                           | RTC_MODE2_ALARM_DAY(time->tm_mday)
+                                           | RTC_MODE2_ALARM_HOUR(time->tm_hour)
+                                           | RTC_MODE2_ALARM_MINUTE(time->tm_min)
+                                           | RTC_MODE2_ALARM_SECOND(time->tm_sec);
+        RTC->MODE2.Mode2Alarm[0].MASK.reg = RTC_MODE2_MASK_SEL(6);
+        while (RTC->MODE2.SYNCBUSY.bit.ALARM0);
+    }
+
+    /* Setup interrupt */
+    NVIC_EnableIRQ(RTC_IRQn);
+
+    /* Enable IRQ */
+    rtc_callback.cb = cb;
+    rtc_callback.arg = arg;
+    RTC->MODE2.INTFLAG.reg |= RTC_MODE2_INTFLAG_ALARM0;
+    RTC->MODE2.INTENSET.bit.ALARM0 = 1;
+
+    return 0;
+}
+
+int rtc_get_alarm(struct tm *time)
+{
+ RTC_MODE2_ALARM_Type alarm;
+
+    /* Read alarm register in one time */
+    alarm.reg = RTC->MODE2.Mode2Alarm[0].ALARM.reg;
+
+    time->tm_year = alarm.bit.YEAR + reference_year;
+    if ((time->tm_year < reference_year) || (time->tm_year > (reference_year + 63))) {
+        return -1;
+    }
+    time->tm_mon = alarm.bit.MONTH - 1;
+    time->tm_mday = alarm.bit.DAY;
+    time->tm_hour = alarm.bit.HOUR;
+    time->tm_min = alarm.bit.MINUTE;
+    time->tm_sec = alarm.bit.SECOND;
+
+    return 0;
+}
+
+void rtc_clear_alarm(void)
+{
+    /* disable interrupt */
+    RTC->MODE2.INTENCLR.bit.ALARM0 = 1;
+    rtc_callback.cb = NULL;
+    rtc_callback.arg = NULL;
+}
+
+void rtc_poweron(void)
+{
+    RTC->MODE2.CTRLA.bit.ENABLE = 1;
+    while (RTC->MODE2.SYNCBUSY.bit.ENABLE);
+}
+
+void rtc_poweroff(void)
+{
+    RTC->MODE2.CTRLA.bit.ENABLE = 0;
+    while (RTC->MODE2.SYNCBUSY.bit.ENABLE);
+}
+
+void isr_rtc(void)
+{
+    if (RTC->MODE2.INTFLAG.bit.ALARM0) {
+        rtc_callback.cb(rtc_callback.arg);
+        /* clear flag */
+        RTC->MODE2.INTFLAG.reg |= RTC_MODE2_INTFLAG_ALARM0;
+    }
+    if (RTC->MODE2.INTFLAG.bit.OVF) {
+        /* clear flag */
+        RTC->MODE2.INTFLAG.reg |= RTC_MODE2_INTFLAG_OVF;
+        /* At 1Hz, RTC goes till 63 years (2^5, see 17.8.22 in datasheet)
+        * Start RTC again with reference_year 64 years more (Be careful with alarm set) */
+        reference_year += 64;
+    }
+    cortexm_isr_end();
+}
diff --git a/cpu/saml1x/periph/rtt.c b/cpu/saml1x/periph/rtt.c
new file mode 100644
index 0000000000..d2da91a6fc
--- /dev/null
+++ b/cpu/saml1x/periph/rtt.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
+ *               2015 FreshTemp, LLC.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_saml21
+ * @ingroup     drivers_periph_rtt
+ * @{
+ *
+ * @file        rtt.c
+ * @brief       Low-level RTT driver implementation
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * @}
+ */
+
+#include <stdint.h>
+#include "periph/rtt.h"
+#include "board.h"
+
+#define ENABLE_DEBUG 0
+#include "debug.h"
+
+static rtt_cb_t _overflow_cb;
+static void* _overflow_arg;
+
+static rtt_cb_t _cmp0_cb;
+static void* _cmp0_arg;
+
+void rtt_init(void)
+{
+    DEBUG("%s:%d\n", __func__, __LINE__);
+    /* Turn on power manager for RTC */
+    MCLK->APBAMASK.reg |= MCLK_APBAMASK_RTC | MCLK_APBAMASK_OSC32KCTRL;
+    rtt_poweron();
+
+    /* reset */
+    RTC->MODE0.CTRLA.bit.SWRST = 1;
+    while(RTC->MODE0.CTRLA.bit.SWRST) {}
+
+    /* set 32bit counting mode */
+    RTC->MODE0.CTRLA.bit.MODE = 0;
+
+    /* set clock source */
+    OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K;
+
+    /* enable */
+    RTC->MODE0.CTRLA.bit.ENABLE = 1;
+    while(RTC->MODE0.SYNCBUSY.bit.ENABLE) {}
+
+    /* initially clear flag */
+    RTC->MODE0.INTFLAG.reg |= RTC_MODE1_INTFLAG_CMP(1 << 0);
+
+    /* enable RTT IRQ */
+    NVIC_EnableIRQ(RTC_IRQn);
+
+    DEBUG("%s:%d %u\n", __func__, __LINE__, (unsigned)rtt_get_counter());
+}
+
+void rtt_set_overflow_cb(rtt_cb_t cb, void *arg)
+{
+    DEBUG("%s:%d\n", __func__, __LINE__);
+    /* clear overflow cb to avoid race while assigning */
+    rtt_clear_overflow_cb();
+
+    /* set callback variables */
+    _overflow_cb = cb;
+    _overflow_arg = arg;
+
+    /* enable overflow interrupt */
+    RTC->MODE0.INTENSET.bit.OVF = 1;
+}
+void rtt_clear_overflow_cb(void)
+{
+    DEBUG("%s:%d\n", __func__, __LINE__);
+    /* disable overflow interrupt */
+    RTC->MODE0.INTENCLR.bit.OVF = 1;
+}
+
+uint32_t rtt_get_counter(void)
+{
+    DEBUG("%s:%d\n", __func__, __LINE__);
+    while (RTC->MODE0.SYNCBUSY.bit.COUNT) {}
+    return RTC->MODE0.COUNT.reg;
+}
+
+void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg)
+{
+    DEBUG("%s:%d alarm=%u\n", __func__, __LINE__, (unsigned)alarm);
+
+    /* disable interrupt to avoid race */
+    rtt_clear_alarm();
+
+    /* set COM register */
+    while (RTC->MODE0.SYNCBUSY.bit.COMP0) {}
+    RTC->MODE0.COMP[0].reg = alarm;
+
+    /* setup callback */
+    _cmp0_cb = cb;
+    _cmp0_arg = arg;
+
+    /* enable compare interrupt */
+    RTC->MODE0.INTENSET.bit.CMP0 = 1;
+}
+
+void rtt_clear_alarm(void)
+{
+    DEBUG("%s:%d\n", __func__, __LINE__);
+    /* clear compare interrupt */
+    RTC->MODE0.INTENCLR.bit.CMP0 = 1;
+}
+
+void rtt_poweron(void)
+{
+    DEBUG("%s:%d\n", __func__, __LINE__);
+    MCLK->APBAMASK.reg |= MCLK_APBAMASK_RTC;
+}
+
+void rtt_poweroff(void)
+{
+    DEBUG("%s:%d\n", __func__, __LINE__);
+    MCLK->APBAMASK.reg &= ~MCLK_APBAMASK_RTC;
+}
+
+void isr_rtc(void)
+{
+    if (RTC->MODE0.INTFLAG.bit.OVF) {
+        RTC->MODE0.INTFLAG.reg |= RTC_MODE0_INTFLAG_OVF;
+        if (_overflow_cb) {
+            _overflow_cb(_overflow_arg);
+        }
+    }
+    if (RTC->MODE0.INTFLAG.bit.CMP0) {
+        /* clear flag */
+        RTC->MODE0.INTFLAG.reg |= RTC_MODE1_INTFLAG_CMP(1 << 0);
+        /* disable interrupt */
+        RTC->MODE0.INTENCLR.bit.CMP0 = 1;
+        if (_cmp0_cb) {
+            _cmp0_cb(_cmp0_arg);
+        }
+    }
+    cortexm_isr_end();
+}
diff --git a/cpu/saml1x/periph/timer.c b/cpu/saml1x/periph/timer.c
new file mode 100644
index 0000000000..bf0a13f4b1
--- /dev/null
+++ b/cpu/saml1x/periph/timer.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2018 Mesotic SAS
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_saml1x
+ * @ingroup     drivers_periph_timer
+ * @{
+ *
+ * @file        timer.c
+ * @brief       Low-level timer driver implementation
+ *
+ * @author      Dylan Laduranty <dylan.laduranty@mesotic.com>
+ *
+ * @}
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "board.h"
+#include "cpu.h"
+
+#include "periph/timer.h"
+#include "periph_conf.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+/**
+ * @brief Timer state memory
+ */
+static timer_isr_ctx_t config[TIMER_NUMOF];
+
+/* enable timer interrupts */
+static inline void _irq_enable(tim_t dev);
+
+
+/**
+ * @brief Setup the given timer
+ */
+int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
+{
+    /* at the moment, the timer can only run at 1MHz */
+    if (freq != 1000000ul) {
+        return -1;
+    }
+    /* configure GCLK0 to feed TC0 & TC1*/
+    GCLK->PCHCTRL[TC0_GCLK_ID].reg |= GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0;
+    while (!(GCLK->PCHCTRL[TC0_GCLK_ID].reg & GCLK_PCHCTRL_CHEN)) {}
+
+    /* select the timer and enable the timer specific peripheral clocks */
+    switch (dev) {
+#if TIMER_0_EN
+    case TIMER_0:
+        if (TIMER_0_DEV.CTRLA.bit.ENABLE) {
+            return 0;
+        }
+        MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC0;
+        /* reset timer */
+        TIMER_0_DEV.CTRLA.bit.SWRST = 1;
+        while (TIMER_0_DEV.SYNCBUSY.bit.SWRST) {}
+        TIMER_0_DEV.CTRLA.reg |= TC_CTRLA_MODE_COUNT32 |    /* choosing 32 bit mode */
+                                 TC_CTRLA_PRESCALER(4) |    /* sourced by 4MHz with Presc 4 results in 1MHz*/
+                                 TC_CTRLA_PRESCSYNC_RESYNC; /* initial prescaler resync */
+        break;
+#endif
+    case TIMER_UNDEFINED:
+    default:
+        return -1;
+    }
+
+    /* save callback */
+    config[dev].cb = cb;
+    config[dev].arg = arg;
+
+    /* enable interrupts for given timer */
+    _irq_enable(dev);
+
+    timer_start(dev);
+
+    return 0;
+}
+
+int timer_set_absolute(tim_t dev, int channel, unsigned int value)
+{
+    DEBUG("Setting timer %i channel %i to %i\n", dev, channel, value);
+
+    /* get timer base register address */
+    switch (dev) {
+#if TIMER_0_EN
+    case TIMER_0:
+        /* set timeout value */
+        switch (channel) {
+        case 0:
+            TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC0;
+            TIMER_0_DEV.CC[0].reg = value;
+            TIMER_0_DEV.INTENSET.bit.MC0 = 1;
+            break;
+        case 1:
+            TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC1;
+            TIMER_0_DEV.CC[1].reg = value;
+            TIMER_0_DEV.INTENSET.bit.MC1 = 1;
+            break;
+        default:
+            return -1;
+        }
+        break;
+#endif
+    case TIMER_UNDEFINED:
+    default:
+        return -1;
+    }
+
+    return 1;
+}
+
+int timer_clear(tim_t dev, int channel)
+{
+    /* get timer base register address */
+    switch (dev) {
+#if TIMER_0_EN
+    case TIMER_0:
+        switch (channel) {
+        case 0:
+            TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC0;
+            TIMER_0_DEV.INTENCLR.bit.MC0 = 1;
+            break;
+        case 1:
+            TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC1;
+            TIMER_0_DEV.INTENCLR.bit.MC1 = 1;
+            break;
+        default:
+            return -1;
+        }
+        break;
+#endif
+    case TIMER_UNDEFINED:
+    default:
+        return -1;
+    }
+
+    return 1;
+}
+
+unsigned int timer_read(tim_t dev)
+{
+    switch (dev) {
+#if TIMER_0_EN
+    case TIMER_0:
+        /* request syncronisation */
+        TIMER_0_DEV.CTRLBSET.bit.CMD = TC_CTRLBSET_CMD_READSYNC_Val;
+        while (TIMER_0_DEV.SYNCBUSY.bit.CTRLB) {
+            /* WORKAROUND to prevent being stuck there if timer not init */
+            if(!TIMER_0_DEV.CTRLA.bit.ENABLE) {
+                return 0;
+            }
+        }
+        return TIMER_0_DEV.COUNT.reg;
+#endif
+    default:
+        return 0;
+    }
+
+
+}
+
+void timer_stop(tim_t dev)
+{
+    switch (dev) {
+#if TIMER_0_EN
+        case TIMER_0:
+            TIMER_0_DEV.CTRLA.bit.ENABLE = 0;
+            break;
+#endif
+        case TIMER_UNDEFINED:
+            break;
+    }
+}
+
+void timer_start(tim_t dev)
+{
+    switch (dev) {
+#if TIMER_0_EN
+        case TIMER_0:
+            TIMER_0_DEV.CTRLA.bit.ENABLE = 1;
+            break;
+#endif
+        case TIMER_UNDEFINED:
+            break;
+    }
+}
+
+static inline void _irq_enable(tim_t dev)
+{
+    switch (dev) {
+#if TIMER_0_EN
+        case TIMER_0:
+            NVIC_EnableIRQ(TC0_IRQn);
+            break;
+#endif
+        case TIMER_UNDEFINED:
+            break;
+    }
+}
+
+#if TIMER_0_EN
+void TIMER_0_ISR(void)
+{
+    if (TIMER_0_DEV.INTFLAG.bit.MC0 && TIMER_0_DEV.INTENSET.bit.MC0) {
+        if(config[TIMER_0].cb) {
+            TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC0;
+            TIMER_0_DEV.INTENCLR.reg = TC_INTENCLR_MC0;
+            config[TIMER_0].cb(config[TIMER_0].arg, 0);
+        }
+    }
+    else if (TIMER_0_DEV.INTFLAG.bit.MC1 && TIMER_0_DEV.INTENSET.bit.MC1) {
+        if(config[TIMER_0].cb) {
+            TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC1;
+            TIMER_0_DEV.INTENCLR.reg = TC_INTENCLR_MC1;
+            config[TIMER_0].cb(config[TIMER_0].arg, 1);
+        }
+    }
+    cortexm_isr_end();
+}
+#endif /* TIMER_0_EN */
diff --git a/cpu/saml1x/vectors.c b/cpu/saml1x/vectors.c
new file mode 100644
index 0000000000..7e4e93ee21
--- /dev/null
+++ b/cpu/saml1x/vectors.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2018 Mesotic SAS
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_saml1x
+ * @{
+ *
+ * @file        vectors.c
+ * @brief       Startup code and interrupt vector definition
+ *
+ * @author      Dylan Laduranty <dylan.laduranty@mesotic.com>
+ *
+ * @}
+ */
+
+#include <stdint.h>
+#include "vectors_cortexm.h"
+
+/* define a local dummy handler as it needs to be in the same compilation unit
+ * as the alias definition */
+void dummy_handler(void) {
+    dummy_handler_default();
+}
+
+/* SAML1x specific interrupt vector */
+WEAK_DEFAULT void isr_system(void);
+WEAK_DEFAULT void isr_wdt(void);
+WEAK_DEFAULT void isr_rtc(void);
+WEAK_DEFAULT void isr_eic0(void);
+WEAK_DEFAULT void isr_eic1(void);
+WEAK_DEFAULT void isr_eic2(void);
+WEAK_DEFAULT void isr_eic3(void);
+WEAK_DEFAULT void isr_eic_other(void);
+WEAK_DEFAULT void isr_freqm(void);
+WEAK_DEFAULT void isr_nvmctrl(void);
+WEAK_DEFAULT void isr_port(void);
+WEAK_DEFAULT void isr_dmac0(void);
+WEAK_DEFAULT void isr_dmac1(void);
+WEAK_DEFAULT void isr_dmac2(void);
+WEAK_DEFAULT void isr_dmac3(void);
+WEAK_DEFAULT void isr_dmac_other(void);
+WEAK_DEFAULT void isr_evsys0(void);
+WEAK_DEFAULT void isr_evsys1(void);
+WEAK_DEFAULT void isr_evsys2(void);
+WEAK_DEFAULT void isr_evsys3(void);
+WEAK_DEFAULT void isr_evsys_nschk(void);
+WEAK_DEFAULT void isr_pac(void);
+WEAK_DEFAULT void isr_sercom0_0(void);
+WEAK_DEFAULT void isr_sercom0_1(void);
+WEAK_DEFAULT void isr_sercom0_2(void);
+WEAK_DEFAULT void isr_sercom0_other(void);
+WEAK_DEFAULT void isr_sercom1_0(void);
+WEAK_DEFAULT void isr_sercom1_1(void);
+WEAK_DEFAULT void isr_sercom1_2(void);
+WEAK_DEFAULT void isr_sercom1_other(void);
+WEAK_DEFAULT void isr_sercom2_0(void);
+WEAK_DEFAULT void isr_sercom2_1(void);
+WEAK_DEFAULT void isr_sercom2_2(void);
+WEAK_DEFAULT void isr_sercom2_other(void);
+WEAK_DEFAULT void isr_tc0(void);
+WEAK_DEFAULT void isr_tc1(void);
+WEAK_DEFAULT void isr_tc2(void);
+WEAK_DEFAULT void isr_adc_other(void);
+WEAK_DEFAULT void isr_adc_resrdy(void);
+WEAK_DEFAULT void isr_ac(void);
+WEAK_DEFAULT void isr_dac_underrun_a(void);
+WEAK_DEFAULT void isr_dac_empty(void);
+WEAK_DEFAULT void isr_ptc(void);
+WEAK_DEFAULT void isr_trng(void);
+WEAK_DEFAULT void isr_tram(void);
+
+/* CPU specific interrupt vector table */
+ISR_VECTOR(1) const isr_t vector_cpu[CPU_IRQ_NUMOF] = {
+    (void*) isr_system,             /*  0 Main Clock */
+    (void*) isr_wdt,                /*  1 Watchdog Timer */
+    (void*) isr_rtc,                /*  2 Real-Time Counter */
+    (void*) isr_eic0,               /*  3 External Interrupt Controller */
+    (void*) isr_eic1,               /*  4 External Interrupt Controller */
+    (void*) isr_eic2,               /*  5 External Interrupt Controller */
+    (void*) isr_eic3,               /*  6 External Interrupt Controller */
+    (void*) isr_eic_other,          /*  7 External Interrupt Controller */
+    (void*) isr_freqm,              /*  8 Frequency Meter */
+    (void*) isr_nvmctrl,            /*  9 Non-Volatile Memory Controller */
+    (void*) isr_port,               /*  10 Port Module */
+    (void*) isr_dmac0,              /*  11 Direct Memory Access Controller */
+    (void*) isr_dmac1,              /*  12 Direct Memory Access Controller */
+    (void*) isr_dmac2,              /*  13 Direct Memory Access Controller */
+    (void*) isr_dmac3,              /*  14 Direct Memory Access Controller */
+    (void*) isr_dmac_other,         /*  15 Direct Memory Access Controller */
+    (void*) isr_evsys0,             /*  16 Event System Interface */
+    (void*) isr_evsys1,             /*  17 Event System Interface */
+    (void*) isr_evsys2,             /*  18 Event System Interface */
+    (void*) isr_evsys3,             /*  19 Event System Interface */
+    (void*) isr_evsys_nschk,        /*  20 Event System Interface */
+    (void*) isr_pac,                /*  21 Peripheral Access Controller */
+    (void*) isr_sercom0_0,          /*  22 Serial Communication Interface */
+    (void*) isr_sercom0_1,          /*  23 Serial Communication Interface */
+    (void*) isr_sercom0_2,          /*  24 Serial Communication Interface */
+    (void*) isr_sercom0_other,      /*  25 Serial Communication Interface */
+    (void*) isr_sercom1_0,          /*  26 Serial Communication Interface */
+    (void*) isr_sercom1_1,          /*  27 Serial Communication Interface */
+    (void*) isr_sercom1_2,          /*  28 Serial Communication Interface */
+    (void*) isr_sercom1_other,      /*  29 Serial Communication Interface */
+    (void*) isr_sercom2_0,          /*  30 Serial Communication Interface */
+    (void*) isr_sercom2_1,          /*  31 Serial Communication Interface */
+    (void*) isr_sercom2_2,          /*  32 Serial Communication Interface */
+    (void*) isr_sercom2_other,      /*  33 Serial Communication Interface */
+    (void*) isr_tc0,                /*  34 Basic Timer Counter  */
+    (void*) isr_tc1,                /*  35 Basic Timer Counter  */
+    (void*) isr_tc2,                /*  36 Basic Timer Counter  */
+    (void*) isr_adc_other,          /*  37 Analog Digital Converter */
+    (void*) isr_adc_resrdy,         /*  38 Analog Digital Converter */
+    (void*) isr_ac,                 /*  39 Analog Comparators */
+    (void*) isr_dac_underrun_a,     /*  40 Digital Analog Converter */
+    (void*) isr_dac_empty,          /*  41 Analog Digital Converter */
+    (void*) isr_ptc,                /*  42 Peripheral Touch Controller */
+    (void*) isr_trng,               /*  43 True Random Number Generator */
+    (void*) isr_tram,               /*  44 Trust RAM */
+};
-- 
GitLab