start with USB CDC echo example

this is the Atmel START USB CDC Echo example project for the
SAM E54 Xplained Pro board using an Atmel ATSAME54P20A
microcontroller.
Atmel START information:
- Version: 1.4.1810 (Dec 18, 2018, 5:52 AM GMT+1)
- Server: 1.4.93
- Content version: 1.0.1340

This will serve as basis for the sysmoOCTSIM project

A jenkins contrib script has also been added to the
osmo-ccid-firmware project to build the sysmoOCTSIM firmware

Change-Id: I356de75e7b730d63fb819248e71d36f785932199
diff --git a/sysmoOCTSIM/hpl/cmcc/hpl_cmcc.c b/sysmoOCTSIM/hpl/cmcc/hpl_cmcc.c
new file mode 100644
index 0000000..bddf0e1
--- /dev/null
+++ b/sysmoOCTSIM/hpl/cmcc/hpl_cmcc.c
@@ -0,0 +1,354 @@
+/**
+ * \file
+ *
+ * \brief Generic CMCC(Cortex M Cache Controller) related functionality.
+ *
+ * Copyright (c)2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS".  NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
+ */
+
+#include <compiler.h>
+#include <hpl_cmcc.h>
+#include <hpl_cmcc_config.h>
+
+/**
+ * \brief Initialize Cache Module
+ *
+ * This function does low level cache configuration.
+ *
+ * \return initialize status
+ */
+int32_t _cmcc_init(void)
+{
+	int32_t return_value;
+
+	_cmcc_disable(CMCC);
+
+	if (_is_cache_disabled(CMCC)) {
+		hri_cmcc_write_CFG_reg(
+		    CMCC,
+		    (CMCC_CFG_CSIZESW(CONF_CMCC_CACHE_SIZE) | (CONF_CMCC_DATA_CACHE_DISABLE << CMCC_CFG_DCDIS_Pos)
+		     | (CONF_CMCC_INST_CACHE_DISABLE << CMCC_CFG_ICDIS_Pos) | (CONF_CMCC_CLK_GATING_DISABLE)));
+
+		_cmcc_enable(CMCC);
+		return_value = _is_cache_enabled(CMCC) == true ? ERR_NONE : ERR_FAILURE;
+	} else {
+		return_value = ERR_NOT_INITIALIZED;
+	}
+
+	return return_value;
+}
+
+/**
+ * \brief Configure CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ * \param[in] cache configuration structure pointer
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_configure(const void *hw, struct _cache_cfg *cache_ctrl)
+{
+	int32_t return_value;
+
+	_cmcc_disable(hw);
+
+	if (_is_cache_disabled(hw)) {
+		hri_cmcc_write_CFG_reg(
+		    hw,
+		    (CMCC_CFG_CSIZESW(cache_ctrl->cache_size) | (cache_ctrl->data_cache_disable << CMCC_CFG_DCDIS_Pos)
+		     | (cache_ctrl->inst_cache_disable << CMCC_CFG_ICDIS_Pos) | (cache_ctrl->gclk_gate_disable)));
+
+		return_value = ERR_NONE;
+	} else {
+		return_value = ERR_NOT_INITIALIZED;
+	}
+
+	return return_value;
+}
+
+/**
+ * \brief Enable data cache in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ * \param[in] boolean 1 -> Enable the data cache, 0 -> disable the data cache
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_enable_data_cache(const void *hw, bool value)
+{
+	uint32_t tmp;
+	int32_t  ret;
+
+	tmp = hri_cmcc_read_CFG_reg(hw);
+	tmp &= ~CMCC_CFG_DCDIS;
+	tmp |= ((!value) << CMCC_CFG_DCDIS_Pos);
+
+	ret = _cmcc_disable(hw);
+	hri_cmcc_write_CFG_reg(hw, tmp);
+	ret = _cmcc_enable(hw);
+
+	return ret;
+}
+
+/**
+ * \brief Enable instruction cache in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ * \param[in] boolean 1 -> Enable the inst cache, 0 -> disable the inst cache
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_enable_inst_cache(const void *hw, bool value)
+{
+	uint32_t tmp;
+	int32_t  ret;
+
+	tmp = hri_cmcc_read_CFG_reg(hw);
+	tmp &= ~CMCC_CFG_ICDIS;
+	tmp |= ((!value) << CMCC_CFG_ICDIS_Pos);
+
+	ret = _cmcc_disable(hw);
+	hri_cmcc_write_CFG_reg(hw, tmp);
+	ret = _cmcc_enable(hw);
+
+	return ret;
+}
+
+/**
+ * \brief Enable clock gating in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ * \param[in] boolean 1 -> Enable the clock gate, 0 -> disable the clock gate
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_enable_clock_gating(const void *hw, bool value)
+{
+	uint32_t tmp;
+	int32_t  ret;
+
+	tmp = hri_cmcc_read_CFG_reg(hw);
+	tmp |= value;
+
+	ret = _cmcc_disable(hw);
+	hri_cmcc_write_CFG_reg(hw, tmp);
+	ret = _cmcc_enable(hw);
+
+	return ret;
+}
+
+/**
+ * \brief Configure the cache size in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ * \param[in] element from cache size configuration enumerator
+ *				0->1K, 1->2K, 2->4K(default)
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_configure_cache_size(const void *hw, enum conf_cache_size size)
+{
+	uint32_t tmp;
+	int32_t  ret;
+
+	tmp = hri_cmcc_read_CFG_reg(hw);
+	tmp &= (~CMCC_CFG_CSIZESW_Msk);
+	tmp |= (size << CMCC_CFG_CSIZESW_Pos);
+
+	ret = _cmcc_disable(hw);
+	hri_cmcc_write_CFG_reg(hw, tmp);
+	ret = _cmcc_enable(hw);
+
+	return ret;
+}
+
+/**
+ * \brief Lock the mentioned WAY in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ * \param[in] element from "way_num_index" enumerator
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_lock_way(const void *hw, enum way_num_index num)
+{
+	uint32_t tmp;
+	int32_t  ret;
+
+	tmp = hri_cmcc_read_LCKWAY_reg(hw);
+	tmp |= CMCC_LCKWAY_LCKWAY(num);
+
+	ret = _cmcc_disable(hw);
+	hri_cmcc_write_LCKWAY_reg(hw, tmp);
+	ret = _cmcc_enable(hw);
+
+	return ret;
+}
+
+/**
+ * \brief Unlock the mentioned WAY in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ * \param[in] element from "way_num_index" enumerator
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_unlock_way(const void *hw, enum way_num_index num)
+{
+	uint32_t tmp;
+	int32_t  ret;
+
+	tmp = hri_cmcc_read_LCKWAY_reg(hw);
+	tmp &= (~CMCC_LCKWAY_LCKWAY(num));
+
+	ret = _cmcc_disable(hw);
+	hri_cmcc_write_LCKWAY_reg(hw, tmp);
+	ret = _cmcc_enable(hw);
+
+	return ret;
+}
+
+/**
+ * \brief Invalidate the mentioned cache line in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ * \param[in] element from "way_num" enumerator (valid arg is 0-3)
+ * \param[in] line number (valid arg is 0-63 as each way will have 64 lines)
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_invalidate_by_line(const void *hw, uint8_t way_num, uint8_t line_num)
+{
+	int32_t return_value;
+
+	if ((way_num < CMCC_WAY_NOS) && (line_num < CMCC_LINE_NOS)) {
+		_cmcc_disable(hw);
+		while (!(_is_cache_disabled(hw)))
+			;
+		hri_cmcc_write_MAINT1_reg(hw, (CMCC_MAINT1_INDEX(line_num) | CMCC_MAINT1_WAY(way_num)));
+		return_value = ERR_NONE;
+	} else {
+		return_value = ERR_INVALID_ARG;
+	}
+
+	return return_value;
+}
+
+/**
+ * \brief Invalidate entire cache entries in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_invalidate_all(const void *hw)
+{
+	int32_t return_value;
+
+	_cmcc_disable(hw);
+	if (_is_cache_disabled(hw)) {
+		hri_cmcc_write_MAINT0_reg(hw, CMCC_MAINT0_INVALL);
+		return_value = ERR_NONE;
+	} else {
+		return_value = ERR_FAILURE;
+	}
+
+	return return_value;
+}
+
+/**
+ * \brief Configure cache monitor in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ * \param[in] element from cache monitor configurations enumerator
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_configure_monitor(const void *hw, enum conf_cache_monitor monitor_cfg)
+{
+	hri_cmcc_write_MCFG_reg(hw, CMCC_MCFG_MODE(monitor_cfg));
+
+	return ERR_NONE;
+}
+
+/**
+ * \brief Enable cache monitor in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_enable_monitor(const void *hw)
+{
+	hri_cmcc_write_MEN_reg(hw, CMCC_MEN_MENABLE);
+
+	return ERR_NONE;
+}
+
+/**
+ * \brief Disable cache monitor in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_disable_monitor(const void *hw)
+{
+	hri_cmcc_write_MEN_reg(hw, (CMCC_MONITOR_DISABLE << CMCC_MEN_MENABLE_Pos));
+
+	return ERR_NONE;
+}
+
+/**
+ * \brief Reset cache monitor in CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ *
+ * \return status of operation
+ */
+int32_t _cmcc_reset_monitor(const void *hw)
+{
+	hri_cmcc_write_MCTRL_reg(hw, CMCC_MCTRL_SWRST);
+
+	return ERR_NONE;
+}
+
+/**
+ * \brief Get cache monitor event counter value from CMCC module
+ *
+ * \param[in] pointer pointing to the starting address of CMCC module
+ *
+ * \return event counter value
+ */
+uint32_t _cmcc_get_monitor_event_count(const void *hw)
+{
+	return hri_cmcc_read_MSR_reg(hw);
+}
diff --git a/sysmoOCTSIM/hpl/core/hpl_core_m4.c b/sysmoOCTSIM/hpl/core/hpl_core_m4.c
new file mode 100644
index 0000000..acb75bc
--- /dev/null
+++ b/sysmoOCTSIM/hpl/core/hpl_core_m4.c
@@ -0,0 +1,235 @@
+/**
+ * \file
+ *
+ * \brief Core related functionality implementation.
+ *
+ * Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <hpl_core.h>
+#include <hpl_irq.h>
+#ifndef _UNIT_TEST_
+#include <utils.h>
+#endif
+#include <utils_assert.h>
+#include <peripheral_clk_config.h>
+
+#ifndef CONF_CPU_FREQUENCY
+#define CONF_CPU_FREQUENCY 1000000
+#endif
+
+#if CONF_CPU_FREQUENCY < 1000
+#define CPU_FREQ_POWER 3
+#elif CONF_CPU_FREQUENCY < 10000
+#define CPU_FREQ_POWER 4
+#elif CONF_CPU_FREQUENCY < 100000
+#define CPU_FREQ_POWER 5
+#elif CONF_CPU_FREQUENCY < 1000000
+#define CPU_FREQ_POWER 6
+#elif CONF_CPU_FREQUENCY < 10000000
+#define CPU_FREQ_POWER 7
+#elif CONF_CPU_FREQUENCY < 100000000
+#define CPU_FREQ_POWER 8
+#elif CONF_CPU_FREQUENCY < 1000000000
+#define CPU_FREQ_POWER 9
+#endif
+
+/**
+ * \brief The array of interrupt handlers
+ */
+struct _irq_descriptor *_irq_table[PERIPH_COUNT_IRQn];
+
+/**
+ * \brief Reset MCU
+ */
+void _reset_mcu(void)
+{
+	NVIC_SystemReset();
+}
+
+/**
+ * \brief Put MCU to sleep
+ */
+void _go_to_sleep(void)
+{
+	__DSB();
+	__WFI();
+}
+
+/**
+ * \brief Retrieve current IRQ number
+ */
+uint8_t _irq_get_current(void)
+{
+	return (uint8_t)__get_IPSR() - 16;
+}
+
+/**
+ * \brief Disable the given IRQ
+ */
+void _irq_disable(uint8_t n)
+{
+	NVIC_DisableIRQ((IRQn_Type)n);
+}
+
+/**
+ * \brief Set the given IRQ
+ */
+void _irq_set(uint8_t n)
+{
+	NVIC_SetPendingIRQ((IRQn_Type)n);
+}
+
+/**
+ * \brief Clear the given IRQ
+ */
+void _irq_clear(uint8_t n)
+{
+	NVIC_ClearPendingIRQ((IRQn_Type)n);
+}
+
+/**
+ * \brief Enable the given IRQ
+ */
+void _irq_enable(uint8_t n)
+{
+	NVIC_EnableIRQ((IRQn_Type)n);
+}
+
+/**
+ * \brief Register IRQ handler
+ */
+void _irq_register(const uint8_t n, struct _irq_descriptor *const irq)
+{
+	ASSERT(n < PERIPH_COUNT_IRQn);
+
+	_irq_table[n] = irq;
+}
+
+/**
+ * \brief Default interrupt handler for unused IRQs.
+ */
+void Default_Handler(void)
+{
+	while (1) {
+	}
+}
+
+/**
+ * \brief Retrieve the amount of cycles to delay for the given amount of us
+ */
+static inline uint32_t _get_cycles_for_us_internal(const uint16_t us, const uint32_t freq, const uint8_t power)
+{
+	switch (power) {
+	case 9:
+		return (us * (freq / 1000000) + 2) / 3;
+	case 8:
+		return (us * (freq / 100000) + 29) / 30;
+	case 7:
+		return (us * (freq / 10000) + 299) / 300;
+	case 6:
+		return (us * (freq / 1000) + 2999) / 3000;
+	case 5:
+		return (us * (freq / 100) + 29999) / 30000;
+	case 4:
+		return (us * (freq / 10) + 299999) / 300000;
+	default:
+		return (us * freq + 2999999) / 3000000;
+	}
+}
+
+/**
+ * \brief Retrieve the amount of cycles to delay for the given amount of us
+ */
+uint32_t _get_cycles_for_us(const uint16_t us)
+{
+	return _get_cycles_for_us_internal(us, CONF_CPU_FREQUENCY, CPU_FREQ_POWER);
+}
+
+/**
+ * \brief Retrieve the amount of cycles to delay for the given amount of ms
+ */
+static inline uint32_t _get_cycles_for_ms_internal(const uint16_t ms, const uint32_t freq, const uint8_t power)
+{
+	switch (power) {
+	case 9:
+		return (ms * (freq / 1000000) + 2) / 3 * 1000;
+	case 8:
+		return (ms * (freq / 100000) + 2) / 3 * 100;
+	case 7:
+		return (ms * (freq / 10000) + 2) / 3 * 10;
+	case 6:
+		return (ms * (freq / 1000) + 2) / 3;
+	case 5:
+		return (ms * (freq / 100) + 29) / 30;
+	case 4:
+		return (ms * (freq / 10) + 299) / 300;
+	default:
+		return (ms * (freq / 1) + 2999) / 3000;
+	}
+}
+
+/**
+ * \brief Retrieve the amount of cycles to delay for the given amount of ms
+ */
+uint32_t _get_cycles_for_ms(const uint16_t ms)
+{
+	return _get_cycles_for_ms_internal(ms, CONF_CPU_FREQUENCY, CPU_FREQ_POWER);
+}
+/**
+ * \brief Initialize delay functionality
+ */
+void _delay_init(void *const hw)
+{
+	(void)hw;
+}
+/**
+ * \brief Delay loop to delay n number of cycles
+ */
+void _delay_cycles(void *const hw, uint32_t cycles)
+{
+#ifndef _UNIT_TEST_
+	(void)hw;
+	(void)cycles;
+#if defined __GNUC__
+	__asm(".syntax unified\n"
+	      "__delay:\n"
+	      "subs r1, r1, #1\n"
+	      "bhi __delay\n"
+	      ".syntax divided");
+#elif defined __CC_ARM
+	__asm("__delay:\n"
+	      "subs cycles, cycles, #1\n"
+	      "bhi __delay\n");
+#elif defined __ICCARM__
+	__asm("__delay:\n"
+	      "subs r1, r1, #1\n"
+	      "bhi.n __delay\n");
+#endif
+#endif
+}
diff --git a/sysmoOCTSIM/hpl/core/hpl_core_port.h b/sysmoOCTSIM/hpl/core/hpl_core_port.h
new file mode 100644
index 0000000..3f3e8f2
--- /dev/null
+++ b/sysmoOCTSIM/hpl/core/hpl_core_port.h
@@ -0,0 +1,61 @@
+/**
+ * \file
+ *
+ * \brief Core related functionality implementation.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#ifndef _HPL_CORE_PORT_H_INCLUDED
+#define _HPL_CORE_PORT_H_INCLUDED
+
+#include <peripheral_clk_config.h>
+
+/* It's possible to include this file in ARM ASM files (e.g., in FreeRTOS IAR
+ * portable implement, portasm.s -> FreeRTOSConfig.h -> hpl_core_port.h),
+ * there will be assembling errors.
+ * So the following things are not included for assembling.
+ */
+#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
+
+#ifndef _UNIT_TEST_
+#include <compiler.h>
+#endif
+
+/**
+ * \brief Check if it's in ISR handling
+ * \return \c true if it's in ISR
+ */
+static inline bool _is_in_isr(void)
+{
+	return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk);
+}
+
+#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
+
+#endif /* _HPL_CORE_PORT_H_INCLUDED */
diff --git a/sysmoOCTSIM/hpl/core/hpl_init.c b/sysmoOCTSIM/hpl/core/hpl_init.c
new file mode 100644
index 0000000..be0db93
--- /dev/null
+++ b/sysmoOCTSIM/hpl/core/hpl_init.c
@@ -0,0 +1,78 @@
+/**
+ * \file
+ *
+ * \brief HPL initialization related functionality implementation.
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <hpl_gpio.h>
+#include <hpl_init.h>
+#include <hpl_gclk_base.h>
+#include <hpl_mclk_config.h>
+
+#include <hpl_dma.h>
+#include <hpl_dmac_config.h>
+#include <hpl_cmcc_config.h>
+#include <hal_cache.h>
+
+/* Referenced GCLKs (out of 0~11), should be initialized firstly
+ */
+#define _GCLK_INIT_1ST 0x00000000
+/* Not referenced GCLKs, initialized last */
+#define _GCLK_INIT_LAST 0x00000FFF
+
+/**
+ * \brief Initialize the hardware abstraction layer
+ */
+void _init_chip(void)
+{
+	hri_nvmctrl_set_CTRLA_RWS_bf(NVMCTRL, CONF_NVM_WAIT_STATE);
+
+	_osc32kctrl_init_sources();
+	_oscctrl_init_sources();
+	_mclk_init();
+#if _GCLK_INIT_1ST
+	_gclk_init_generators_by_fref(_GCLK_INIT_1ST);
+#endif
+	_oscctrl_init_referenced_generators();
+	_gclk_init_generators_by_fref(_GCLK_INIT_LAST);
+
+#if CONF_DMAC_ENABLE
+	hri_mclk_set_AHBMASK_DMAC_bit(MCLK);
+	_dma_init();
+#endif
+
+#if (CONF_PORT_EVCTRL_PORT_0 | CONF_PORT_EVCTRL_PORT_1 | CONF_PORT_EVCTRL_PORT_2 | CONF_PORT_EVCTRL_PORT_3)
+	_port_event_init();
+#endif
+
+#if CONF_CMCC_ENABLE
+	cache_init();
+#endif
+}
diff --git a/sysmoOCTSIM/hpl/dmac/hpl_dmac.c b/sysmoOCTSIM/hpl/dmac/hpl_dmac.c
new file mode 100644
index 0000000..27021dd
--- /dev/null
+++ b/sysmoOCTSIM/hpl/dmac/hpl_dmac.c
@@ -0,0 +1,262 @@
+
+/**
+ * \file
+ *
+ * \brief Generic DMAC related functionality.
+ *
+ * Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+#include <hpl_dma.h>
+#include <utils_assert.h>
+#include <utils.h>
+#include <hpl_dmac_config.h>
+#include <utils_repeat_macro.h>
+
+#if CONF_DMAC_ENABLE
+/* Section containing first descriptors for all DMAC channels */
+COMPILER_ALIGNED(16)
+DmacDescriptor _descriptor_section[DMAC_CH_NUM];
+
+/* Section containing current descriptors for all DMAC channels */
+COMPILER_ALIGNED(16)
+DmacDescriptor _write_back_section[DMAC_CH_NUM];
+
+/* Array containing callbacks for DMAC channels */
+static struct _dma_resource _resources[DMAC_CH_NUM];
+
+/* DMAC interrupt handler */
+static void _dmac_handler(void);
+
+/* This macro DMAC configuration */
+#define DMAC_CHANNEL_CFG(i, n)                                                                                         \
+	{(CONF_DMAC_RUNSTDBY_##n << DMAC_CHCTRLA_RUNSTDBY_Pos) | DMAC_CHCTRLA_TRIGACT(CONF_DMAC_TRIGACT_##n)               \
+	     | DMAC_CHCTRLA_TRIGSRC(CONF_DMAC_TRIGSRC_##n),                                                                \
+	 DMAC_CHPRILVL_PRILVL(CONF_DMAC_LVL_##n),                                                                          \
+	 (CONF_DMAC_EVIE_##n << DMAC_CHEVCTRL_EVIE_Pos) | (CONF_DMAC_EVOE_##n << DMAC_CHEVCTRL_EVOE_Pos)                   \
+	     | (CONF_DMAC_EVACT_##n << DMAC_CHEVCTRL_EVACT_Pos),                                                           \
+	 DMAC_BTCTRL_STEPSIZE(CONF_DMAC_STEPSIZE_##n) | (CONF_DMAC_STEPSEL_##n << DMAC_BTCTRL_STEPSEL_Pos)                 \
+	     | (CONF_DMAC_DSTINC_##n << DMAC_BTCTRL_DSTINC_Pos) | (CONF_DMAC_SRCINC_##n << DMAC_BTCTRL_SRCINC_Pos)         \
+	     | DMAC_BTCTRL_BEATSIZE(CONF_DMAC_BEATSIZE_##n) | DMAC_BTCTRL_BLOCKACT(CONF_DMAC_BLOCKACT_##n)                 \
+	     | DMAC_BTCTRL_EVOSEL(CONF_DMAC_EVOSEL_##n)},
+
+/* DMAC channel configuration */
+struct dmac_channel_cfg {
+	uint32_t ctrla;
+	uint8_t  prilvl;
+	uint8_t  evctrl;
+	uint16_t btctrl;
+};
+
+/* DMAC channel configurations */
+const static struct dmac_channel_cfg _cfgs[] = {REPEAT_MACRO(DMAC_CHANNEL_CFG, i, DMAC_CH_NUM)};
+
+/**
+ * \brief Initialize DMAC
+ */
+int32_t _dma_init(void)
+{
+	uint8_t i;
+
+	hri_dmac_clear_CTRL_DMAENABLE_bit(DMAC);
+	hri_dmac_clear_CRCCTRL_reg(DMAC, DMAC_CRCCTRL_CRCSRC_Msk);
+	hri_dmac_set_CTRL_SWRST_bit(DMAC);
+	while (hri_dmac_get_CTRL_SWRST_bit(DMAC))
+		;
+
+	hri_dmac_write_CTRL_reg(DMAC,
+	                        (CONF_DMAC_LVLEN0 << DMAC_CTRL_LVLEN0_Pos) | (CONF_DMAC_LVLEN1 << DMAC_CTRL_LVLEN1_Pos)
+	                            | (CONF_DMAC_LVLEN2 << DMAC_CTRL_LVLEN2_Pos)
+	                            | (CONF_DMAC_LVLEN3 << DMAC_CTRL_LVLEN3_Pos));
+	hri_dmac_write_DBGCTRL_DBGRUN_bit(DMAC, CONF_DMAC_DBGRUN);
+
+	hri_dmac_write_PRICTRL0_reg(
+	    DMAC,
+	    DMAC_PRICTRL0_LVLPRI0(CONF_DMAC_LVLPRI0) | DMAC_PRICTRL0_LVLPRI1(CONF_DMAC_LVLPRI1)
+	        | DMAC_PRICTRL0_LVLPRI2(CONF_DMAC_LVLPRI2) | DMAC_PRICTRL0_LVLPRI3(CONF_DMAC_LVLPRI3)
+	        | (CONF_DMAC_RRLVLEN0 << DMAC_PRICTRL0_RRLVLEN0_Pos) | (CONF_DMAC_RRLVLEN1 << DMAC_PRICTRL0_RRLVLEN1_Pos)
+	        | (CONF_DMAC_RRLVLEN2 << DMAC_PRICTRL0_RRLVLEN2_Pos) | (CONF_DMAC_RRLVLEN3 << DMAC_PRICTRL0_RRLVLEN3_Pos));
+	hri_dmac_write_BASEADDR_reg(DMAC, (uint32_t)_descriptor_section);
+	hri_dmac_write_WRBADDR_reg(DMAC, (uint32_t)_write_back_section);
+
+	for (i = 0; i < DMAC_CH_NUM; i++) {
+		hri_dmac_write_CHCTRLA_reg(DMAC, i, _cfgs[i].ctrla);
+		hri_dmac_write_CHPRILVL_reg(DMAC, i, _cfgs[i].prilvl);
+		hri_dmac_write_CHEVCTRL_reg(DMAC, i, _cfgs[i].evctrl);
+		hri_dmacdescriptor_write_BTCTRL_reg(&_descriptor_section[i], _cfgs[i].btctrl);
+	}
+
+	for (i = 0; i < 5; i++) {
+		NVIC_DisableIRQ(DMAC_0_IRQn + i);
+		NVIC_ClearPendingIRQ(DMAC_0_IRQn + i);
+		NVIC_EnableIRQ(DMAC_0_IRQn + i);
+	}
+
+	hri_dmac_set_CTRL_DMAENABLE_bit(DMAC);
+
+	return ERR_NONE;
+}
+
+/**
+ * \brief Enable/disable DMA interrupt
+ */
+void _dma_set_irq_state(const uint8_t channel, const enum _dma_callback_type type, const bool state)
+{
+	if (DMA_TRANSFER_COMPLETE_CB == type) {
+		hri_dmac_write_CHINTEN_TCMPL_bit(DMAC, channel, state);
+	} else if (DMA_TRANSFER_ERROR_CB == type) {
+		hri_dmac_write_CHINTEN_TERR_bit(DMAC, channel, state);
+	}
+}
+
+int32_t _dma_set_destination_address(const uint8_t channel, const void *const dst)
+{
+	hri_dmacdescriptor_write_DSTADDR_reg(&_descriptor_section[channel], (uint32_t)dst);
+
+	return ERR_NONE;
+}
+
+int32_t _dma_set_source_address(const uint8_t channel, const void *const src)
+{
+	hri_dmacdescriptor_write_SRCADDR_reg(&_descriptor_section[channel], (uint32_t)src);
+
+	return ERR_NONE;
+}
+
+int32_t _dma_set_next_descriptor(const uint8_t current_channel, const uint8_t next_channel)
+{
+	hri_dmacdescriptor_write_DESCADDR_reg(&_descriptor_section[current_channel],
+	                                      (uint32_t)&_descriptor_section[next_channel]);
+
+	return ERR_NONE;
+}
+
+int32_t _dma_srcinc_enable(const uint8_t channel, const bool enable)
+{
+	hri_dmacdescriptor_write_BTCTRL_SRCINC_bit(&_descriptor_section[channel], enable);
+
+	return ERR_NONE;
+}
+
+int32_t _dma_set_data_amount(const uint8_t channel, const uint32_t amount)
+{
+	uint32_t address   = hri_dmacdescriptor_read_DSTADDR_reg(&_descriptor_section[channel]);
+	uint8_t  beat_size = hri_dmacdescriptor_read_BTCTRL_BEATSIZE_bf(&_descriptor_section[channel]);
+
+	if (hri_dmacdescriptor_get_BTCTRL_DSTINC_bit(&_descriptor_section[channel])) {
+		hri_dmacdescriptor_write_DSTADDR_reg(&_descriptor_section[channel], address + amount * (1 << beat_size));
+	}
+
+	address = hri_dmacdescriptor_read_SRCADDR_reg(&_descriptor_section[channel]);
+
+	if (hri_dmacdescriptor_get_BTCTRL_SRCINC_bit(&_descriptor_section[channel])) {
+		hri_dmacdescriptor_write_SRCADDR_reg(&_descriptor_section[channel], address + amount * (1 << beat_size));
+	}
+
+	hri_dmacdescriptor_write_BTCNT_reg(&_descriptor_section[channel], amount);
+
+	return ERR_NONE;
+}
+
+int32_t _dma_enable_transaction(const uint8_t channel, const bool software_trigger)
+{
+	hri_dmacdescriptor_set_BTCTRL_VALID_bit(&_descriptor_section[channel]);
+	hri_dmac_set_CHCTRLA_ENABLE_bit(DMAC, channel);
+
+	if (software_trigger) {
+		hri_dmac_set_SWTRIGCTRL_reg(DMAC, 1 << channel);
+	}
+
+	return ERR_NONE;
+}
+
+int32_t _dma_get_channel_resource(struct _dma_resource **resource, const uint8_t channel)
+{
+	*resource = &_resources[channel];
+
+	return ERR_NONE;
+}
+
+int32_t _dma_dstinc_enable(const uint8_t channel, const bool enable)
+{
+	hri_dmacdescriptor_write_BTCTRL_DSTINC_bit(&_descriptor_section[channel], enable);
+
+	return ERR_NONE;
+}
+/**
+ * \internal DMAC interrupt handler
+ */
+static void _dmac_handler(void)
+{
+	uint8_t               channel      = hri_dmac_get_INTPEND_reg(DMAC, DMAC_INTPEND_ID_Msk);
+	struct _dma_resource *tmp_resource = &_resources[channel];
+
+	if (hri_dmac_get_CHINTFLAG_TERR_bit(DMAC, channel)) {
+		hri_dmac_clear_CHINTFLAG_TERR_bit(DMAC, channel);
+		tmp_resource->dma_cb.error(tmp_resource);
+	} else if (hri_dmac_get_CHINTFLAG_TCMPL_bit(DMAC, channel)) {
+		hri_dmac_clear_CHINTFLAG_TCMPL_bit(DMAC, channel);
+		tmp_resource->dma_cb.transfer_done(tmp_resource);
+	}
+}
+/**
+ * \brief DMAC interrupt handler
+ */
+void DMAC_0_Handler(void)
+{
+	_dmac_handler();
+}
+/**
+ * \brief DMAC interrupt handler
+ */
+void DMAC_1_Handler(void)
+{
+	_dmac_handler();
+}
+/**
+ * \brief DMAC interrupt handler
+ */
+void DMAC_2_Handler(void)
+{
+	_dmac_handler();
+}
+/**
+ * \brief DMAC interrupt handler
+ */
+void DMAC_3_Handler(void)
+{
+	_dmac_handler();
+}
+/**
+ * \brief DMAC interrupt handler
+ */
+void DMAC_4_Handler(void)
+{
+	_dmac_handler();
+}
+
+#endif /* CONF_DMAC_ENABLE */
diff --git a/sysmoOCTSIM/hpl/gclk/hpl_gclk.c b/sysmoOCTSIM/hpl/gclk/hpl_gclk.c
new file mode 100644
index 0000000..211ccc3
--- /dev/null
+++ b/sysmoOCTSIM/hpl/gclk/hpl_gclk.c
@@ -0,0 +1,312 @@
+
+/**
+ * \file
+ *
+ * \brief Generic Clock Controller related functionality.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <hpl_gclk_config.h>
+#include <hpl_init.h>
+#include <utils_assert.h>
+
+/**
+ * \brief Initializes generators
+ */
+void _gclk_init_generators(void)
+{
+
+#if CONF_GCLK_GENERATOR_0_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    0,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_0_DIV) | (CONF_GCLK_GEN_0_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_0_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_0_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_0_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_0_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_0_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_0_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_1_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    1,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_1_DIV) | (CONF_GCLK_GEN_1_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_1_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_1_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_1_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_1_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_1_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_1_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_2_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    2,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_2_DIV) | (CONF_GCLK_GEN_2_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_2_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_2_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_2_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_2_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_2_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_2_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_3_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    3,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_3_DIV) | (CONF_GCLK_GEN_3_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_3_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_3_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_3_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_3_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_3_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_3_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_4_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    4,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_4_DIV) | (CONF_GCLK_GEN_4_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_4_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_4_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_4_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_4_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_4_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_4_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_5_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    5,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_5_DIV) | (CONF_GCLK_GEN_5_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_5_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_5_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_5_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_5_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_5_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_5_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_6_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    6,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_6_DIV) | (CONF_GCLK_GEN_6_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_6_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_6_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_6_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_6_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_6_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_6_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_7_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    7,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_7_DIV) | (CONF_GCLK_GEN_7_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_7_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_7_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_7_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_7_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_7_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_7_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_8_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    8,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_8_DIV) | (CONF_GCLK_GEN_8_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_8_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_8_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_8_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_8_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_8_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_8_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_9_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    9,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_9_DIV) | (CONF_GCLK_GEN_9_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_9_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_9_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_9_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_9_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_9_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_9_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_10_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    10,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_10_DIV) | (CONF_GCLK_GEN_10_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_10_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_10_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_10_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_10_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_10_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_10_SOURCE);
+#endif
+
+#if CONF_GCLK_GENERATOR_11_CONFIG == 1
+	hri_gclk_write_GENCTRL_reg(
+	    GCLK,
+	    11,
+	    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_11_DIV) | (CONF_GCLK_GEN_11_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+	        | (CONF_GCLK_GEN_11_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_11_OE << GCLK_GENCTRL_OE_Pos)
+	        | (CONF_GCLK_GEN_11_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_11_IDC << GCLK_GENCTRL_IDC_Pos)
+	        | (CONF_GCLK_GENERATOR_11_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_11_SOURCE);
+#endif
+}
+
+void _gclk_init_generators_by_fref(uint32_t bm)
+{
+
+#if CONF_GCLK_GENERATOR_0_CONFIG == 1
+	if (bm & (1ul << 0)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    0,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_0_DIV) | (CONF_GCLK_GEN_0_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_0_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_0_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_0_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_0_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_0_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_0_SOURCE);
+	}
+#endif
+
+#if CONF_GCLK_GENERATOR_1_CONFIG == 1
+	if (bm & (1ul << 1)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    1,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_1_DIV) | (CONF_GCLK_GEN_1_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_1_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_1_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_1_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_1_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_1_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_1_SOURCE);
+	}
+#endif
+
+#if CONF_GCLK_GENERATOR_2_CONFIG == 1
+	if (bm & (1ul << 2)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    2,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_2_DIV) | (CONF_GCLK_GEN_2_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_2_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_2_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_2_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_2_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_2_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_2_SOURCE);
+	}
+#endif
+
+#if CONF_GCLK_GENERATOR_3_CONFIG == 1
+	if (bm & (1ul << 3)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    3,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_3_DIV) | (CONF_GCLK_GEN_3_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_3_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_3_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_3_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_3_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_3_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_3_SOURCE);
+	}
+#endif
+
+#if CONF_GCLK_GENERATOR_4_CONFIG == 1
+	if (bm & (1ul << 4)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    4,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_4_DIV) | (CONF_GCLK_GEN_4_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_4_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_4_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_4_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_4_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_4_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_4_SOURCE);
+	}
+#endif
+
+#if CONF_GCLK_GENERATOR_5_CONFIG == 1
+	if (bm & (1ul << 5)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    5,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_5_DIV) | (CONF_GCLK_GEN_5_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_5_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_5_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_5_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_5_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_5_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_5_SOURCE);
+	}
+#endif
+
+#if CONF_GCLK_GENERATOR_6_CONFIG == 1
+	if (bm & (1ul << 6)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    6,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_6_DIV) | (CONF_GCLK_GEN_6_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_6_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_6_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_6_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_6_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_6_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_6_SOURCE);
+	}
+#endif
+
+#if CONF_GCLK_GENERATOR_7_CONFIG == 1
+	if (bm & (1ul << 7)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    7,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_7_DIV) | (CONF_GCLK_GEN_7_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_7_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_7_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_7_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_7_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_7_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_7_SOURCE);
+	}
+#endif
+
+#if CONF_GCLK_GENERATOR_8_CONFIG == 1
+	if (bm & (1ul << 8)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    8,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_8_DIV) | (CONF_GCLK_GEN_8_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_8_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_8_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_8_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_8_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_8_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_8_SOURCE);
+	}
+#endif
+
+#if CONF_GCLK_GENERATOR_9_CONFIG == 1
+	if (bm & (1ul << 9)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    9,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_9_DIV) | (CONF_GCLK_GEN_9_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_9_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_9_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_9_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_9_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_9_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_9_SOURCE);
+	}
+#endif
+
+#if CONF_GCLK_GENERATOR_10_CONFIG == 1
+	if (bm & (1ul << 10)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    10,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_10_DIV) | (CONF_GCLK_GEN_10_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_10_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_10_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_10_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_10_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_10_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_10_SOURCE);
+	}
+#endif
+
+#if CONF_GCLK_GENERATOR_11_CONFIG == 1
+	if (bm & (1ul << 11)) {
+		hri_gclk_write_GENCTRL_reg(
+		    GCLK,
+		    11,
+		    GCLK_GENCTRL_DIV(CONF_GCLK_GEN_11_DIV) | (CONF_GCLK_GEN_11_RUNSTDBY << GCLK_GENCTRL_RUNSTDBY_Pos)
+		        | (CONF_GCLK_GEN_11_DIVSEL << GCLK_GENCTRL_DIVSEL_Pos) | (CONF_GCLK_GEN_11_OE << GCLK_GENCTRL_OE_Pos)
+		        | (CONF_GCLK_GEN_11_OOV << GCLK_GENCTRL_OOV_Pos) | (CONF_GCLK_GEN_11_IDC << GCLK_GENCTRL_IDC_Pos)
+		        | (CONF_GCLK_GENERATOR_11_CONFIG << GCLK_GENCTRL_GENEN_Pos) | CONF_GCLK_GEN_11_SOURCE);
+	}
+#endif
+}
diff --git a/sysmoOCTSIM/hpl/gclk/hpl_gclk_base.h b/sysmoOCTSIM/hpl/gclk/hpl_gclk_base.h
new file mode 100644
index 0000000..3e7d282
--- /dev/null
+++ b/sysmoOCTSIM/hpl/gclk/hpl_gclk_base.h
@@ -0,0 +1,87 @@
+/**
+ * \file
+ *
+ * \brief Generic Clock Controller.
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#ifndef _HPL_GCLK_H_INCLUDED
+#define _HPL_GCLK_H_INCLUDED
+
+#include <compiler.h>
+#ifdef _UNIT_TEST_
+#include <hri_gclk1_v210_mock.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \addtogroup gclk_group GCLK Hardware Proxy Layer
+ *
+ * \section gclk_hpl_rev Revision History
+ * - v0.0.0.1 Initial Commit
+ *
+ *@{
+ */
+
+/**
+ * \name HPL functions
+ */
+//@{
+/**
+ * \brief Enable clock on the given channel with the given clock source
+ *
+ * This function maps the given clock source to the given clock channel
+ * and enables channel.
+ *
+ * \param[in] channel The channel to enable clock for
+ * \param[in] source The clock source for the given channel
+ */
+static inline void _gclk_enable_channel(const uint8_t channel, const uint8_t source)
+{
+
+	hri_gclk_write_PCHCTRL_reg(GCLK, channel, source | GCLK_PCHCTRL_CHEN);
+}
+
+/**
+ * \brief Initialize GCLK generators by function references
+ * \param[in] bm Bit mapping for referenced generators,
+ *               a bit 1 in position triggers generator initialization.
+ */
+void _gclk_init_generators_by_fref(uint32_t bm);
+
+//@}
+/**@}*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HPL_GCLK_H_INCLUDED */
diff --git a/sysmoOCTSIM/hpl/mclk/hpl_mclk.c b/sysmoOCTSIM/hpl/mclk/hpl_mclk.c
new file mode 100644
index 0000000..6684320
--- /dev/null
+++ b/sysmoOCTSIM/hpl/mclk/hpl_mclk.c
@@ -0,0 +1,44 @@
+/**
+ * \file
+ *
+ * \brief SAM Main Clock.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <compiler.h>
+#include <hpl_mclk_config.h>
+
+/**
+ * \brief Initialize master clock generator
+ */
+void _mclk_init(void)
+{
+	void *hw = (void *)MCLK;
+	hri_mclk_write_CPUDIV_reg(hw, MCLK_CPUDIV_DIV(CONF_MCLK_CPUDIV));
+}
diff --git a/sysmoOCTSIM/hpl/osc32kctrl/hpl_osc32kctrl.c b/sysmoOCTSIM/hpl/osc32kctrl/hpl_osc32kctrl.c
new file mode 100644
index 0000000..8859b42
--- /dev/null
+++ b/sysmoOCTSIM/hpl/osc32kctrl/hpl_osc32kctrl.c
@@ -0,0 +1,82 @@
+
+/**
+ * \file
+ *
+ * \brief SAM 32k Oscillators Controller.
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+#include <hpl_init.h>
+#include <hpl_osc32kctrl_config.h>
+
+/**
+ * \brief Initialize 32 kHz clock sources
+ */
+void _osc32kctrl_init_sources(void)
+{
+	void *   hw    = (void *)OSC32KCTRL;
+	uint16_t calib = 0;
+
+#if CONF_XOSC32K_CONFIG == 1
+	hri_osc32kctrl_write_XOSC32K_reg(
+	    hw,
+	    OSC32KCTRL_XOSC32K_STARTUP(CONF_XOSC32K_STARTUP) | (CONF_XOSC32K_ONDEMAND << OSC32KCTRL_XOSC32K_ONDEMAND_Pos)
+	        | (CONF_XOSC32K_RUNSTDBY << OSC32KCTRL_XOSC32K_RUNSTDBY_Pos)
+	        | (CONF_XOSC32K_EN1K << OSC32KCTRL_XOSC32K_EN1K_Pos) | (CONF_XOSC32K_EN32K << OSC32KCTRL_XOSC32K_EN32K_Pos)
+	        | (CONF_XOSC32K_XTALEN << OSC32KCTRL_XOSC32K_XTALEN_Pos) |
+#ifdef CONF_XOSC32K_CGM
+	        OSC32KCTRL_XOSC32K_CGM(CONF_XOSC32K_CGM) |
+#endif
+	        (CONF_XOSC32K_ENABLE << OSC32KCTRL_XOSC32K_ENABLE_Pos));
+
+	hri_osc32kctrl_write_CFDCTRL_reg(hw, (CONF_XOSC32K_CFDEN << OSC32KCTRL_CFDCTRL_CFDEN_Pos));
+
+	hri_osc32kctrl_write_EVCTRL_reg(hw, (CONF_XOSC32K_CFDEO << OSC32KCTRL_EVCTRL_CFDEO_Pos));
+#endif
+
+#if CONF_OSCULP32K_CONFIG == 1
+	calib = hri_osc32kctrl_read_OSCULP32K_CALIB_bf(hw);
+	hri_osc32kctrl_write_OSCULP32K_reg(hw,
+#if CONF_OSCULP32K_CALIB_ENABLE == 1
+	                                   OSC32KCTRL_OSCULP32K_CALIB(CONF_OSCULP32K_CALIB)
+#else
+	                                   OSC32KCTRL_OSCULP32K_CALIB(calib)
+#endif
+	);
+#endif
+
+#if CONF_XOSC32K_CONFIG
+#if CONF_XOSC32K_ENABLE == 1 && CONF_XOSC32K_ONDEMAND == 0
+	while (!hri_osc32kctrl_get_STATUS_XOSC32KRDY_bit(hw))
+		;
+#endif
+#endif
+
+	hri_osc32kctrl_write_RTCCTRL_reg(hw, OSC32KCTRL_RTCCTRL_RTCSEL(CONF_RTCCTRL));
+	(void)calib;
+}
diff --git a/sysmoOCTSIM/hpl/oscctrl/hpl_oscctrl.c b/sysmoOCTSIM/hpl/oscctrl/hpl_oscctrl.c
new file mode 100644
index 0000000..9f55076
--- /dev/null
+++ b/sysmoOCTSIM/hpl/oscctrl/hpl_oscctrl.c
@@ -0,0 +1,230 @@
+
+/**
+ * \file
+ *
+ * \brief SAM Oscillators Controller.
+ *
+ * Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <hpl_init.h>
+#include <hpl_oscctrl_config.h>
+#include <hpl_gclk_config.h>
+
+/**
+ * \brief Initialize clock sources
+ */
+void _oscctrl_init_sources(void)
+{
+	void *hw = (void *)OSCCTRL;
+
+#if CONF_XOSC0_CONFIG == 1
+	hri_oscctrl_write_XOSCCTRL_reg(
+	    hw,
+	    0,
+	    OSCCTRL_XOSCCTRL_CFDPRESC(CONF_XOSC0_CFDPRESC) | OSCCTRL_XOSCCTRL_STARTUP(CONF_XOSC0_STARTUP)
+	        | (CONF_XOSC0_SWBEN << OSCCTRL_XOSCCTRL_SWBEN_Pos) | (CONF_XOSC0_CFDEN << OSCCTRL_XOSCCTRL_CFDEN_Pos)
+	        | (0 << OSCCTRL_XOSCCTRL_ENALC_Pos) | OSCCTRL_XOSCCTRL_IMULT(CONF_XOSC0_IMULT)
+	        | OSCCTRL_XOSCCTRL_IPTAT(CONF_XOSC0_IPTAT) | (CONF_XOSC0_LOWBUFGAIN << OSCCTRL_XOSCCTRL_LOWBUFGAIN_Pos)
+	        | (0 << OSCCTRL_XOSCCTRL_ONDEMAND_Pos) | (CONF_XOSC0_RUNSTDBY << OSCCTRL_XOSCCTRL_RUNSTDBY_Pos)
+	        | (CONF_XOSC0_XTALEN << OSCCTRL_XOSCCTRL_XTALEN_Pos) | (CONF_XOSC0_ENABLE << OSCCTRL_XOSCCTRL_ENABLE_Pos));
+#endif
+
+#if CONF_XOSC0_CONFIG == 1
+#if CONF_XOSC0_ENABLE == 1
+	while (!hri_oscctrl_get_STATUS_XOSCRDY0_bit(hw))
+		;
+#endif
+#if CONF_XOSC0_ENALC == 1
+	hri_oscctrl_set_XOSCCTRL_ENALC_bit(hw, 0);
+#endif
+#if CONF_XOSC0_ONDEMAND == 1
+	hri_oscctrl_set_XOSCCTRL_ONDEMAND_bit(hw, 0);
+#endif
+#endif
+
+#if CONF_XOSC1_CONFIG == 1
+	hri_oscctrl_write_XOSCCTRL_reg(
+	    hw,
+	    1,
+	    OSCCTRL_XOSCCTRL_CFDPRESC(CONF_XOSC1_CFDPRESC) | OSCCTRL_XOSCCTRL_STARTUP(CONF_XOSC1_STARTUP)
+	        | (CONF_XOSC1_SWBEN << OSCCTRL_XOSCCTRL_SWBEN_Pos) | (CONF_XOSC1_CFDEN << OSCCTRL_XOSCCTRL_CFDEN_Pos)
+	        | (0 << OSCCTRL_XOSCCTRL_ENALC_Pos) | OSCCTRL_XOSCCTRL_IMULT(CONF_XOSC1_IMULT)
+	        | OSCCTRL_XOSCCTRL_IPTAT(CONF_XOSC1_IPTAT) | (CONF_XOSC1_LOWBUFGAIN << OSCCTRL_XOSCCTRL_LOWBUFGAIN_Pos)
+	        | (0 << OSCCTRL_XOSCCTRL_ONDEMAND_Pos) | (CONF_XOSC1_RUNSTDBY << OSCCTRL_XOSCCTRL_RUNSTDBY_Pos)
+	        | (CONF_XOSC1_XTALEN << OSCCTRL_XOSCCTRL_XTALEN_Pos) | (CONF_XOSC1_ENABLE << OSCCTRL_XOSCCTRL_ENABLE_Pos));
+#endif
+
+#if CONF_XOSC1_CONFIG == 1
+#if CONF_XOSC1_ENABLE == 1
+	while (!hri_oscctrl_get_STATUS_XOSCRDY1_bit(hw))
+		;
+#endif
+#if CONF_XOSC1_ENALC == 1
+	hri_oscctrl_set_XOSCCTRL_ENALC_bit(hw, 1);
+#endif
+#if CONF_XOSC1_ONDEMAND == 1
+	hri_oscctrl_set_XOSCCTRL_ONDEMAND_bit(hw, 1);
+#endif
+#endif
+
+	(void)hw;
+}
+
+void _oscctrl_init_referenced_generators(void)
+{
+	void *hw = (void *)OSCCTRL;
+
+#if CONF_DFLL_CONFIG == 1
+	hri_gclk_write_GENCTRL_SRC_bf(GCLK, 0, GCLK_GENCTRL_SRC_OSCULP32K);
+	while (hri_gclk_get_SYNCBUSY_GENCTRL0_bit(GCLK))
+		;
+	uint8_t tmp;
+	hri_oscctrl_write_DFLLCTRLA_reg(hw, 0);
+#if CONF_DFLL_USBCRM != 1 && CONF_DFLL_MODE != 0
+	hri_gclk_write_PCHCTRL_reg(
+	    GCLK, OSCCTRL_GCLK_ID_DFLL48, (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(CONF_DFLL_GCLK));
+#endif
+
+	hri_oscctrl_write_DFLLMUL_reg(hw,
+	                              OSCCTRL_DFLLMUL_CSTEP(CONF_DFLL_CSTEP) | OSCCTRL_DFLLMUL_FSTEP(CONF_DFLL_FSTEP)
+	                                  | OSCCTRL_DFLLMUL_MUL(CONF_DFLL_MUL));
+	while (hri_oscctrl_get_DFLLSYNC_DFLLMUL_bit(hw))
+		;
+
+	hri_oscctrl_write_DFLLCTRLB_reg(hw, 0);
+	while (hri_oscctrl_get_DFLLSYNC_DFLLCTRLB_bit(hw))
+		;
+
+	tmp = (CONF_DFLL_RUNSTDBY << OSCCTRL_DFLLCTRLA_RUNSTDBY_Pos) | OSCCTRL_DFLLCTRLA_ENABLE;
+	hri_oscctrl_write_DFLLCTRLA_reg(hw, tmp);
+	while (hri_oscctrl_get_DFLLSYNC_ENABLE_bit(hw))
+		;
+
+#if CONF_DFLL_OVERWRITE_CALIBRATION == 1
+	hri_oscctrl_write_DFLLVAL_reg(hw, OSCCTRL_DFLLVAL_COARSE(CONF_DFLL_COARSE) | OSCCTRL_DFLLVAL_FINE(CONF_DFLL_FINE));
+#endif
+	hri_oscctrl_write_DFLLVAL_reg(hw, hri_oscctrl_read_DFLLVAL_reg(hw));
+	while (hri_oscctrl_get_DFLLSYNC_DFLLVAL_bit(hw))
+		;
+
+	tmp = (CONF_DFLL_WAITLOCK << OSCCTRL_DFLLCTRLB_WAITLOCK_Pos) | (CONF_DFLL_BPLCKC << OSCCTRL_DFLLCTRLB_BPLCKC_Pos)
+	      | (CONF_DFLL_QLDIS << OSCCTRL_DFLLCTRLB_QLDIS_Pos) | (CONF_DFLL_CCDIS << OSCCTRL_DFLLCTRLB_CCDIS_Pos)
+	      | (CONF_DFLL_USBCRM << OSCCTRL_DFLLCTRLB_USBCRM_Pos) | (CONF_DFLL_LLAW << OSCCTRL_DFLLCTRLB_LLAW_Pos)
+	      | (CONF_DFLL_STABLE << OSCCTRL_DFLLCTRLB_STABLE_Pos) | (CONF_DFLL_MODE << OSCCTRL_DFLLCTRLB_MODE_Pos) | 0;
+	hri_oscctrl_write_DFLLCTRLB_reg(hw, tmp);
+	while (hri_oscctrl_get_DFLLSYNC_DFLLCTRLB_bit(hw))
+		;
+#endif
+
+#if CONF_FDPLL0_CONFIG == 1
+#if CONF_FDPLL0_REFCLK == 0
+	hri_gclk_write_PCHCTRL_reg(
+	    GCLK, OSCCTRL_GCLK_ID_FDPLL0, (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(CONF_FDPLL0_GCLK));
+#endif
+	hri_oscctrl_write_DPLLRATIO_reg(
+	    hw, 0, OSCCTRL_DPLLRATIO_LDRFRAC(CONF_FDPLL0_LDRFRAC) | OSCCTRL_DPLLRATIO_LDR(CONF_FDPLL0_LDR));
+	hri_oscctrl_write_DPLLCTRLB_reg(
+	    hw,
+	    0,
+	    OSCCTRL_DPLLCTRLB_DIV(CONF_FDPLL0_DIV) | (CONF_FDPLL0_DCOEN << OSCCTRL_DPLLCTRLB_DCOEN_Pos)
+	        | OSCCTRL_DPLLCTRLB_DCOFILTER(CONF_FDPLL0_DCOFILTER)
+	        | (CONF_FDPLL0_LBYPASS << OSCCTRL_DPLLCTRLB_LBYPASS_Pos) | OSCCTRL_DPLLCTRLB_LTIME(CONF_FDPLL0_LTIME)
+	        | OSCCTRL_DPLLCTRLB_REFCLK(CONF_FDPLL0_REFCLK) | (CONF_FDPLL0_WUF << OSCCTRL_DPLLCTRLB_WUF_Pos)
+	        | OSCCTRL_DPLLCTRLB_FILTER(CONF_FDPLL0_FILTER));
+	hri_oscctrl_write_DPLLCTRLA_reg(hw,
+	                                0,
+	                                (CONF_FDPLL0_RUNSTDBY << OSCCTRL_DPLLCTRLA_RUNSTDBY_Pos)
+	                                    | (CONF_FDPLL0_ENABLE << OSCCTRL_DPLLCTRLA_ENABLE_Pos));
+#endif
+
+#if CONF_FDPLL1_CONFIG == 1
+#if CONF_FDPLL1_REFCLK == 0
+	hri_gclk_write_PCHCTRL_reg(
+	    GCLK, OSCCTRL_GCLK_ID_FDPLL1, (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(CONF_FDPLL1_GCLK));
+#endif
+	hri_oscctrl_write_DPLLRATIO_reg(
+	    hw, 1, OSCCTRL_DPLLRATIO_LDRFRAC(CONF_FDPLL1_LDRFRAC) | OSCCTRL_DPLLRATIO_LDR(CONF_FDPLL1_LDR));
+	hri_oscctrl_write_DPLLCTRLB_reg(
+	    hw,
+	    1,
+	    OSCCTRL_DPLLCTRLB_DIV(CONF_FDPLL1_DIV) | (CONF_FDPLL1_DCOEN << OSCCTRL_DPLLCTRLB_DCOEN_Pos)
+	        | OSCCTRL_DPLLCTRLB_DCOFILTER(CONF_FDPLL1_DCOFILTER)
+	        | (CONF_FDPLL1_LBYPASS << OSCCTRL_DPLLCTRLB_LBYPASS_Pos) | OSCCTRL_DPLLCTRLB_LTIME(CONF_FDPLL1_LTIME)
+	        | OSCCTRL_DPLLCTRLB_REFCLK(CONF_FDPLL1_REFCLK) | (CONF_FDPLL1_WUF << OSCCTRL_DPLLCTRLB_WUF_Pos)
+	        | OSCCTRL_DPLLCTRLB_FILTER(CONF_FDPLL1_FILTER));
+	hri_oscctrl_write_DPLLCTRLA_reg(hw,
+	                                1,
+	                                (CONF_FDPLL1_RUNSTDBY << OSCCTRL_DPLLCTRLA_RUNSTDBY_Pos)
+	                                    | (CONF_FDPLL1_ENABLE << OSCCTRL_DPLLCTRLA_ENABLE_Pos));
+#endif
+
+#if CONF_DFLL_CONFIG == 1
+	if (hri_oscctrl_get_DFLLCTRLB_MODE_bit(hw)) {
+		hri_oscctrl_status_reg_t status_mask = OSCCTRL_STATUS_DFLLRDY | OSCCTRL_STATUS_DFLLLCKC;
+
+		while (hri_oscctrl_get_STATUS_reg(hw, status_mask) != status_mask)
+			;
+	} else {
+		while (!hri_oscctrl_get_STATUS_DFLLRDY_bit(hw))
+			;
+	}
+#if CONF_DFLL_ONDEMAND == 1
+	hri_oscctrl_set_DFLLCTRLA_ONDEMAND_bit(hw);
+#endif
+#endif
+
+#if CONF_FDPLL0_CONFIG == 1
+#if CONF_FDPLL0_ENABLE == 1
+	while (!(hri_oscctrl_get_DPLLSTATUS_LOCK_bit(hw, 0) || hri_oscctrl_get_DPLLSTATUS_CLKRDY_bit(hw, 0)))
+		;
+#endif
+#if CONF_FDPLL0_ONDEMAND == 1
+	hri_oscctrl_set_DPLLCTRLA_ONDEMAND_bit(hw, 0);
+#endif
+#endif
+
+#if CONF_FDPLL1_CONFIG == 1
+#if CONF_FDPLL1_ENABLE == 1
+	while (!(hri_oscctrl_get_DPLLSTATUS_LOCK_bit(hw, 1) || hri_oscctrl_get_DPLLSTATUS_CLKRDY_bit(hw, 1)))
+		;
+#endif
+#if CONF_FDPLL1_ONDEMAND == 1
+	hri_oscctrl_set_DPLLCTRLA_ONDEMAND_bit(hw, 1);
+#endif
+#endif
+
+#if CONF_DFLL_CONFIG == 1
+	while (hri_gclk_read_SYNCBUSY_reg(GCLK))
+		;
+	hri_gclk_write_GENCTRL_SRC_bf(GCLK, 0, CONF_GCLK_GEN_0_SOURCE);
+	while (hri_gclk_get_SYNCBUSY_GENCTRL0_bit(GCLK))
+		;
+#endif
+	(void)hw;
+}
diff --git a/sysmoOCTSIM/hpl/pm/hpl_pm.c b/sysmoOCTSIM/hpl/pm/hpl_pm.c
new file mode 100644
index 0000000..55dc4db
--- /dev/null
+++ b/sysmoOCTSIM/hpl/pm/hpl_pm.c
@@ -0,0 +1,68 @@
+
+/**
+ * \file
+ *
+ * \brief SAM Power manager
+ *
+ * Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <hpl_sleep.h>
+#include <hpl_init.h>
+
+/**
+ * \brief Set the sleep mode for the device
+ */
+int32_t _set_sleep_mode(const uint8_t mode)
+{
+	uint8_t delay = 10;
+
+	switch (mode) {
+	case 2:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		hri_pm_write_SLEEPCFG_reg(PM, mode);
+		/* A small latency happens between the store instruction and actual
+		 * writing of the SLEEPCFG register due to bridges. Software has to make
+		 * sure the SLEEPCFG register reads the wanted value before issuing WFI
+		 * instruction.
+		 */
+		do {
+			if (hri_pm_read_SLEEPCFG_reg(PM) == mode) {
+				break;
+			}
+		} while (--delay);
+		break;
+	default:
+		return ERR_INVALID_ARG;
+	}
+
+	return ERR_NONE;
+}
diff --git a/sysmoOCTSIM/hpl/pm/hpl_pm_base.h b/sysmoOCTSIM/hpl/pm/hpl_pm_base.h
new file mode 100644
index 0000000..5a50a91
--- /dev/null
+++ b/sysmoOCTSIM/hpl/pm/hpl_pm_base.h
@@ -0,0 +1,45 @@
+/**
+ * \file
+ *
+ * \brief SAM Power manager
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ */
+
+#ifndef _HPL_PM_BASE_H_INCLUDED
+#define _HPL_PM_BASE_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <utils_assert.h>
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _HPL_PM_BASE_H_INCLUDED */
diff --git a/sysmoOCTSIM/hpl/port/hpl_gpio_base.h b/sysmoOCTSIM/hpl/port/hpl_gpio_base.h
new file mode 100644
index 0000000..f32c40f
--- /dev/null
+++ b/sysmoOCTSIM/hpl/port/hpl_gpio_base.h
@@ -0,0 +1,172 @@
+
+/**
+ * \file
+ *
+ * \brief SAM PORT.
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+#include <compiler.h>
+#include <hpl_gpio.h>
+#include <utils_assert.h>
+#include <hpl_port_config.h>
+
+/**
+ * \brief Set direction on port with mask
+ */
+static inline void _gpio_set_direction(const enum gpio_port port, const uint32_t mask,
+                                       const enum gpio_direction direction)
+{
+	switch (direction) {
+	case GPIO_DIRECTION_OFF:
+		hri_port_clear_DIR_reg(PORT, port, mask);
+		hri_port_write_WRCONFIG_reg(PORT, port, PORT_WRCONFIG_WRPINCFG | (mask & 0xffff));
+		hri_port_write_WRCONFIG_reg(
+		    PORT, port, PORT_WRCONFIG_HWSEL | PORT_WRCONFIG_WRPINCFG | ((mask & 0xffff0000) >> 16));
+		break;
+
+	case GPIO_DIRECTION_IN:
+		hri_port_clear_DIR_reg(PORT, port, mask);
+		hri_port_write_WRCONFIG_reg(PORT, port, PORT_WRCONFIG_WRPINCFG | PORT_WRCONFIG_INEN | (mask & 0xffff));
+		hri_port_write_WRCONFIG_reg(PORT,
+		                            port,
+		                            PORT_WRCONFIG_HWSEL | PORT_WRCONFIG_WRPINCFG | PORT_WRCONFIG_INEN
+		                                | ((mask & 0xffff0000) >> 16));
+		break;
+
+	case GPIO_DIRECTION_OUT:
+		hri_port_set_DIR_reg(PORT, port, mask);
+		hri_port_write_WRCONFIG_reg(PORT, port, PORT_WRCONFIG_WRPINCFG | (mask & 0xffff));
+		hri_port_write_WRCONFIG_reg(
+		    PORT, port, PORT_WRCONFIG_HWSEL | PORT_WRCONFIG_WRPINCFG | ((mask & 0xffff0000) >> 16));
+		break;
+
+	default:
+		ASSERT(false);
+	}
+}
+
+/**
+ * \brief Set output level on port with mask
+ */
+static inline void _gpio_set_level(const enum gpio_port port, const uint32_t mask, const bool level)
+{
+	if (level) {
+		hri_port_set_OUT_reg(PORT, port, mask);
+	} else {
+		hri_port_clear_OUT_reg(PORT, port, mask);
+	}
+}
+
+/**
+ * \brief Change output level to the opposite with mask
+ */
+static inline void _gpio_toggle_level(const enum gpio_port port, const uint32_t mask)
+{
+	hri_port_toggle_OUT_reg(PORT, port, mask);
+}
+
+/**
+ * \brief Get input levels on all port pins
+ */
+static inline uint32_t _gpio_get_level(const enum gpio_port port)
+{
+	uint32_t tmp;
+
+	CRITICAL_SECTION_ENTER();
+
+	uint32_t dir_tmp = hri_port_read_DIR_reg(PORT, port);
+
+	tmp = hri_port_read_IN_reg(PORT, port) & ~dir_tmp;
+	tmp |= hri_port_read_OUT_reg(PORT, port) & dir_tmp;
+
+	CRITICAL_SECTION_LEAVE();
+
+	return tmp;
+}
+
+/**
+ * \brief Set pin pull mode
+ */
+static inline void _gpio_set_pin_pull_mode(const enum gpio_port port, const uint8_t pin,
+                                           const enum gpio_pull_mode pull_mode)
+{
+	switch (pull_mode) {
+	case GPIO_PULL_OFF:
+		hri_port_clear_PINCFG_PULLEN_bit(PORT, port, pin);
+		break;
+
+	case GPIO_PULL_UP:
+		hri_port_clear_DIR_reg(PORT, port, 1U << pin);
+		hri_port_set_PINCFG_PULLEN_bit(PORT, port, pin);
+		hri_port_set_OUT_reg(PORT, port, 1U << pin);
+		break;
+
+	case GPIO_PULL_DOWN:
+		hri_port_clear_DIR_reg(PORT, port, 1U << pin);
+		hri_port_set_PINCFG_PULLEN_bit(PORT, port, pin);
+		hri_port_clear_OUT_reg(PORT, port, 1U << pin);
+		break;
+
+	default:
+		ASSERT(false);
+		break;
+	}
+}
+
+/**
+ * \brief Set gpio pin function
+ */
+static inline void _gpio_set_pin_function(const uint32_t gpio, const uint32_t function)
+{
+	uint8_t port = GPIO_PORT(gpio);
+	uint8_t pin  = GPIO_PIN(gpio);
+
+	if (function == GPIO_PIN_FUNCTION_OFF) {
+		hri_port_write_PINCFG_PMUXEN_bit(PORT, port, pin, false);
+
+	} else {
+		hri_port_write_PINCFG_PMUXEN_bit(PORT, port, pin, true);
+
+		if (pin & 1) {
+			// Odd numbered pin
+			hri_port_write_PMUX_PMUXO_bf(PORT, port, pin >> 1, function & 0xffff);
+		} else {
+			// Even numbered pin
+			hri_port_write_PMUX_PMUXE_bf(PORT, port, pin >> 1, function & 0xffff);
+		}
+	}
+}
+
+static inline void _port_event_init()
+{
+	hri_port_set_EVCTRL_reg(PORT, 0, CONF_PORTA_EVCTRL);
+	hri_port_set_EVCTRL_reg(PORT, 1, CONF_PORTB_EVCTRL);
+	hri_port_set_EVCTRL_reg(PORT, 2, CONF_PORTC_EVCTRL);
+	hri_port_set_EVCTRL_reg(PORT, 3, CONF_PORTD_EVCTRL);
+}
diff --git a/sysmoOCTSIM/hpl/ramecc/hpl_ramecc.c b/sysmoOCTSIM/hpl/ramecc/hpl_ramecc.c
new file mode 100644
index 0000000..4c158b2
--- /dev/null
+++ b/sysmoOCTSIM/hpl/ramecc/hpl_ramecc.c
@@ -0,0 +1,83 @@
+/**
+ * \file
+ *
+ * \brief Generic RAMECC related functionality.
+ *
+ * Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <utils.h>
+#include <utils_assert.h>
+#include <hpl_ramecc.h>
+
+/* RAMECC device descriptor */
+struct _ramecc_device device;
+
+/**
+ * \brief Initialize RAMECC
+ */
+int32_t _ramecc_init(void)
+{
+	if (hri_ramecc_get_STATUS_ECCDIS_bit(RAMECC)) {
+		return ERR_ABORTED;
+	}
+
+	NVIC_DisableIRQ(RAMECC_IRQn);
+	NVIC_ClearPendingIRQ(RAMECC_IRQn);
+	NVIC_EnableIRQ(RAMECC_IRQn);
+
+	return ERR_NONE;
+}
+
+void _ramecc_register_callback(const enum _ramecc_callback_type type, ramecc_cb_t cb)
+{
+	if (RAMECC_DUAL_ERROR_CB == type) {
+		device.ramecc_cb.dual_bit_err = cb;
+		hri_ramecc_write_INTEN_DUALE_bit(RAMECC, NULL != cb);
+	} else if (RAMECC_SINGLE_ERROR_CB == type) {
+		device.ramecc_cb.single_bit_err = cb;
+		hri_ramecc_write_INTEN_SINGLEE_bit(RAMECC, NULL != cb);
+	}
+}
+
+/**
+ * \internal RAMECC interrupt handler
+ */
+void RAMECC_Handler(void)
+{
+	struct _ramecc_device *dev      = (struct _ramecc_device *)&device;
+	volatile uint32_t      int_mask = hri_ramecc_read_INTFLAG_reg(RAMECC);
+
+	if (int_mask & RAMECC_INTFLAG_DUALE && dev->ramecc_cb.dual_bit_err) {
+		dev->ramecc_cb.dual_bit_err((uint32_t)hri_ramecc_read_ERRADDR_reg(RAMECC));
+	} else if (int_mask & RAMECC_INTFLAG_SINGLEE && dev->ramecc_cb.single_bit_err) {
+		dev->ramecc_cb.single_bit_err((uint32_t)hri_ramecc_read_ERRADDR_reg(RAMECC));
+	} else {
+		return;
+	}
+}
diff --git a/sysmoOCTSIM/hpl/usb/hpl_usb.c b/sysmoOCTSIM/hpl/usb/hpl_usb.c
new file mode 100644
index 0000000..6bf09ab
--- /dev/null
+++ b/sysmoOCTSIM/hpl/usb/hpl_usb.c
@@ -0,0 +1,2078 @@
+/**
+ * \file
+ *
+ * \brief SAM USB HPL
+ *
+ * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+#include <compiler.h>
+#include <hal_atomic.h>
+#include <hpl_usb.h>
+#include <hpl_usb_device.h>
+
+#include <hpl_usb_config.h>
+#include <string.h>
+#include <utils_assert.h>
+
+/**
+ * \brief Dummy callback function
+ * \return Always false.
+ */
+static bool _dummy_func_no_return(uint32_t unused0, uint32_t unused1)
+{
+	(void)unused0;
+	(void)unused1;
+	return false;
+}
+
+/**
+ * \brief Load USB calibration value from NVM
+ */
+static void _usb_load_calib(void)
+{
+#define NVM_USB_PAD_TRANSN_POS 32
+#define NVM_USB_PAD_TRANSN_SIZE 5
+#define NVM_USB_PAD_TRANSP_POS 37
+#define NVM_USB_PAD_TRANSP_SIZE 5
+#define NVM_USB_PAD_TRIM_POS 42
+#define NVM_USB_PAD_TRIM_SIZE 3
+	Usb *    hw = USB;
+	uint32_t pad_transn
+	    = (*((uint32_t *)(NVMCTRL_SW0) + (NVM_USB_PAD_TRANSN_POS / 32)) >> (NVM_USB_PAD_TRANSN_POS % 32))
+	      & ((1 << NVM_USB_PAD_TRANSN_SIZE) - 1);
+	uint32_t pad_transp
+	    = (*((uint32_t *)(NVMCTRL_SW0) + (NVM_USB_PAD_TRANSP_POS / 32)) >> (NVM_USB_PAD_TRANSP_POS % 32))
+	      & ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1);
+	uint32_t pad_trim = (*((uint32_t *)(NVMCTRL_SW0) + (NVM_USB_PAD_TRIM_POS / 32)) >> (NVM_USB_PAD_TRIM_POS % 32))
+	                    & ((1 << NVM_USB_PAD_TRIM_SIZE) - 1);
+	if (pad_transn == 0 || pad_transn == 0x1F) {
+		pad_transn = 9;
+	}
+	if (pad_transp == 0 || pad_transp == 0x1F) {
+		pad_transp = 25;
+	}
+	if (pad_trim == 0 || pad_trim == 0x7) {
+		pad_trim = 6;
+	}
+
+	hw->DEVICE.PADCAL.reg = USB_PADCAL_TRANSN(pad_transn) | USB_PADCAL_TRANSP(pad_transp) | USB_PADCAL_TRIM(pad_trim);
+
+	hw->DEVICE.QOSCTRL.bit.CQOS = 3;
+	hw->DEVICE.QOSCTRL.bit.DQOS = 3;
+}
+
+/** \name USB clock source management */
+/*@{*/
+
+/** USB clock is generated by DFLL. */
+#define USB_CLK_SRC_DFLL 0
+
+/** USB clock is generated by DPLL. */
+#define USB_CLK_SRC_DPLL 1
+
+/** Uses DFLL as USB clock source. */
+#define CONF_USB_D_CLK_SRC USB_CLK_SRC_DFLL
+
+/** Retry for USB remote wakeup sending. */
+#define CONF_USB_RMT_WKUP_RETRY 5
+
+/**
+ * \brief Wait DPLL clock to be ready
+ */
+static inline void _usb_d_dev_wait_dpll_rdy(void)
+{
+#define DPLL_READY_FLAG (OSCCTRL_DPLLSTATUS_CLKRDY | OSCCTRL_DPLLSTATUS_LOCK)
+	while (hri_oscctrl_get_DPLLSTATUS_reg(OSCCTRL, 0, DPLL_READY_FLAG) != DPLL_READY_FLAG)
+		;
+}
+
+/**
+ * \brief Wait DFLL clock to be ready
+ */
+static inline void _usb_d_dev_wait_dfll_rdy(void)
+{
+	if (hri_oscctrl_get_DFLLCTRLB_MODE_bit(OSCCTRL)) {
+		while (hri_oscctrl_get_STATUS_reg(OSCCTRL, (OSCCTRL_STATUS_DFLLRDY | OSCCTRL_STATUS_DFLLLCKC))
+		       != (OSCCTRL_STATUS_DFLLRDY | OSCCTRL_STATUS_DFLLLCKC))
+			;
+	} else {
+		while (hri_oscctrl_get_STATUS_reg(OSCCTRL, OSCCTRL_STATUS_DFLLRDY) != OSCCTRL_STATUS_DFLLRDY)
+			;
+	}
+}
+
+/**
+ * \brief Wait USB source clock to be ready
+ * \param[in] clk_src Clock source, could be \ref USB_CLK_SRC_DFLL or
+ *                    \ref USB_CLK_SRC_DPLL.
+ */
+static inline void _usb_d_dev_wait_clk_rdy(const uint8_t clk_src)
+{
+	if (clk_src == USB_CLK_SRC_DFLL) {
+		_usb_d_dev_wait_dfll_rdy();
+	} else if (clk_src == USB_CLK_SRC_DPLL) {
+		_usb_d_dev_wait_dpll_rdy();
+	}
+}
+
+/*@}*/
+
+/** \name USB general settings */
+/*@{*/
+
+/** Increase the value to be aligned. */
+#define _usb_align_up(val) (((val)&0x3) ? (((val) + 4 - ((val)&0x3))) : (val))
+
+/** Check if the buffer is in RAM (can DMA), or cache needed
+ *  \param[in] a Buffer start address.
+ *  \param[in] s Buffer size, in number of bytes.
+ *  \return \c true If the buffer is in RAM.
+ */
+#define _IN_RAM(a, s) ((0x20000000 <= (uint32_t)(a)) && (((uint32_t)(a) + (s)) < (0x20000000 + 0x00042000)))
+
+/** Check if the address should be placed in RAM. */
+#define _usb_is_addr4dma(addr, size) _IN_RAM((addr), (size))
+
+/** Check if the address is 32-bit aligned. */
+#define _usb_is_aligned(val) (((uint32_t)(val)&0x3) == 0)
+/*@}*/
+
+/* Cache static configurations.
+ * By default, all OUT endpoint have 64 bytes cache. */
+#ifndef CONF_USB_EP0_CACHE
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#define CONF_USB_EP0_CACHE 64
+#endif
+
+#ifndef CONF_USB_EP0_I_CACHE
+/** Endpoint cache buffer for IN transactions (none-control). */
+#define CONF_USB_EP0_I_CACHE 0
+#endif
+
+#ifndef CONF_USB_EP1_CACHE
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#define CONF_USB_EP1_CACHE 64
+#endif
+
+#ifndef CONF_USB_EP1_I_CACHE
+/** Endpoint cache buffer for IN transactions (none-control). */
+#define CONF_USB_EP1_I_CACHE 0
+#endif
+
+#ifndef CONF_USB_EP2_CACHE
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#define CONF_USB_EP2_CACHE 64
+#endif
+
+#ifndef CONF_USB_EP2_I_CACHE
+/** Endpoint cache buffer for IN transactions (none-control). */
+#define CONF_USB_EP2_I_CACHE 0
+#endif
+
+#ifndef CONF_USB_EP3_CACHE
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#define CONF_USB_EP3_CACHE 64
+#endif
+
+#ifndef CONF_USB_EP3_I_CACHE
+/** Endpoint cache buffer for IN transactions (none-control). */
+#define CONF_USB_EP3_I_CACHE 0
+#endif
+
+#ifndef CONF_USB_EP4_CACHE
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#define CONF_USB_EP4_CACHE 64
+#endif
+
+#ifndef CONF_USB_EP4_I_CACHE
+/** Endpoint cache buffer for IN transactions (none-control). */
+#define CONF_USB_EP4_I_CACHE 0
+#endif
+
+#ifndef CONF_USB_EP5_CACHE
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#define CONF_USB_EP5_CACHE 64
+#endif
+
+#ifndef CONF_USB_EP5_I_CACHE
+/** Endpoint cache buffer for IN transactions (none-control). */
+#define CONF_USB_EP5_I_CACHE 0
+#endif
+
+#ifndef CONF_USB_EP6_CACHE
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#define CONF_USB_EP6_CACHE 64
+#endif
+
+#ifndef CONF_USB_EP6_I_CACHE
+/** Endpoint cache buffer for IN transactions (none-control). */
+#define CONF_USB_EP6_I_CACHE 0
+#endif
+
+#ifndef CONF_USB_EP7_CACHE
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#define CONF_USB_EP7_CACHE 64
+#endif
+
+#ifndef CONF_USB_EP7_I_CACHE
+/** Endpoint cache buffer for IN transactions (none-control). */
+#define CONF_USB_EP7_I_CACHE 0
+#endif
+
+#ifndef CONF_USB_EP8_CACHE
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#define CONF_USB_EP8_CACHE 64
+#endif
+
+#ifndef CONF_USB_EP8_I_CACHE
+/** Endpoint cache buffer for IN transactions (none-control). */
+#define CONF_USB_EP8_I_CACHE 0
+#endif
+
+#ifndef CONF_USB_EP9_CACHE
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#define CONF_USB_EP9_CACHE 64
+#endif
+
+#ifndef CONF_USB_EP9_I_CACHE
+/** Endpoint cache buffer for IN transactions (none-control). */
+#define CONF_USB_EP9_I_CACHE 0
+#endif
+
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#if CONF_USB_EP0_CACHE
+static uint32_t _usb_ep0_cache[_usb_align_up(CONF_USB_EP0_CACHE) / 4];
+#else
+#define _usb_ep0_cache NULL
+#endif
+
+/** Endpoint cache buffer for IN transactions (none-control). */
+#define _usb_ep0_i_cache NULL
+
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#if CONF_USB_EP1_CACHE && CONF_USB_D_MAX_EP_N >= 1
+static uint32_t _usb_ep1_cache[_usb_align_up(CONF_USB_EP1_CACHE) / 4];
+#else
+#define _usb_ep1_cache NULL
+#endif
+
+/** Endpoint cache buffer for IN transactions (none-control). */
+#if CONF_USB_EP1_I_CACHE && CONF_USB_D_MAX_EP_N >= 1
+static uint32_t _usb_ep1_i_cache[_usb_align_up(CONF_USB_EP1_I_CACHE) / 4];
+#else
+#define _usb_ep1_i_cache NULL
+#endif
+
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#if CONF_USB_EP2_CACHE && CONF_USB_D_MAX_EP_N >= 2
+static uint32_t _usb_ep2_cache[_usb_align_up(CONF_USB_EP2_CACHE) / 4];
+#else
+#define _usb_ep2_cache NULL
+#endif
+
+/** Endpoint cache buffer for IN transactions (none-control). */
+#if CONF_USB_EP2_I_CACHE && CONF_USB_D_MAX_EP_N >= 2
+static uint32_t _usb_ep2_i_cache[_usb_align_up(CONF_USB_EP2_I_CACHE) / 4];
+#else
+#define _usb_ep2_i_cache NULL
+#endif
+
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#if CONF_USB_EP3_CACHE && CONF_USB_D_MAX_EP_N >= 3
+static uint32_t _usb_ep3_cache[_usb_align_up(CONF_USB_EP3_CACHE) / 4];
+#else
+#define _usb_ep3_cache NULL
+#endif
+
+/** Endpoint cache buffer for IN transactions (none-control). */
+#if CONF_USB_EP3_I_CACHE && CONF_USB_D_MAX_EP_N >= 3
+static uint32_t _usb_ep3_i_cache[_usb_align_up(CONF_USB_EP3_I_CACHE) / 4];
+#else
+#define _usb_ep3_i_cache NULL
+#endif
+
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#if CONF_USB_EP4_CACHE && CONF_USB_D_MAX_EP_N >= 4
+static uint32_t _usb_ep4_cache[_usb_align_up(CONF_USB_EP4_CACHE) / 4];
+#else
+#define _usb_ep4_cache NULL
+#endif
+
+/** Endpoint cache buffer for IN transactions (none-control). */
+#if CONF_USB_EP4_I_CACHE && CONF_USB_D_MAX_EP_N >= 4
+static uint32_t _usb_ep4_i_cache[_usb_align_up(CONF_USB_EP4_I_CACHE) / 4];
+#else
+#define _usb_ep4_i_cache NULL
+#endif
+
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#if CONF_USB_EP5_CACHE && CONF_USB_D_MAX_EP_N >= 5
+static uint32_t _usb_ep5_cache[_usb_align_up(CONF_USB_EP5_CACHE) / 4];
+#else
+#define _usb_ep5_cache NULL
+#endif
+
+/** Endpoint cache buffer for IN transactions (none-control). */
+#if CONF_USB_EP5_I_CACHE && CONF_USB_D_MAX_EP_N >= 5
+static uint32_t _usb_ep5_i_cache[_usb_align_up(CONF_USB_EP5_I_CACHE) / 4];
+#else
+#define _usb_ep5_i_cache NULL
+#endif
+
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#if CONF_USB_EP6_CACHE && CONF_USB_D_MAX_EP_N >= 6
+static uint32_t _usb_ep6_cache[_usb_align_up(CONF_USB_EP6_CACHE) / 4];
+#else
+#define _usb_ep6_cache NULL
+#endif
+
+/** Endpoint cache buffer for IN transactions (none-control). */
+#if CONF_USB_EP6_I_CACHE && CONF_USB_D_MAX_EP_N >= 6
+static uint32_t _usb_ep6_i_cache[_usb_align_up(CONF_USB_EP6_I_CACHE) / 4];
+#else
+#define _usb_ep6_i_cache NULL
+#endif
+
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#if CONF_USB_EP7_CACHE && CONF_USB_D_MAX_EP_N >= 7
+static uint32_t _usb_ep7_cache[_usb_align_up(CONF_USB_EP7_CACHE) / 4];
+#else
+#define _usb_ep7_cache NULL
+#endif
+
+/** Endpoint cache buffer for IN transactions (none-control). */
+#if CONF_USB_EP7_I_CACHE && CONF_USB_D_MAX_EP_N >= 7
+static uint32_t _usb_ep7_i_cache[_usb_align_up(CONF_USB_EP7_I_CACHE) / 4];
+#else
+#define _usb_ep7_i_cache NULL
+#endif
+
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#if CONF_USB_EP8_CACHE && CONF_USB_D_MAX_EP_N >= 8
+static uint32_t _usb_ep8_cache[_usb_align_up(CONF_USB_EP8_CACHE) / 4];
+#else
+#define _usb_ep8_cache NULL
+#endif
+
+/** Endpoint cache buffer for IN transactions (none-control). */
+#if CONF_USB_EP8_I_CACHE && CONF_USB_D_MAX_EP_N >= 8
+static uint32_t _usb_ep8_i_cache[_usb_align_up(CONF_USB_EP8_I_CACHE) / 4];
+#else
+#define _usb_ep8_i_cache NULL
+#endif
+
+/** Endpoint cache buffer for OUT transactions (none-control) or SETUP/IN/OUT
+ *  transactions (control). */
+#if CONF_USB_EP9_CACHE && CONF_USB_D_MAX_EP_N >= 9
+static uint32_t _usb_ep9_cache[_usb_align_up(CONF_USB_EP9_CACHE) / 4];
+#else
+#define _usb_ep9_cache NULL
+#endif
+
+/** Endpoint cache buffer for IN transactions (none-control). */
+#if CONF_USB_EP9_I_CACHE && CONF_USB_D_MAX_EP_N >= 9
+static uint32_t _usb_ep9_i_cache[_usb_align_up(CONF_USB_EP9_I_CACHE) / 4];
+#else
+#define _usb_ep9_i_cache NULL
+#endif
+
+/** Access endpoint cache buffer for OUT transactions (none-control) or
+ *  SETUP/IN/OUT transactions (control). */
+#define _USB_EP_CACHE(n) ((void *)_usb_ep##n##_cache)
+
+/** Access endpoint cache buffer for IN transactions (none-control). */
+#define _USB_EP_I_CACHE(n) ((void *)_usb_ep##n##_i_cache)
+
+/** The configuration settings for one of the endpoint hardware. */
+struct _usb_ep_cfg_item {
+	/* Endpoint cache buffer for OUT transactions (none-control) or
+	 * SETUP/IN/OUT transactions (control). */
+	void *cache;
+	/* endpoint cache buffer for IN transactions (none-control). */
+	void *i_cache;
+	/* Cache buffer size for OUT transactions (none-control) or
+	 * SETUP/IN/OUT transactions (control). */
+	uint16_t size;
+	/* Cache buffer size for IN transactions (none-control). */
+	uint16_t i_size;
+};
+
+/** Build the endpoint configuration settings for one endpoint. */
+#define _USB_EP_CFG_ITEM(n)                                                                                            \
+	{                                                                                                                  \
+		_USB_EP_CACHE(n), _USB_EP_I_CACHE(n), CONF_USB_EP##n##_CACHE, CONF_USB_EP##n##_I_CACHE,                        \
+	}
+
+/** The configuration settings for all endpoint. */
+static const struct _usb_ep_cfg_item _usb_ep_cfgs[] = {_USB_EP_CFG_ITEM(0)
+#if CONF_USB_D_MAX_EP_N >= 1
+                                                           ,
+                                                       _USB_EP_CFG_ITEM(1)
+#endif
+#if CONF_USB_D_MAX_EP_N >= 2
+                                                           ,
+                                                       _USB_EP_CFG_ITEM(2)
+#endif
+#if CONF_USB_D_MAX_EP_N >= 3
+                                                           ,
+                                                       _USB_EP_CFG_ITEM(3)
+#endif
+#if CONF_USB_D_MAX_EP_N >= 4
+                                                           ,
+                                                       _USB_EP_CFG_ITEM(4)
+#endif
+#if CONF_USB_D_MAX_EP_N >= 5
+                                                           ,
+                                                       _USB_EP_CFG_ITEM(5)
+#endif
+#if CONF_USB_D_MAX_EP_N >= 6
+                                                           ,
+                                                       _USB_EP_CFG_ITEM(6)
+#endif
+#if CONF_USB_D_MAX_EP_N >= 7
+                                                           ,
+                                                       _USB_EP_CFG_ITEM(7)
+#endif
+#if CONF_USB_D_MAX_EP_N >= 8
+                                                           ,
+                                                       _USB_EP_CFG_ITEM(8)
+#endif
+#if CONF_USB_D_MAX_EP_N >= 9
+                                                           ,
+                                                       _USB_EP_CFG_ITEM(9)
+#endif
+};
+
+/** \name HW specific settings and implements */
+/*@{*/
+
+/** Number of endpoints supported. */
+#define USB_D_N_EP (1 + CONF_USB_D_NUM_EP_SP * 2)
+
+/** HPL USB device endpoint struct. */
+struct _usb_d_dev_ep {
+	/** Pointer to transaction buffer. */
+	uint8_t *trans_buf;
+	/** Transaction size. */
+	uint32_t trans_size;
+	/** Transaction transferred count. */
+	uint32_t trans_count;
+
+	/** Pointer to cache buffer, must be aligned. */
+	uint8_t *cache;
+
+	/** Endpoint size. */
+	uint16_t size;
+	/** Endpoint address. */
+	uint8_t ep;
+	/** Feature flags. */
+	union {
+		/** Interpreted by bit fields. */
+		struct {
+			/** EPCFG.ETYPE. */
+			uint8_t eptype : 3;
+			/** Stall status. */
+			uint8_t is_stalled : 1;
+			/** Transaction auto ZLP. */
+			uint8_t need_zlp : 1;
+			/** Transaction with cache */
+			uint8_t use_cache : 1;
+			/** Endpoint is busy. */
+			uint8_t is_busy : 1;
+			/** Transaction direction. */
+			uint8_t dir : 1;
+		} bits;
+		uint8_t u8;
+	} flags;
+};
+
+/** Check if the endpoint is used. */
+#define _usb_d_dev_ep_is_used(ept) ((ept)->ep != 0xFF)
+
+/** Check if the endpoint is busy doing transactions. */
+#define _usb_d_dev_ep_is_busy(ept) ((ept)->flags.bits.is_busy)
+
+/** Check if the endpoint is control endpoint. */
+#define _usb_d_dev_ep_is_ctrl(ept) ((ept)->flags.bits.eptype == USB_D_EPTYPE_CTRL)
+
+/** Check if the endpoint transactions are IN. */
+#define _usb_d_dev_ep_is_in(ept) ((ept)->flags.bits.dir)
+
+/** Interrupt flags for SETUP transaction. */
+#define USB_D_SETUP_INT_FLAGS (USB_DEVICE_EPINTFLAG_RXSTP)
+
+/** Interrupt flags for BANK1 transactions. */
+#define USB_D_BANK1_INT_FLAGS (USB_DEVICE_EPINTFLAG_TRCPT1 | USB_DEVICE_EPINTFLAG_TRFAIL1 | USB_DEVICE_EPINTFLAG_STALL1)
+
+/** Interrupt flags for BANK0 transactions. */
+#define USB_D_BANK0_INT_FLAGS (USB_DEVICE_EPINTFLAG_TRCPT0 | USB_DEVICE_EPINTFLAG_TRFAIL0 | USB_DEVICE_EPINTFLAG_STALL0)
+
+/** Interrupt flags for SETUP/IN/OUT transactions. */
+#define USB_D_ALL_INT_FLAGS (0x7F)
+
+/** Interrupt flags for WAKEUP event. */
+#define USB_D_WAKEUP_INT_FLAGS (USB_DEVICE_INTFLAG_UPRSM | USB_DEVICE_INTFLAG_EORSM | USB_DEVICE_INTFLAG_WAKEUP)
+
+/** Interrupt flags for SUSPEND event. */
+#define USB_D_SUSPEND_INT_FLAGS (USB_DEVICE_INTFLAG_LPMSUSP | USB_DEVICE_INTFLAG_SUSPEND)
+
+/** Max data bytes for a single DMA transfer. */
+#define USB_D_DEV_TRANS_MAX 8192 /* 14-bits, uses 13-bits. */
+
+/** Endpoint type setting to disable. */
+#define USB_D_EPTYPE_DISABLE 0
+
+/** Endpoint type setting to work as control endpoint. */
+#define USB_D_EPTYPE_CTRL 1
+
+/** Endpoint type setting to work as isochronous endpoint. */
+#define USB_D_EPTYPE_ISOCH 2
+
+/** Endpoint type setting to work as interrupt endpoint. */
+#define USB_D_EPTYPE_INT 3
+
+/** Endpoint type setting to work as bulk endpoint. */
+#define USB_D_EPTYPE_BULK 4
+
+/** Endpoint type setting for dual bank endpoint. */
+#define USB_D_EPTYPE_DUAL 5
+
+/** EPCFG register value for control endpoints. */
+#define USB_D_EPCFG_CTRL 0x11
+
+/** HPL USB device struct. */
+struct _usb_d_dev {
+	/** Callbacks of USB device. */
+	struct _usb_d_dev_callbacks callbacks;
+	/** Endpoint transaction callbacks. */
+	struct _usb_d_dev_ep_callbacks ep_callbacks;
+	/** Endpoints (ep0 + others). */
+	struct _usb_d_dev_ep ep[USB_D_N_EP];
+};
+
+/** Private data for SAM0 USB peripheral.
+ */
+typedef struct _usb_d_dev_prvt {
+	/** USB device descriptor table for peripheral to work. */
+	UsbDeviceDescriptor desc_table[CONF_USB_D_MAX_EP_N + 1];
+} usb_d_dev_prvt_t;
+
+/*@}*/
+
+/** USB device driver instance. */
+static struct _usb_d_dev dev_inst;
+
+/** USB device driver private data instance. */
+static struct _usb_d_dev_prvt prvt_inst;
+
+static void _usb_d_dev_reset_epts(void);
+
+static void _usb_d_dev_trans_done(struct _usb_d_dev_ep *ept, const int32_t status);
+static void _usb_d_dev_trans_stop(struct _usb_d_dev_ep *ept, bool dir, const int32_t code);
+
+static void _usb_d_dev_in_next(struct _usb_d_dev_ep *ept, bool isr);
+static void _usb_d_dev_out_next(struct _usb_d_dev_ep *ept, bool isr);
+
+static inline void _usb_d_dev_trans_setup(struct _usb_d_dev_ep *ept);
+
+/** \brief ACK the endpoint interrupt
+ * \param[in] epn Endpoint number.
+ * \param[in] flags Interrupt flags.
+ */
+static inline void _usbd_ep_int_ack(uint8_t epn, uint32_t flags)
+{
+	hri_usbendpoint_clear_EPINTFLAG_reg(USB, epn, flags);
+}
+
+/** \brief Enable the endpoint interrupt
+ * \param[in] epn Endpoint number.
+ * \param[in] flags Interrupt flags.
+ */
+static inline void _usbd_ep_int_en(uint8_t epn, uint32_t flags)
+{
+	hri_usbendpoint_set_EPINTEN_reg(USB, epn, flags);
+}
+
+/** \brief Disable the endpoint interrupt
+ * \param[in] epn Endpoint number.
+ * \param[in] flags Interrupt flags.
+ */
+static inline void _usbd_ep_int_dis(uint8_t epn, uint32_t flags)
+{
+	hri_usbendpoint_clear_EPINTEN_reg(USB, epn, flags);
+}
+
+/** \brief Check if endpoint is control endpoint
+ * \param[in] epn Endpoint number.
+ */
+static inline bool _usbd_ep_is_ctrl(uint8_t epn)
+{
+	return (hri_usbendpoint_read_EPCFG_reg(USB, epn) == USB_D_EPCFG_CTRL);
+}
+
+/** \brief Set endpoint stall
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] st Stall status.
+ */
+static inline void _usbd_ep_set_stall(uint8_t epn, uint8_t bank_n, bool st)
+{
+	if (st) {
+		hri_usbendpoint_set_EPSTATUS_reg(USB, epn, (USB_DEVICE_EPSTATUS_STALLRQ0 << bank_n));
+	} else {
+		hri_usbendpoint_clear_EPSTATUS_reg(USB, epn, (USB_DEVICE_EPSTATUS_STALLRQ0 << bank_n));
+	}
+}
+
+/** \brief Check if the endpoint is stalled
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \return \c true if it's stalled.
+ */
+static inline bool _usbd_ep_is_stalled(uint8_t epn, uint8_t bank_n)
+{
+	Usb *hw = USB;
+	return (hri_usbendpoint_read_EPSTATUS_reg(hw, epn) & (USB_DEVICE_EPSTATUS_STALLRQ0 << bank_n));
+}
+
+/** \brief Check if stall has been sent from the endpoint
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \return \c true if it's sent.
+ */
+static inline bool _usbd_ep_is_stall_sent(uint8_t epn, uint8_t bank_n)
+{
+	Usb *hw = USB;
+	return (hri_usbendpoint_read_EPINTFLAG_reg(hw, epn) & (USB_DEVICE_EPINTFLAG_STALL0 << bank_n));
+}
+
+/** \brief ACK endpoint STALL interrupt
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ */
+static inline void _usbd_ep_ack_stall(uint8_t epn, uint8_t bank_n)
+{
+	_usbd_ep_int_ack(epn, (USB_DEVICE_EPINTFLAG_STALL0 << bank_n));
+}
+
+/** \brief Enable/disable endpoint STALL interrupt
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] en \c true to enable, \c false to disable.
+ */
+static inline void _usbd_ep_int_stall_en(uint8_t epn, uint8_t bank_n, const bool en)
+{
+	if (en) {
+		_usbd_ep_int_en(epn, USB_DEVICE_EPINTFLAG_STALL0 << bank_n);
+	} else {
+		_usbd_ep_int_dis(epn, USB_DEVICE_EPINTFLAG_STALL0 << bank_n);
+	}
+}
+
+/** \brief Stop SETUP transactions
+ * \param[in] epn Endpoint number.
+ */
+static inline void _usbd_ep_stop_setup(uint8_t epn)
+{
+	hri_usbendpoint_clear_EPINTEN_RXSTP_bit(USB, epn);
+}
+
+/** \brief Check if SETUP packet is ready in cache
+ * \param[in] epn Endpoint number.
+ */
+static inline bool _usbd_ep_is_setup(uint8_t epn)
+{
+	return hri_usbendpoint_get_EPINTFLAG_reg(USB, epn, USB_DEVICE_EPINTFLAG_RXSTP);
+}
+
+/** \brief ACK endpoint SETUP interrupt
+ * \param[in] epn Endpoint number.
+ */
+static inline void _usbd_ep_ack_setup(uint8_t epn)
+{
+	_usbd_ep_int_ack(epn, USB_DEVICE_EPINTFLAG_RXSTP);
+}
+
+/** \brief Set endpoint toggle value
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] tgl Toggle value.
+ */
+static inline void _usbd_ep_set_toggle(uint8_t epn, uint8_t bank_n, uint8_t tgl)
+{
+	if (tgl) {
+		hri_usbendpoint_set_EPSTATUS_reg(USB, epn, (USB_DEVICE_EPSTATUS_DTGLOUT << bank_n));
+	} else {
+		hri_usbendpoint_clear_EPSTATUS_reg(USB, epn, (USB_DEVICE_EPSTATUS_DTGLOUT << bank_n));
+	}
+}
+
+/** \brief ACK IN/OUT complete interrupt
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ */
+static inline void _usbd_ep_ack_io_cpt(uint8_t epn, uint8_t bank_n)
+{
+	_usbd_ep_int_ack(epn, USB_DEVICE_EPINTFLAG_TRCPT0 << bank_n);
+}
+
+/** \brief Set DMA buffer used for bank data
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] addr DMA buffer address to set.
+ */
+static inline void _usbd_ep_set_buf(uint8_t epn, uint8_t bank_n, uint32_t addr)
+{
+	UsbDeviceDescBank *bank = &prvt_inst.desc_table[epn].DeviceDescBank[bank_n];
+	bank->ADDR.reg          = addr;
+}
+
+/** \brief Set bank count for IN transactions
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] count Data count for IN.
+ */
+static inline void _usbd_ep_set_in_count(uint8_t epn, uint8_t bank_n, uint16_t count)
+{
+	UsbDeviceDescBank *bank             = &prvt_inst.desc_table[epn].DeviceDescBank[bank_n];
+	bank->PCKSIZE.bit.MULTI_PACKET_SIZE = count;
+}
+
+/** \brief Set bank size for IN transactions
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] size Data size for IN.
+ */
+static inline void _usbd_ep_set_in_size(uint8_t epn, uint8_t bank_n, uint16_t size)
+{
+	UsbDeviceDescBank *bank      = &prvt_inst.desc_table[epn].DeviceDescBank[bank_n];
+	bank->PCKSIZE.bit.BYTE_COUNT = size;
+}
+
+/** \brief Set bank count for OUT transaction
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] count Data count for OUT.
+ */
+static inline void _usbd_ep_set_out_count(uint8_t epn, uint8_t bank_n, uint16_t count)
+{
+	UsbDeviceDescBank *bank      = &prvt_inst.desc_table[epn].DeviceDescBank[bank_n];
+	bank->PCKSIZE.bit.BYTE_COUNT = count;
+}
+
+/** \brief Set bank size for OUT transactions
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] size Data size for OUT.
+ */
+static inline void _usbd_ep_set_out_size(uint8_t epn, uint8_t bank_n, uint16_t size)
+{
+	UsbDeviceDescBank *bank             = &prvt_inst.desc_table[epn].DeviceDescBank[bank_n];
+	bank->PCKSIZE.bit.MULTI_PACKET_SIZE = size;
+}
+
+/** Set bank size and count for IN transactions
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] size Data size.
+ * \param[in] count Initial data count.
+ */
+static inline void _usbd_ep_set_in_trans(uint8_t epn, uint8_t bank_n, uint32_t size, uint32_t count)
+{
+	_usbd_ep_set_in_size(epn, bank_n, size);
+	_usbd_ep_set_in_count(epn, bank_n, count);
+}
+
+/** \brief Set bank size and count for OUT transaction
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] size Data size.
+ * \param[in] count Initial data count.
+ */
+static inline void _usbd_ep_set_out_trans(uint8_t epn, uint8_t bank_n, uint32_t size, uint32_t count)
+{
+	_usbd_ep_set_out_size(epn, bank_n, size);
+	_usbd_ep_set_out_count(epn, bank_n, count);
+}
+
+/** \brief Clear bank status
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ */
+static inline void _usbd_ep_clear_bank_status(uint8_t epn, uint8_t bank_n)
+{
+	UsbDeviceDescBank *bank = &prvt_inst.desc_table[epn].DeviceDescBank[bank_n];
+	bank->STATUS_BK.reg     = 0;
+}
+
+/** Set IN ready for IN transactions
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] rdy Set to \c true to indicate IN packet ready to TX.
+ */
+static inline void _usbd_ep_set_in_rdy(uint8_t epn, uint8_t bank_n, const bool rdy)
+{
+	if (rdy) {
+		hri_usbendpoint_set_EPSTATUS_reg(USB, epn, USB_DEVICE_EPSTATUS_BK0RDY << bank_n);
+	} else {
+		hri_usbendpoint_clear_EPSTATUS_reg(USB, epn, USB_DEVICE_EPSTATUS_BK0RDY << bank_n);
+	}
+}
+
+/** \brief Set bank ready for OUT transactions
+ * \param[in] epn Endpoint number.
+ * \param[in] bank_n Endpoint bank number.
+ * \param[in] rdy Set to \c true to indicate OUT bank ready to RX.
+ */
+static inline void _usbd_ep_set_out_rdy(uint8_t epn, uint8_t bank_n, const bool rdy)
+{
+	if (rdy) {
+		hri_usbendpoint_clear_EPSTATUS_reg(USB, epn, USB_DEVICE_EPSTATUS_BK0RDY << bank_n);
+	} else {
+		hri_usbendpoint_set_EPSTATUS_reg(USB, epn, USB_DEVICE_EPSTATUS_BK0RDY << bank_n);
+	}
+}
+
+/**
+ *  \brief Convert USB endpoint size to HW PCKSIZE.SIZE
+ * \param[in] n Number of bytes of endpoint size.
+ */
+static inline uint8_t _usbd_ep_pcksize_size(uint16_t n)
+{
+	return (
+	    (n > 512)
+	        ? 7
+	        : ((n > 256) ? 6 : ((n > 128) ? 5 : ((n > 64) ? 4 : ((n > 32) ? 3 : ((n > 16) ? 2 : ((n > 8) ? 1 : 0)))))));
+}
+
+/**
+ *  \brief Obtain endpoint descriptor pointer
+ * \param[in] epn Endpoint number.
+ * \param[in] dir Endpoint direction.
+ */
+static inline struct _usb_d_dev_ep *_usb_d_dev_ept(uint8_t epn, bool dir)
+{
+	uint8_t ep_index = (epn == 0) ? 0 : (dir ? (epn + CONF_USB_D_MAX_EP_N) : epn);
+	return &dev_inst.ep[ep_index];
+}
+
+/**
+ * \brief Handles USB SOF interrupt
+ */
+static inline void _usb_d_dev_sof(void)
+{
+	/* ACK SOF interrupt. */
+	hri_usbdevice_clear_INTFLAG_reg(USB, USB_DEVICE_INTFLAG_SOF);
+	dev_inst.callbacks.sof();
+}
+
+/**
+ * \brief Handles USB LPM Suspend interrupt
+ */
+static inline void _usb_d_dev_lpmsusp(void)
+{
+	uint8_t  i;
+	uint32_t lpm_variable = 0;
+
+	/* ACK LPMSUSP interrupt. */
+	hri_usbdevice_clear_INTFLAG_reg(USB, USB_D_SUSPEND_INT_FLAGS);
+	/* Change interrupt masks */
+	hri_usbdevice_clear_INTEN_reg(USB, USB_D_SUSPEND_INT_FLAGS);
+	hri_usbdevice_set_INTEN_reg(USB, USB_D_WAKEUP_INT_FLAGS);
+
+	/* Find LPM data */
+	for (i = 0; i < CONF_USB_D_MAX_EP_N; i++) {
+		UsbDeviceDescBank *bank = &prvt_inst.desc_table[i].DeviceDescBank[0];
+		if (bank->EXTREG.bit.SUBPID == 0x3) {
+			/* Save LPM variable */
+			lpm_variable = bank->EXTREG.bit.VARIABLE;
+			/* Clear */
+			bank->EXTREG.reg = 0;
+			break;
+		}
+	}
+	dev_inst.callbacks.event(USB_EV_LPM_SUSPEND, lpm_variable);
+}
+
+/**
+ * \brief Handles USB RAM Error interrupt
+ */
+static inline void _usb_d_dev_ramerr(void)
+{
+	hri_usbdevice_clear_INTFLAG_reg(USB, USB_DEVICE_INTFLAG_RAMACER);
+	dev_inst.callbacks.event(USB_EV_ERROR, 0);
+}
+
+/**
+ * \brief Handles USB resume/wakeup interrupts
+ */
+static inline void _usb_d_dev_wakeup(void)
+{
+	hri_usbdevice_clear_INTFLAG_reg(USB, USB_D_WAKEUP_INT_FLAGS);
+	hri_usbdevice_clear_INTEN_reg(USB, USB_D_WAKEUP_INT_FLAGS);
+	hri_usbdevice_set_INTEN_reg(USB, USB_D_SUSPEND_INT_FLAGS);
+
+	_usb_d_dev_wait_clk_rdy(CONF_USB_D_CLK_SRC);
+	dev_inst.callbacks.event(USB_EV_WAKEUP, 0);
+}
+
+/**
+ * \brief Handles USB signal reset interrupt
+ */
+static inline void _usb_d_dev_reset(void)
+{
+	/* EP0 will not be reseted by USB RESET, disable manually. */
+	hri_usbendpoint_write_EPCFG_reg(USB, 0, 0);
+
+	hri_usbdevice_clear_INTFLAG_reg(USB, USB_DEVICE_INTFLAG_EORST);
+	hri_usbdevice_clear_INTEN_reg(USB, USB_D_WAKEUP_INT_FLAGS);
+	hri_usbdevice_set_INTEN_reg(USB, USB_D_SUSPEND_INT_FLAGS);
+
+	_usb_d_dev_reset_epts();
+	dev_inst.callbacks.event(USB_EV_RESET, 0);
+}
+
+static inline void _usb_d_dev_suspend(void)
+{
+	hri_usbdevice_clear_INTFLAG_reg(USB, USB_D_SUSPEND_INT_FLAGS);
+	hri_usbdevice_clear_INTEN_reg(USB, USB_D_SUSPEND_INT_FLAGS);
+	hri_usbdevice_set_INTEN_reg(USB, USB_D_WAKEUP_INT_FLAGS);
+
+	dev_inst.callbacks.event(USB_EV_SUSPEND, 0);
+}
+
+/**
+ * \brief Handles USB non-endpoint interrupt
+ */
+static inline bool _usb_d_dev_handle_nep(void)
+{
+	bool     rc    = true;
+	uint16_t flags = hri_usbdevice_read_INTFLAG_reg(USB);
+	flags &= hri_usbdevice_read_INTEN_reg(USB);
+
+	if (flags & USB_DEVICE_INTFLAG_SOF) {
+		_usb_d_dev_sof();
+		return true;
+	}
+	if (flags & USB_DEVICE_INTFLAG_LPMSUSP) {
+		_usb_d_dev_lpmsusp();
+	} else if (flags & USB_DEVICE_INTFLAG_RAMACER) {
+		_usb_d_dev_ramerr();
+	} else if (flags & USB_D_WAKEUP_INT_FLAGS) {
+		_usb_d_dev_wakeup();
+	} else if (flags & USB_DEVICE_INTFLAG_EORST) {
+		_usb_d_dev_reset();
+	} else if (flags & USB_DEVICE_INTFLAG_SUSPEND) {
+		_usb_d_dev_suspend();
+	} else {
+		rc = false;
+	}
+	return rc;
+}
+
+/**
+ * \brief Prepare next IN transactions
+ * \param[in] ept Pointer to endpoint information.
+ * \param[in] isr Invoked from ISR.
+ */
+static void _usb_d_dev_in_next(struct _usb_d_dev_ep *ept, bool isr)
+{
+	Usb *              hw          = USB;
+	uint8_t            epn         = USB_EP_GET_N(ept->ep);
+	UsbDeviceDescBank *bank        = &prvt_inst.desc_table[epn].DeviceDescBank[0];
+	uint16_t           trans_count = isr ? bank[1].PCKSIZE.bit.BYTE_COUNT : 0;
+	uint16_t           trans_next;
+	uint16_t           last_pkt = trans_count & ((ept->size == 1023) ? ept->size : (ept->size - 1));
+	uint8_t            inten    = 0;
+	bool               is_ctrl  = _usb_d_dev_ep_is_ctrl(ept);
+
+	if (isr) {
+		_usbd_ep_ack_io_cpt(epn, 1);
+	}
+
+	ept->trans_count += trans_count;
+	/* Send more data. */
+	if (ept->trans_count < ept->trans_size) {
+		trans_next = ept->trans_size - ept->trans_count;
+		if (ept->flags.bits.use_cache) {
+			if (trans_next > ept->size) {
+				trans_next = ept->size;
+			}
+			memcpy(ept->cache, &ept->trans_buf[ept->trans_count], trans_next);
+			_usbd_ep_set_buf(epn, 1, (uint32_t)ept->cache);
+		} else {
+			if (trans_next > USB_D_DEV_TRANS_MAX) {
+				trans_next = USB_D_DEV_TRANS_MAX;
+			}
+			_usbd_ep_set_buf(epn, 1, (uint32_t)&ept->trans_buf[ept->trans_count]);
+		}
+		_usbd_ep_set_in_trans(epn, 1, trans_next, 0);
+		goto _in_tx_exec;
+	} else if (ept->flags.bits.need_zlp) {
+		ept->flags.bits.need_zlp = 0;
+		_usbd_ep_set_in_trans(epn, 1, 0, 0);
+		goto _in_tx_exec;
+	}
+	/* Complete. */
+	if (is_ctrl) {
+		hri_usbendpoint_clear_EPINTEN_reg(hw, epn, USB_D_BANK1_INT_FLAGS | USB_DEVICE_EPINTFLAG_TRCPT0);
+	} else {
+		hri_usbendpoint_clear_EPINTEN_reg(hw, epn, USB_D_BANK1_INT_FLAGS);
+	}
+
+	/* No ping-pong, so ask more data without background transfer. */
+	if (last_pkt == ept->size) {
+		ept->flags.bits.is_busy = 0;
+		if (dev_inst.ep_callbacks.more(ept->ep, ept->trans_count)) {
+			/* More data added. */
+			return;
+		}
+		ept->flags.bits.is_busy = 1;
+	}
+	/* Finish normally. */
+	_usb_d_dev_trans_done(ept, USB_TRANS_DONE);
+	return;
+
+_in_tx_exec:
+	if (!isr) {
+		if (is_ctrl) {
+			/* Control endpoint: SETUP or OUT will abort IN transaction.
+			 * SETUP: terminate the IN without any notification. Trigger
+			 *        SETUP callback.
+			 * OUT NAK: terminate IN.
+			 */
+			inten = USB_D_BANK1_INT_FLAGS | USB_DEVICE_EPINTFLAG_TRFAIL0;
+		} else {
+			/* Initialize normal IN transaction. */
+			inten = USB_D_BANK1_INT_FLAGS;
+		}
+		hri_usbendpoint_set_EPINTEN_reg(hw, epn, inten);
+	}
+	_usbd_ep_set_in_rdy(epn, 1, true);
+}
+
+/**
+ * \brief Prepare next OUT transactions
+ * \param[in] ept Pointer to endpoint information.
+ * \param[in] isr Invoked from ISR.
+ */
+static void _usb_d_dev_out_next(struct _usb_d_dev_ep *ept, bool isr)
+{
+	Usb *              hw         = USB;
+	uint8_t            epn        = USB_EP_GET_N(ept->ep);
+	UsbDeviceDescBank *bank       = &prvt_inst.desc_table[epn].DeviceDescBank[0];
+	uint16_t           trans_size = isr ? bank->PCKSIZE.bit.MULTI_PACKET_SIZE : 0;
+	uint16_t           last_trans = isr ? bank->PCKSIZE.bit.BYTE_COUNT : 0;
+	uint16_t           size_mask  = (ept->size == 1023) ? 1023 : (ept->size - 1);
+	uint16_t           last_pkt   = last_trans & size_mask;
+	uint16_t           trans_next;
+	uint8_t            inten;
+	bool               is_ctrl = _usb_d_dev_ep_is_ctrl(ept);
+
+	if (isr) {
+		_usbd_ep_ack_io_cpt(epn, 0);
+	}
+
+	/* If cache is used, copy data to buffer. */
+	if (ept->flags.bits.use_cache && ept->trans_size) {
+		uint16_t buf_remain = ept->trans_size - ept->trans_count;
+		memcpy(&ept->trans_buf[ept->trans_count], ept->cache, (buf_remain > last_pkt) ? last_pkt : buf_remain);
+	}
+
+	/* Force wait ZLP */
+	if (ept->trans_size == 0 && ept->flags.bits.need_zlp) {
+		ept->flags.bits.need_zlp  = 0;
+		ept->flags.bits.use_cache = 1;
+		_usbd_ep_set_buf(epn, 0, (uint32_t)ept->cache);
+		_usbd_ep_set_out_trans(epn, 0, ept->size, 0);
+		goto _out_rx_exec;
+	} else if (isr && last_pkt < ept->size) {
+		/* Short packet. */
+		ept->flags.bits.need_zlp = 0;
+		ept->trans_count += last_trans;
+	} else {
+		/* Full packets. */
+		ept->trans_count += trans_size;
+
+		/* Wait more data */
+		if (ept->trans_count < ept->trans_size) {
+			/* Continue OUT */
+			trans_next = ept->trans_size - ept->trans_count;
+			if (ept->flags.bits.use_cache) {
+				/* Expect single packet each time. */
+				if (trans_next > ept->size) {
+					trans_next = ept->size;
+				}
+				_usbd_ep_set_buf(epn, 0, (uint32_t)ept->cache);
+			} else {
+				/* Multiple packets each time. */
+				if (trans_next > ept->size) {
+					if (trans_next > USB_D_DEV_TRANS_MAX) {
+						trans_next = USB_D_DEV_TRANS_MAX;
+					} else {
+						/* Must expect multiple of ep size. */
+						trans_next -= trans_next & size_mask;
+					}
+				} else if (trans_next < ept->size) {
+					/* Last un-aligned packet should be cached. */
+					ept->flags.bits.use_cache = 1;
+				}
+				_usbd_ep_set_buf(epn, 0, (uint32_t)&ept->trans_buf[ept->trans_count]);
+			}
+			_usbd_ep_set_out_trans(epn, 0, trans_next, 0);
+			goto _out_rx_exec;
+		}
+	}
+	/* Finish normally. */
+	if (is_ctrl) {
+		hri_usbendpoint_clear_EPINTEN_reg(hw, epn, USB_D_BANK0_INT_FLAGS | USB_DEVICE_EPINTFLAG_TRFAIL1);
+	} else {
+		hri_usbendpoint_clear_EPINTEN_reg(hw, epn, USB_D_BANK0_INT_FLAGS);
+	}
+	/* Use ep0 out cache for next setup packets */
+	if (0 == epn) {
+		_usbd_ep_set_buf(epn, 0, (uint32_t)ept->cache);
+	}
+	_usb_d_dev_trans_done(ept, USB_TRANS_DONE);
+	return;
+
+_out_rx_exec:
+	if (!isr) {
+		if (is_ctrl) {
+			/* Initialize control OUT transaction. */
+
+			/* Control transfer: SETUP or IN request will abort the
+			 *                   OUT transactions.
+			 * SETUP: terminate OUT without any notification.
+			 *        Trigger SETUP notification.
+			 * IN NAK: finish OUT normally. Notify data done.
+			 */
+			_usbd_ep_clear_bank_status(epn, 1);
+			/* Detect OUT, SETUP, NAK IN */
+			inten = USB_D_BANK0_INT_FLAGS | USB_DEVICE_EPINTFLAG_TRFAIL1;
+		} else {
+			/* Initialize normal OUT transaction. */
+			inten = USB_D_BANK0_INT_FLAGS;
+		}
+		hri_usbendpoint_set_EPINTEN_reg(hw, epn, inten);
+	}
+	_usbd_ep_set_out_rdy(epn, 0, true);
+}
+
+/**
+ * \brief Handles setup received interrupt
+ * \param[in] ept Pointer to endpoint information.
+ */
+static void _usb_d_dev_handle_setup(struct _usb_d_dev_ep *ept)
+{
+	uint8_t epn     = USB_EP_GET_N(ept->ep);
+	bool    is_ctrl = _usb_d_dev_ep_is_ctrl(ept);
+
+	if (!is_ctrl) {
+		/* Should never be here! */
+		_usbd_ep_ack_setup(epn);
+		_usbd_ep_stop_setup(epn);
+		return;
+	}
+	/* Control transfer:
+	 * SETUP transaction will terminate IN/OUT transaction,
+	 * and start new transaction with received SETUP packet.
+	 */
+	if (_usb_d_dev_ep_is_busy(ept)) {
+		ept->flags.bits.is_busy = 0;
+
+		/* Stop transfer on either direction. */
+		_usbd_ep_set_in_rdy(epn, 1, false);
+		_usbd_ep_set_out_rdy(epn, 0, false);
+	}
+	ept->flags.bits.is_stalled = 0;
+
+	/* Clear status and notify SETUP */
+	_usbd_ep_clear_bank_status(epn, 0);
+	_usbd_ep_clear_bank_status(epn, 1);
+	_usbd_ep_int_ack(epn, USB_D_BANK0_INT_FLAGS | USB_D_BANK1_INT_FLAGS);
+	_usbd_ep_int_dis(epn, USB_D_BANK0_INT_FLAGS | USB_D_BANK1_INT_FLAGS);
+	/* Invoke callback. */
+	dev_inst.ep_callbacks.setup(ept->ep);
+}
+
+/**
+ * \brief Handles stall sent interrupt
+ * \param[in] ept Pointer to endpoint information.
+ * \param[in] bank_n Bank number.
+ */
+static void _usb_d_dev_handle_stall(struct _usb_d_dev_ep *ept, const uint8_t bank_n)
+{
+	uint8_t epn = USB_EP_GET_N(ept->ep);
+	/* Clear interrupt enable. Leave status there for status check. */
+	_usbd_ep_int_stall_en(epn, bank_n, false);
+	dev_inst.ep_callbacks.done(ept->ep, USB_TRANS_STALL, ept->trans_count);
+}
+
+/**
+ * \brief Handles transaction fail interrupt
+ * \param[in] ept Pointer to endpoint information.
+ * \param[in] bank_n Bank number.
+ */
+static void _usb_d_dev_handle_trfail(struct _usb_d_dev_ep *ept, const uint8_t bank_n)
+{
+	Usb *              hw      = USB;
+	uint8_t            epn     = USB_EP_GET_N(ept->ep);
+	const uint8_t      fail[2] = {USB_DEVICE_EPINTFLAG_TRFAIL0, USB_DEVICE_EPINTFLAG_TRFAIL1};
+	UsbDeviceDescBank *bank    = prvt_inst.desc_table[epn].DeviceDescBank;
+	uint8_t            eptype
+	    = bank_n ? hri_usbendpoint_read_EPCFG_EPTYPE1_bf(hw, epn) : hri_usbendpoint_read_EPCFG_EPTYPE0_bf(hw, epn);
+	bool                      is_ctrl = _usb_d_dev_ep_is_ctrl(ept);
+	USB_DEVICE_STATUS_BK_Type st;
+	st.reg = bank[bank_n].STATUS_BK.reg;
+
+	if ((eptype == USB_D_EPTYPE_ISOCH) && st.bit.CRCERR) {
+		bank[bank_n].STATUS_BK.bit.CRCERR = 0;
+		hri_usbendpoint_clear_EPINTFLAG_reg(hw, epn, fail[bank_n]);
+		hri_usbendpoint_clear_EPINTEN_reg(hw, epn, fail[bank_n]);
+		_usb_d_dev_trans_stop(ept, bank_n, USB_TRANS_ERROR);
+	} else if (st.bit.ERRORFLOW) {
+		bank[bank_n].STATUS_BK.bit.ERRORFLOW = 0;
+		hri_usbendpoint_clear_EPINTFLAG_reg(hw, epn, fail[bank_n]);
+		hri_usbendpoint_clear_EPINTEN_reg(hw, epn, fail[bank_n]);
+		/* Abort control transfer. */
+		if (is_ctrl && _usb_d_dev_ep_is_busy(ept)) {
+			if (bank_n != _usb_d_dev_ep_is_in(ept)) {
+				_usb_d_dev_trans_stop(ept, _usb_d_dev_ep_is_in(ept), USB_TRANS_DONE);
+			}
+		}
+	} else {
+		_usbd_ep_clear_bank_status(epn, bank_n);
+		hri_usbendpoint_clear_EPINTFLAG_reg(hw, epn, fail[bank_n]);
+		hri_usbendpoint_clear_EPINTEN_reg(hw, epn, fail[bank_n]);
+	}
+}
+
+/**
+ * \brief Analyze flags for setup transaction
+ * \param[in] ept Pointer to endpoint information.
+ * \param[in] flags Endpoint interrupt flags.
+ */
+static inline void _usb_d_dev_trans_setup_isr(struct _usb_d_dev_ep *ept, const uint8_t flags)
+{
+	/*
+	 * SETPU is automatically ACKed by hardware
+	 * OUT & IN should be set to NAK when checking SETUP
+	 * No need to check OUT & IN status.
+	 */
+	if (flags & USB_DEVICE_EPINTFLAG_RXSTP) {
+		_usb_d_dev_handle_setup(ept);
+	} else if (flags & USB_DEVICE_EPINTFLAG_STALL1) {
+		_usb_d_dev_handle_stall(ept, 1);
+	} else if (flags & USB_DEVICE_EPINTFLAG_STALL0) {
+		_usb_d_dev_handle_stall(ept, 0);
+	}
+}
+
+/**
+ * \brief Analyze flags for IN transactions
+ * \param[in] ept Pointer to endpoint information.
+ * \param[in] flags Endpoint interrupt flags.
+ */
+static inline void _usb_d_dev_trans_in_isr(struct _usb_d_dev_ep *ept, const uint8_t flags)
+{
+	/*
+	 * Check IN flags
+	 * If control endpoint, SETUP & OUT is checked to see if abort
+	 */
+	if (flags & USB_DEVICE_EPINTFLAG_STALL1) {
+		_usb_d_dev_handle_stall(ept, 1);
+	} else if (flags & USB_DEVICE_EPINTFLAG_TRFAIL1) {
+		_usb_d_dev_handle_trfail(ept, 1);
+	} else if (flags & USB_DEVICE_EPINTFLAG_TRCPT1) {
+		_usb_d_dev_in_next(ept, true);
+	} else if (_usb_d_dev_ep_is_ctrl(ept)) {
+		/* Check OUT NAK
+		 * Check SETUP
+		 */
+		if (flags & USB_DEVICE_EPINTFLAG_TRFAIL0) {
+			_usb_d_dev_handle_trfail(ept, 0);
+		} else if (flags & USB_DEVICE_EPINTFLAG_RXSTP) {
+			_usb_d_dev_handle_setup(ept);
+		}
+	}
+}
+
+/**
+ * \brief Analyze flags for OUT transactions
+ * \param[in] ept Pointer to endpoint information.
+ * \param[in] flags Endpoint interrupt flags.
+ */
+static inline void _usb_d_dev_trans_out_isr(struct _usb_d_dev_ep *ept, const uint8_t flags)
+{
+	/*
+	 * Check OUT flags.
+	 * If control endpoint, SETUP & IN NAK is checked to see if abort
+	 */
+	if (flags & USB_DEVICE_EPINTFLAG_STALL0) {
+		_usb_d_dev_handle_stall(ept, 0);
+	} else if (flags & USB_DEVICE_EPINTFLAG_TRFAIL0) {
+		_usb_d_dev_handle_trfail(ept, 0);
+	} else if (flags & USB_DEVICE_EPINTFLAG_TRCPT0) {
+		_usb_d_dev_out_next(ept, true);
+	} else if (_usb_d_dev_ep_is_ctrl(ept)) {
+		/* Check IN NAK
+		 * Check SETUP
+		 */
+		if (flags & USB_DEVICE_EPINTFLAG_TRFAIL1) {
+			_usb_d_dev_handle_trfail(ept, 1);
+		} else if (flags & USB_DEVICE_EPINTFLAG_RXSTP) {
+			_usb_d_dev_handle_setup(ept);
+		}
+	}
+}
+
+/**
+ * \brief Handles the endpoint interrupts.
+ * \param[in] epint Endpoint interrupt summary (by bits).
+ * \param[in] ept Pointer to endpoint information.
+ */
+static inline void _usb_d_dev_handle_eps(uint32_t epint, struct _usb_d_dev_ep *ept)
+{
+	Usb *hw = USB;
+
+	uint8_t flags, mask;
+	uint8_t epn = USB_EP_GET_N(ept->ep);
+
+	if (!(epint & (1u << epn))) {
+		return;
+	}
+	flags = hw->DEVICE.DeviceEndpoint[epn].EPINTFLAG.reg;
+	mask  = hw->DEVICE.DeviceEndpoint[epn].EPINTENSET.reg;
+	flags &= mask;
+	if (flags) {
+		if ((ept->flags.bits.eptype == 0x1) && !_usb_d_dev_ep_is_busy(ept)) {
+			_usb_d_dev_trans_setup_isr(ept, flags);
+		} else if (_usb_d_dev_ep_is_in(ept)) {
+			_usb_d_dev_trans_in_isr(ept, flags);
+		} else {
+			_usb_d_dev_trans_out_isr(ept, flags);
+		}
+	}
+}
+
+/**
+ * \brief USB device interrupt handler
+ * \param[in] unused The parameter is not used
+ */
+static void _usb_d_dev_handler(void)
+{
+	Usb *   hw = USB;
+	uint8_t i;
+
+	uint16_t epint = hw->DEVICE.EPINTSMRY.reg;
+	if (0 == epint) {
+		if (_usb_d_dev_handle_nep()) {
+			return;
+		}
+	}
+	/* Handle endpoints */
+	for (i = 0; i < USB_D_N_EP; i++) {
+		struct _usb_d_dev_ep *ept = &dev_inst.ep[i];
+		if (ept->ep == 0xFF) {
+			continue;
+		}
+		_usb_d_dev_handle_eps(epint, ept);
+	}
+}
+
+/**
+ * \brief Reset all endpoint software instances
+ */
+static void _usb_d_dev_reset_epts(void)
+{
+	uint8_t i;
+	for (i = 0; i < USB_D_N_EP; i++) {
+		_usb_d_dev_trans_done(&dev_inst.ep[i], USB_TRANS_RESET);
+		dev_inst.ep[i].ep       = 0xFF;
+		dev_inst.ep[i].flags.u8 = 0;
+	}
+	memset(prvt_inst.desc_table, 0, sizeof(UsbDeviceDescriptor) * (CONF_USB_D_MAX_EP_N + 1));
+}
+
+int32_t _usb_d_dev_init(void)
+{
+	Usb *         hw         = USB;
+	uint8_t       speed      = CONF_USB_D_SPEED;
+	const uint8_t spdconf[4] = {
+	    USB_DEVICE_CTRLB_SPDCONF(1), /* LS */
+	    USB_DEVICE_CTRLB_SPDCONF(0), /* FS */
+	    0,
+	    0 /* Reserved */
+	};
+
+	if (!hri_usbdevice_is_syncing(hw, USB_SYNCBUSY_SWRST)) {
+		if (hri_usbdevice_get_CTRLA_reg(hw, USB_CTRLA_ENABLE)) {
+			hri_usbdevice_clear_CTRLA_ENABLE_bit(hw);
+			hri_usbdevice_wait_for_sync(hw, USB_SYNCBUSY_ENABLE);
+		}
+		hri_usbdevice_write_CTRLA_reg(hw, USB_CTRLA_SWRST);
+	}
+	hri_usbdevice_wait_for_sync(hw, USB_SYNCBUSY_SWRST);
+
+	dev_inst.callbacks.sof   = (_usb_d_dev_sof_cb_t)_dummy_func_no_return;
+	dev_inst.callbacks.event = (_usb_d_dev_event_cb_t)_dummy_func_no_return;
+
+	dev_inst.ep_callbacks.setup = (_usb_d_dev_ep_cb_setup_t)_dummy_func_no_return;
+	dev_inst.ep_callbacks.more  = (_usb_d_dev_ep_cb_more_t)_dummy_func_no_return;
+	dev_inst.ep_callbacks.done  = (_usb_d_dev_ep_cb_done_t)_dummy_func_no_return;
+
+	_usb_d_dev_reset_epts();
+
+	_usb_load_calib();
+
+	hri_usbdevice_write_CTRLA_reg(hw, USB_CTRLA_RUNSTDBY);
+	hri_usbdevice_write_DESCADD_reg(hw, (uint32_t)prvt_inst.desc_table);
+	hri_usbdevice_write_CTRLB_reg(hw, spdconf[speed] | USB_DEVICE_CTRLB_DETACH);
+
+	return ERR_NONE;
+}
+
+void _usb_d_dev_deinit(void)
+{
+	Usb *hw = USB;
+
+	while (_usb_d_dev_disable() < 0)
+		;
+
+	hri_usbdevice_write_CTRLA_reg(hw, USB_CTRLA_SWRST);
+
+	NVIC_DisableIRQ(USB_0_IRQn);
+	NVIC_ClearPendingIRQ(USB_0_IRQn);
+	NVIC_DisableIRQ(USB_1_IRQn);
+	NVIC_ClearPendingIRQ(USB_1_IRQn);
+	NVIC_DisableIRQ(USB_2_IRQn);
+	NVIC_ClearPendingIRQ(USB_2_IRQn);
+	NVIC_DisableIRQ(USB_3_IRQn);
+	NVIC_ClearPendingIRQ(USB_3_IRQn);
+}
+
+int32_t _usb_d_dev_enable(void)
+{
+	Usb *   hw = USB;
+	uint8_t ctrla;
+
+	if (hri_usbdevice_get_SYNCBUSY_reg(hw, (USB_SYNCBUSY_ENABLE | USB_SYNCBUSY_SWRST))) {
+		return -USB_ERR_DENIED;
+	}
+	ctrla = hri_usbdevice_read_CTRLA_reg(hw);
+	if ((ctrla & USB_CTRLA_ENABLE) == 0) {
+		hri_usbdevice_write_CTRLA_reg(hw, ctrla | USB_CTRLA_ENABLE);
+	}
+
+	NVIC_EnableIRQ(USB_0_IRQn);
+	NVIC_EnableIRQ(USB_1_IRQn);
+	NVIC_EnableIRQ(USB_2_IRQn);
+	NVIC_EnableIRQ(USB_3_IRQn);
+
+	hri_usbdevice_set_INTEN_reg(hw,
+	                            USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST | USB_DEVICE_INTENSET_RAMACER
+	                                | USB_D_SUSPEND_INT_FLAGS);
+
+	return ERR_NONE;
+}
+
+int32_t _usb_d_dev_disable(void)
+{
+	Usb *   hw = USB;
+	uint8_t ctrla;
+
+	if (hri_usbdevice_get_SYNCBUSY_reg(hw, (USB_SYNCBUSY_ENABLE | USB_SYNCBUSY_SWRST))) {
+		return -USB_ERR_DENIED;
+	}
+
+	ctrla = hri_usbdevice_read_CTRLA_reg(hw);
+	if (ctrla & USB_CTRLA_ENABLE) {
+		hri_usbdevice_write_CTRLA_reg(hw, ctrla & ~USB_CTRLA_ENABLE);
+	}
+
+	NVIC_DisableIRQ(USB_0_IRQn);
+	NVIC_DisableIRQ(USB_1_IRQn);
+	NVIC_DisableIRQ(USB_2_IRQn);
+	NVIC_DisableIRQ(USB_3_IRQn);
+
+	hri_usbdevice_clear_INTEN_reg(hw,
+	                              USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST | USB_DEVICE_INTENSET_RAMACER
+	                                  | USB_D_SUSPEND_INT_FLAGS | USB_D_WAKEUP_INT_FLAGS);
+
+	return ERR_NONE;
+}
+
+void _usb_d_dev_attach(void)
+{
+	hri_usbdevice_clear_CTRLB_DETACH_bit(USB);
+}
+
+void _usb_d_dev_detach(void)
+{
+	hri_usbdevice_set_CTRLB_DETACH_bit(USB);
+}
+
+#ifndef USB_FSMSTATUS_FSMSTATE_ON
+#define USB_FSMSTATUS_FSMSTATE_ON USB_FSMSTATUS_FSMSTATE(2ul)
+#endif
+void _usb_d_dev_send_remotewakeup(void)
+{
+	uint32_t retry = CONF_USB_RMT_WKUP_RETRY;
+	_usb_d_dev_wait_clk_rdy(CONF_USB_D_CLK_SRC);
+	while ((USB_FSMSTATUS_FSMSTATE_ON != hri_usbdevice_read_FSMSTATUS_FSMSTATE_bf(USB)) && (retry--)) {
+		USB->DEVICE.CTRLB.bit.UPRSM = 1;
+	}
+}
+
+enum usb_speed _usb_d_dev_get_speed(void)
+{
+	uint8_t              sp       = (enum usb_speed)hri_usbdevice_read_STATUS_SPEED_bf(USB);
+	const enum usb_speed speed[2] = {USB_SPEED_FS, USB_SPEED_LS};
+
+	return speed[sp];
+}
+
+void _usb_d_dev_set_address(uint8_t addr)
+{
+	hri_usbdevice_write_DADD_reg(USB, USB_DEVICE_DADD_ADDEN | USB_DEVICE_DADD_DADD(addr));
+}
+
+uint8_t _usb_d_dev_get_address(void)
+{
+	uint8_t addr = hri_usbdevice_read_DADD_DADD_bf(USB);
+	return addr;
+}
+
+uint16_t _usb_d_dev_get_frame_n(void)
+{
+	uint16_t fn = hri_usbdevice_read_FNUM_FNUM_bf(USB);
+	return fn;
+}
+
+uint8_t _usb_d_dev_get_uframe_n(void)
+{
+	uint8_t ufn = hri_usbdevice_read_FNUM_MFNUM_bf(USB);
+	return ufn;
+}
+
+/**
+ *  \brief Start a setup transaction
+ *  \param[in] ept Endpoint information.
+ */
+static inline void _usb_d_dev_trans_setup(struct _usb_d_dev_ep *ept)
+{
+	Usb *   hw  = USB;
+	uint8_t epn = USB_EP_GET_N(ept->ep);
+
+	_usbd_ep_set_buf(epn, 0, (uint32_t)ept->cache);
+	_usbd_ep_set_out_trans(epn, 0, ept->size, 0);
+
+	hri_usbendpoint_clear_EPSTATUS_reg(hw, epn, USB_DEVICE_EPSTATUS_STALLRQ(0x3) | USB_DEVICE_EPSTATUS_BK1RDY);
+	_usbd_ep_set_out_rdy(epn, 0, false);
+
+	hri_usbendpoint_set_EPINTEN_reg(hw, epn, USB_D_SETUP_INT_FLAGS);
+}
+
+int32_t _usb_d_dev_ep0_init(const uint8_t max_pkt_siz)
+{
+	return _usb_d_dev_ep_init(0, USB_EP_XTYPE_CTRL, max_pkt_siz);
+}
+
+int32_t _usb_d_dev_ep_init(const uint8_t ep, const uint8_t attr, const uint16_t max_pkt_siz)
+{
+	uint8_t               epn = USB_EP_GET_N(ep);
+	bool                  dir = USB_EP_GET_DIR(ep);
+	struct _usb_d_dev_ep *ept = _usb_d_dev_ept(epn, dir);
+
+	uint8_t                        ep_type = attr & USB_EP_XTYPE_MASK;
+	const struct _usb_ep_cfg_item *pcfg    = &_usb_ep_cfgs[epn];
+
+	if (epn > CONF_USB_D_MAX_EP_N) {
+		return -USB_ERR_PARAM;
+	}
+	if (ept->ep != 0xFF) {
+		return -USB_ERR_REDO;
+	}
+	if (ep_type == USB_EP_XTYPE_CTRL) {
+		struct _usb_d_dev_ep *ept_in = _usb_d_dev_ept(epn, !dir);
+		if (ept_in->ep != 0xFF) {
+			return -USB_ERR_REDO;
+		}
+		if (pcfg->cache == NULL) {
+			return -USB_ERR_FUNC;
+		}
+	}
+	if ((dir ? pcfg->i_cache : pcfg->cache) && ((dir ? pcfg->i_size : pcfg->size) < max_pkt_siz)) {
+		return -USB_ERR_FUNC;
+	}
+
+	/* Initialize EP n settings */
+	ept->cache    = (uint8_t *)(dir ? pcfg->i_cache : pcfg->cache);
+	ept->size     = max_pkt_siz;
+	ept->flags.u8 = (ep_type + 1);
+	ept->ep       = ep;
+
+	return USB_OK;
+}
+
+void _usb_d_dev_ep_deinit(uint8_t ep)
+{
+	Usb *                 hw  = USB;
+	uint8_t               epn = USB_EP_GET_N(ep);
+	bool                  dir = USB_EP_GET_DIR(ep);
+	struct _usb_d_dev_ep *ept = _usb_d_dev_ept(epn, dir);
+
+	if (epn > CONF_USB_D_MAX_EP_N || !_usb_d_dev_ep_is_used(ept)) {
+		return;
+	}
+
+	/* Finish pending transactions. */
+	_usb_d_dev_trans_stop(ept, dir, USB_TRANS_RESET);
+
+	/* Disable the endpoint. */
+	if (_usb_d_dev_ep_is_ctrl(ept)) {
+		hw->DEVICE.DeviceEndpoint[ep].EPCFG.reg = 0;
+	} else if (USB_EP_GET_DIR(ep)) {
+		hw->DEVICE.DeviceEndpoint[USB_EP_GET_N(ep)].EPCFG.reg &= ~USB_DEVICE_EPCFG_EPTYPE1_Msk;
+	} else {
+		hw->DEVICE.DeviceEndpoint[ep].EPCFG.reg &= ~USB_DEVICE_EPCFG_EPTYPE0_Msk;
+	}
+	ept->flags.u8 = 0;
+	ept->ep       = 0xFF;
+}
+
+int32_t _usb_d_dev_ep_enable(const uint8_t ep)
+{
+	Usb *                 hw    = USB;
+	uint8_t               epn   = USB_EP_GET_N(ep);
+	bool                  dir   = USB_EP_GET_DIR(ep);
+	struct _usb_d_dev_ep *ept   = _usb_d_dev_ept(epn, dir);
+	uint8_t               epcfg = hri_usbendpoint_read_EPCFG_reg(hw, epn);
+	UsbDeviceDescBank *   bank;
+
+	if (epn > CONF_USB_D_MAX_EP_N || !_usb_d_dev_ep_is_used(ept)) {
+		return -USB_ERR_PARAM;
+	}
+
+	bank = prvt_inst.desc_table[epn].DeviceDescBank;
+	if (ept->flags.bits.eptype == USB_D_EPTYPE_CTRL) {
+		if (epcfg & (USB_DEVICE_EPCFG_EPTYPE1_Msk | USB_DEVICE_EPCFG_EPTYPE0_Msk)) {
+			return -USB_ERR_REDO;
+		}
+		hri_usbendpoint_write_EPCFG_reg(hw, epn, USB_D_EPCFG_CTRL);
+		bank[0].PCKSIZE.reg = USB_DEVICE_PCKSIZE_MULTI_PACKET_SIZE(ept->size)
+		                      | USB_DEVICE_PCKSIZE_SIZE(_usbd_ep_pcksize_size(ept->size));
+		bank[1].PCKSIZE.reg
+		    = USB_DEVICE_PCKSIZE_BYTE_COUNT(ept->size) | USB_DEVICE_PCKSIZE_SIZE(_usbd_ep_pcksize_size(ept->size));
+		/* By default, control endpoint accept SETUP and NAK all other token. */
+		_usbd_ep_set_out_rdy(epn, 0, false);
+		_usbd_ep_set_in_rdy(epn, 1, false);
+
+		_usbd_ep_clear_bank_status(epn, 0);
+		_usbd_ep_clear_bank_status(epn, 1);
+
+		/* Enable SETUP reception for control endpoint. */
+		_usb_d_dev_trans_setup(ept);
+
+	} else if (dir) {
+		if (epcfg & USB_DEVICE_EPCFG_EPTYPE1_Msk) {
+			return -USB_ERR_REDO;
+		}
+		epcfg |= USB_DEVICE_EPCFG_EPTYPE1(ept->flags.bits.eptype);
+		hri_usbendpoint_write_EPCFG_reg(hw, epn, epcfg);
+
+		bank[1].PCKSIZE.reg
+		    = USB_DEVICE_PCKSIZE_BYTE_COUNT(ept->size) | USB_DEVICE_PCKSIZE_SIZE(_usbd_ep_pcksize_size(ept->size));
+
+		/* By default, IN endpoint will NAK all token. */
+		_usbd_ep_set_in_rdy(epn, 1, false);
+		_usbd_ep_clear_bank_status(epn, 1);
+
+	} else {
+
+		if (epcfg & USB_DEVICE_EPCFG_EPTYPE0_Msk) {
+			return -USB_ERR_REDO;
+		}
+		epcfg |= USB_DEVICE_EPCFG_EPTYPE0(ept->flags.bits.eptype);
+		hri_usbendpoint_write_EPCFG_reg(hw, epn, epcfg);
+
+		bank[0].PCKSIZE.reg = USB_DEVICE_PCKSIZE_MULTI_PACKET_SIZE(ept->size)
+		                      | USB_DEVICE_PCKSIZE_SIZE(_usbd_ep_pcksize_size(ept->size));
+
+		/* By default, OUT endpoint will NAK all token. */
+		_usbd_ep_set_out_rdy(epn, 0, false);
+		_usbd_ep_clear_bank_status(epn, 0);
+	}
+
+	return USB_OK;
+}
+
+void _usb_d_dev_ep_disable(const uint8_t ep)
+{
+	Usb *                 hw  = USB;
+	uint8_t               epn = USB_EP_GET_N(ep);
+	bool                  dir = USB_EP_GET_DIR(ep);
+	struct _usb_d_dev_ep *ept = _usb_d_dev_ept(epn, dir);
+
+	_usb_d_dev_trans_stop(ept, dir, USB_TRANS_RESET);
+	if (_usb_d_dev_ep_is_ctrl(ept)) {
+		hri_usbendpoint_clear_EPINTEN_reg(hw, epn, USB_D_ALL_INT_FLAGS);
+	}
+}
+
+/**
+ * \brief Get endpoint stall status
+ * \param[in] ept Pointer to endpoint information.
+ * \param[in] dir Endpoint direction.
+ * \return Stall status.
+ * \retval \c true Endpoint is stalled.
+ * \retval \c false Endpoint is not stalled.
+ */
+static inline int32_t _usb_d_dev_ep_stall_get(struct _usb_d_dev_ep *ept, bool dir)
+{
+	uint8_t epn = USB_EP_GET_N(ept->ep);
+	return _usbd_ep_is_stalled(epn, dir);
+}
+
+/**
+ * \brief Set endpoint stall
+ * \param[in, out] ept Pointer to endpoint information.
+ * \param[in] dir Endpoint direction.
+ * \return Always 0, success.
+ */
+static inline int32_t _usb_d_dev_ep_stall_set(struct _usb_d_dev_ep *ept, bool dir)
+{
+	uint8_t epn = USB_EP_GET_N(ept->ep);
+	_usbd_ep_set_stall(epn, dir, true);
+	_usbd_ep_int_en(epn, USB_DEVICE_EPINTFLAG_STALL0 << dir);
+	ept->flags.bits.is_stalled = 1;
+	/* In stall interrupt abort the transfer. */
+	return ERR_NONE;
+}
+
+/**
+ * \brief Clear endpoint stall
+ * \param[in, out] ept Pointer to endpoint information.
+ * \param[in] dir Endpoint direction.
+ * \return Always 0, success.
+ */
+static inline int32_t _usb_d_dev_ep_stall_clr(struct _usb_d_dev_ep *ept, bool dir)
+{
+	uint8_t epn        = USB_EP_GET_N(ept->ep);
+	bool    is_stalled = _usbd_ep_is_stalled(epn, dir);
+	if (!is_stalled) {
+		return ERR_NONE;
+	}
+	_usbd_ep_set_stall(epn, dir, false);
+	_usbd_ep_int_dis(epn, USB_DEVICE_EPINTFLAG_STALL0 << dir);
+	if (_usbd_ep_is_stall_sent(epn, dir)) {
+		_usbd_ep_ack_stall(epn, dir);
+		_usbd_ep_set_toggle(epn, dir, 0);
+	}
+	if (_usb_d_dev_ep_is_ctrl(ept)) {
+		if ((hri_usbendpoint_read_EPSTATUS_reg(USB, epn) & USB_DEVICE_EPSTATUS_STALLRQ_Msk) == 0) {
+			ept->flags.bits.is_stalled = 0;
+		}
+	} else {
+		ept->flags.bits.is_stalled = 0;
+	}
+	return ERR_NONE;
+}
+
+int32_t _usb_d_dev_ep_stall(const uint8_t ep, const enum usb_ep_stall_ctrl ctrl)
+{
+	uint8_t               epn = USB_EP_GET_N(ep);
+	bool                  dir = USB_EP_GET_DIR(ep);
+	struct _usb_d_dev_ep *ept = _usb_d_dev_ept(epn, dir);
+	int32_t               rc;
+
+	if (epn > CONF_USB_D_MAX_EP_N) {
+		return -USB_ERR_PARAM;
+	}
+
+	if (USB_EP_STALL_SET == ctrl) {
+		rc = _usb_d_dev_ep_stall_set(ept, dir);
+	} else if (USB_EP_STALL_CLR == ctrl) {
+		rc = _usb_d_dev_ep_stall_clr(ept, dir);
+	} else {
+		rc = _usb_d_dev_ep_stall_get(ept, dir);
+	}
+	return rc;
+}
+
+/**
+ *  \brief Finish the transaction and invoke callback
+ * \param[in, out] ept Pointer to endpoint information.
+ * \param[in] code Information code passed.
+ */
+static void _usb_d_dev_trans_done(struct _usb_d_dev_ep *ept, const int32_t code)
+{
+	if (!(_usb_d_dev_ep_is_used(ept) && _usb_d_dev_ep_is_busy(ept))) {
+		return;
+	}
+	ept->flags.bits.is_busy = 0;
+	dev_inst.ep_callbacks.done(ept->ep, code, ept->trans_count);
+}
+
+/**
+ *  \brief Terminate the transaction with specific status code
+ * \param[in, out] ept Pointer to endpoint information.
+ * \param[in] dir Endpoint direction.
+ * \param[in] code Information code passed.
+ */
+static void _usb_d_dev_trans_stop(struct _usb_d_dev_ep *ept, bool dir, const int32_t code)
+{
+	uint8_t epn = USB_EP_GET_N(ept->ep);
+	;
+	const uint8_t intflags[2] = {USB_D_BANK0_INT_FLAGS, USB_D_BANK1_INT_FLAGS};
+	if (!(_usb_d_dev_ep_is_used(ept) && _usb_d_dev_ep_is_busy(ept))) {
+		return;
+	}
+	/* Stop transfer */
+	if (dir) {
+		/* NAK IN */
+		_usbd_ep_set_in_rdy(epn, 1, false);
+	} else {
+		/* NAK OUT */
+		_usbd_ep_set_out_rdy(epn, 0, false);
+	}
+	_usbd_ep_int_ack(epn, intflags[dir]);
+	_usbd_ep_int_dis(epn, intflags[dir]);
+	_usb_d_dev_trans_done(ept, code);
+}
+
+int32_t _usb_d_dev_ep_read_req(const uint8_t ep, uint8_t *req_buf)
+{
+	uint8_t            epn   = USB_EP_GET_N(ep);
+	UsbDeviceDescBank *bank  = prvt_inst.desc_table[epn].DeviceDescBank;
+	uint32_t           addr  = bank[0].ADDR.reg;
+	uint16_t           bytes = bank[0].PCKSIZE.bit.BYTE_COUNT;
+
+	if (epn > CONF_USB_D_MAX_EP_N || !req_buf) {
+		return -USB_ERR_PARAM;
+	}
+	if (!_usbd_ep_is_ctrl(epn)) {
+		return -USB_ERR_FUNC;
+	}
+	if (!_usbd_ep_is_setup(epn)) {
+		return ERR_NONE;
+	}
+	memcpy(req_buf, (void *)addr, 8);
+	_usbd_ep_ack_setup(epn);
+
+	return bytes;
+}
+
+int32_t _usb_d_dev_ep_trans(const struct usb_d_transfer *trans)
+{
+	uint8_t               epn = USB_EP_GET_N(trans->ep);
+	bool                  dir = USB_EP_GET_DIR(trans->ep);
+	struct _usb_d_dev_ep *ept = _usb_d_dev_ept(epn, dir);
+
+	uint16_t size_mask      = (ept->size == 1023) ? 1023 : (ept->size - 1);
+	bool     size_n_aligned = (trans->size & size_mask);
+
+	bool use_cache = false;
+
+	volatile hal_atomic_t flags;
+
+	if (epn > CONF_USB_D_MAX_EP_N) {
+		return -USB_ERR_PARAM;
+	}
+
+	/* Cases that needs cache:
+	 * 1. Buffer not in RAM (cache all).
+	 * 2. IN/OUT with unaligned buffer (cache all).
+	 * 3. OUT with unaligned packet size (cache last packet).
+	 * 4. OUT size < 8 (sub-case for 3).
+	 */
+	if (!_usb_is_addr4dma(trans->buf, trans->size) || (!_usb_is_aligned(trans->buf))
+	    || (!dir && (trans->size < ept->size))) {
+		if (!ept->cache) {
+			return -USB_ERR_FUNC;
+		}
+		/* Use cache all the time. */
+		use_cache = true;
+	}
+	if (!dir && size_n_aligned) {
+		if (!ept->cache) {
+			return -USB_ERR_PARAM;
+		}
+		/* Set 'use_cache' on last packet. */
+	}
+
+	/* Check halt */
+	if (ept->flags.bits.is_stalled) {
+		return USB_HALTED;
+	}
+
+	/* Try to start transactions. */
+
+	atomic_enter_critical(&flags);
+	if (_usb_d_dev_ep_is_busy(ept)) {
+		atomic_leave_critical(&flags);
+		return USB_BUSY;
+	}
+	ept->flags.bits.is_busy = 1;
+	atomic_leave_critical(&flags);
+
+	/* Copy transaction information. */
+	ept->trans_buf   = trans->buf;
+	ept->trans_size  = trans->size;
+	ept->trans_count = 0;
+
+	ept->flags.bits.dir       = dir;
+	ept->flags.bits.use_cache = use_cache;
+	ept->flags.bits.need_zlp  = (trans->zlp && (!size_n_aligned));
+
+	if (dir) {
+		_usb_d_dev_in_next(ept, false);
+	} else {
+		_usb_d_dev_out_next(ept, false);
+	}
+
+	return ERR_NONE;
+}
+
+void _usb_d_dev_ep_abort(const uint8_t ep)
+{
+	uint8_t               epn = USB_EP_GET_N(ep);
+	bool                  dir = USB_EP_GET_DIR(ep);
+	struct _usb_d_dev_ep *ept = _usb_d_dev_ept(epn, dir);
+	if (epn > CONF_USB_D_MAX_EP_N) {
+		return;
+	}
+	_usb_d_dev_trans_stop(ept, dir, USB_TRANS_ABORT);
+}
+
+int32_t _usb_d_dev_ep_get_status(const uint8_t ep, struct usb_d_trans_status *stat)
+{
+	uint8_t               epn = USB_EP_GET_N(ep);
+	bool                  dir = USB_EP_GET_DIR(ep);
+	struct _usb_d_dev_ep *ept = _usb_d_dev_ept(epn, dir);
+	bool                  busy, stall;
+
+	if (epn > CONF_USB_D_MAX_EP_N) {
+		return USB_ERR_PARAM;
+	}
+	busy  = ept->flags.bits.is_busy;
+	stall = ept->flags.bits.is_stalled;
+	if (stat) {
+		stat->stall = stall;
+		stat->busy  = busy;
+		stat->setup = USB->DEVICE.DeviceEndpoint[epn].EPINTFLAG.bit.RXSTP;
+		stat->dir   = ept->flags.bits.dir;
+		stat->size  = ept->trans_size;
+		stat->count = ept->trans_count;
+		stat->ep    = ep;
+		stat->xtype = ept->flags.bits.eptype - 1;
+	}
+	if (stall) {
+		return USB_HALTED;
+	}
+	if (busy) {
+		return USB_BUSY;
+	}
+	return USB_OK;
+}
+
+void _usb_d_dev_register_callback(const enum usb_d_cb_type type, const FUNC_PTR func)
+{
+	FUNC_PTR f = (func == NULL) ? (FUNC_PTR)_dummy_func_no_return : (FUNC_PTR)func;
+	if (type == USB_D_CB_EVENT) {
+		dev_inst.callbacks.event = (_usb_d_dev_event_cb_t)f;
+	} else if (type == USB_D_CB_SOF) {
+		dev_inst.callbacks.sof = (_usb_d_dev_sof_cb_t)f;
+	}
+}
+
+void _usb_d_dev_register_ep_callback(const enum usb_d_dev_ep_cb_type type, const FUNC_PTR func)
+{
+	FUNC_PTR f = (func == NULL) ? (FUNC_PTR)_dummy_func_no_return : (FUNC_PTR)func;
+	if (type == USB_D_DEV_EP_CB_SETUP) {
+		dev_inst.ep_callbacks.setup = (_usb_d_dev_ep_cb_setup_t)f;
+	} else if (type == USB_D_DEV_EP_CB_MORE) {
+		dev_inst.ep_callbacks.more = (_usb_d_dev_ep_cb_more_t)f;
+	} else if (type == USB_D_DEV_EP_CB_DONE) {
+		dev_inst.ep_callbacks.done = (_usb_d_dev_ep_cb_done_t)f;
+	}
+}
+
+/**
+ * \brief USB interrupt handler
+ */
+void USB_0_Handler(void)
+{
+
+	_usb_d_dev_handler();
+}
+/**
+ * \brief USB interrupt handler
+ */
+void USB_1_Handler(void)
+{
+
+	_usb_d_dev_handler();
+}
+/**
+ * \brief USB interrupt handler
+ */
+void USB_2_Handler(void)
+{
+
+	_usb_d_dev_handler();
+}
+/**
+ * \brief USB interrupt handler
+ */
+void USB_3_Handler(void)
+{
+
+	_usb_d_dev_handler();
+}