changeset 3935:08933f6eaff1 2018-nfc

default merged into nfc2018
author glihm <bertinp17@icloud.com>
date Tue, 17 Apr 2018 16:02:59 +0200
parents c462f2b053e0 (current diff) 17707fd0e782 (diff)
children
files arch/efm32/drivers/msc/flash.S arch/nrf5x/drivers/Makefile arch/nrf5x/drivers/drivers.config cpu/arm32m/bytecode.c examples/capsule/Makefile examples/capsule/array.c examples/capsule/array.h examples/capsule/config examples/capsule/qsort_bench.c examples/capsule/qsort_capsule.c examples/capsule/qsort_capsule.h examples/capsule/qsort_libc.c examples/capsule/qsort_libc.h examples/enum_demo/Makefile examples/enum_demo/config_emu examples/enum_demo/config_emu_darwin examples/enum_demo/config_soclib examples/enum_demo/hello.c examples/enum_demo/platform.dts examples/memory_map/Makefile examples/memory_map/config examples/memory_map/memory_map.c examples/null_zero_random/Makefile examples/null_zero_random/config_emu examples/null_zero_random/config_soclib examples/null_zero_random/config_x86 examples/null_zero_random/main.c examples/openmp_sort/Makefile examples/openmp_sort/config examples/openmp_sort/sort.c examples/sam7_ex256_demo/Makefile examples/sam7_ex256_demo/bitmap.c examples/sam7_ex256_demo/block.c examples/sam7_ex256_demo/config_sam7 examples/sam7_ex256_demo/i2c.c examples/sam7_ex256_demo/joystick.c examples/sam7_ex256_demo/lcd.c examples/sam7_ex256_demo/main.c examples/sam7_ex256_demo/timer.c examples/spi/Makefile examples/spi/config examples/spi/spi.c examples/tinygl_demo/Makefile examples/tinygl_demo/config examples/tinygl_demo/gears.c examples/tinygl_demo/pf_soclib_tinygl.dts examples/tinygl_demo/spin.c examples/tinygl_demo/ui.h examples/tinygl_demo/vgafb.c examples/vmem/Makefile examples/vmem/config_emu examples/vmem/config_ibmpc examples/vmem/config_soclib examples/vmem/vmem.c libdevice/Makefile libdevice/device.config libdevice/device_persist.c libdevice/include/device/class/persist.h libdevice/include/device/driver.h libdevice/shell.c
diffstat 505 files changed, 63702 insertions(+), 11791 deletions(-) [+]
line wrap: on
line diff
--- a/arch/bcm283x/drivers/gpio/gpio.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/bcm283x/drivers/gpio/gpio.c	Tue Apr 17 16:02:59 2018 +0200
@@ -299,16 +299,19 @@
 
   uint32_t sel;
 
-  if (mux == BCM283X_GPIO_GPFSEL_FSEL_INPUT ||
-      mux == BCM283X_GPIO_GPFSEL_FSEL_OUTPUT)
+  switch (mux)
     {
+    case IOMUX_INVALID_MUX:
+    case BCM283X_GPIO_GPFSEL_FSEL_INPUT:
+    case BCM283X_GPIO_GPFSEL_FSEL_OUTPUT: {
       /* in/out */
       error_t err = bcm283x_gpio_mode(pv, dir, 1ULL << io_id, &sel);
       if (err)
         return err;
+      break;
     }
-  else
-    {
+
+    default:
       /* special function */
       sel = mux;
     }
--- a/arch/bcm283x/drivers/i2c/i2c.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/bcm283x/drivers/i2c/i2c.c	Tue Apr 17 16:02:59 2018 +0200
@@ -527,6 +527,7 @@
   dev_drv_i2c_ctrl_context_cleanup(&pv->i2c_ctrl_ctx);
 #endif
 
+  device_iomux_cleanup(dev);
   mem_free(pv);
   return 0;
 }
--- a/arch/bcm283x/drivers/spi/spi.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/bcm283x/drivers/spi/spi.c	Tue Apr 17 16:02:59 2018 +0200
@@ -241,17 +241,16 @@
 
   LOCK_SPIN_IRQ(&dev->lock);
 
+  tr->err = 0;
+
   if (pv->tr != NULL)
     tr->err = -EBUSY;
   else if (tr->cs_op != DEV_SPI_CS_NOP_NOP)
     tr->err = -ENOTSUP;
-  else
+  else if (tr->data.count > 0)
     {
-      assert(tr->data.count > 0);
-
       pv->tr = tr;
       pv->fifo_lvl = 0;
-      tr->err = 0;
 
       BCM283X_SPI_CS_TA_SET(pv->ctrl, ACTIVE);
       BCM283X_SPI_CS_CLEAR_SET(pv->ctrl, NONE);
@@ -335,6 +334,7 @@
   dev_spi_context_cleanup(&pv->spi_ctrl_ctx);
 #endif
 
+  device_iomux_cleanup(dev);
   mem_free(pv);
   return 0;
 }
--- a/arch/cc26xx/drivers/gpio/gpio.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/cc26xx/drivers/gpio/gpio.c	Tue Apr 17 16:02:59 2018 +0200
@@ -158,7 +158,8 @@
   iocfg_reg &= ~CC26XX_IOC_IOCFG_HYST_EN;         //Input Hysteresis disable
 
   iocfg_set_mode(&iocfg_reg, &oe, mode);
-  iocfg_set_mux(&iocfg_reg, mux);
+  if (mux != IOMUX_INVALID_MUX)
+    iocfg_set_mux(&iocfg_reg, mux);
   iocfg_set_irq(&iocfg_reg, sense);
 
   cc26xx_gpio_mode_reg(io_first, io_last, mask, iocfg_reg, oe);
--- a/arch/cc26xx/drivers/spi/spi.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/cc26xx/drivers/spi/spi.c	Tue Apr 17 16:02:59 2018 +0200
@@ -222,13 +222,14 @@
 
   LOCK_SPIN_IRQ(&dev->lock);
 
+  tr->err = 0;
+
   if (pv->tr != NULL)
     tr->err = -EBUSY;
   else if (tr->cs_op != DEV_SPI_CS_NOP_NOP)
     tr->err = -ENOTSUP;
-  else
+  else if (tr->data.count > 0)
     {
-      assert(tr->data.count > 0);
       tr->err = 0;
       pv->tr = tr;
       pv->fifo_lvl = 0;
@@ -374,6 +375,7 @@
   dev_spi_context_cleanup(&pv->spi_ctrl_ctx);
 #endif
 
+  device_iomux_cleanup(dev);
   mem_free(pv);
 
   return 0;
--- a/arch/cc26xx/drivers/uart/uart_char.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/cc26xx/drivers/uart/uart_char.c	Tue Apr 17 16:02:59 2018 +0200
@@ -476,6 +476,7 @@
   dev_request_queue_destroy(&pv->read_q);
   dev_request_queue_destroy(&pv->write_q);
 
+  device_iomux_cleanup(dev);
   mem_free(pv);
   return 0;
 }
--- a/arch/efm32/Makefile	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/Makefile	Tue Apr 17 16:02:59 2018 +0200
@@ -1,5 +1,5 @@
 
-objs = arch_init.o power.o
+objs = arch_init.o power.o flash.o
 
 meta = ldscript
 
--- a/arch/efm32/arch_init.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/arch_init.c	Tue Apr 17 16:02:59 2018 +0200
@@ -38,25 +38,14 @@
 
   b = EFM32_CMU_ADDR;
 
- /* Enable HFXO */
 #if (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG1) ||\
     (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12)
 
-  x = EFM32_CMU_OSCENCMD_HFXOEN;
-  cpu_mem_write_32(b + EFM32_CMU_OSCENCMD_ADDR, x);
-  while (!(cpu_mem_read_32(b + EFM32_CMU_STATUS_ADDR) & EFM32_CMU_STATUS_HFXORDY))
-    ;
-  cpu_mem_write_32(b + EFM32_CMU_HFCLKSEL_ADDR, EFM32_CMU_HFCLKSEL_HF(HFXO));
-
   x = cpu_mem_read_32(b + EFM32_CMU_CTRL_ADDR);
-  x = EFM32_CMU_CTRL_HFPERCLKEN |
-      EFM32_CMU_CTRL_HFRADIOCLKEN;
   x |= EFM32_CMU_CTRL_HFPERCLKEN;
   cpu_mem_write_32(b + EFM32_CMU_CTRL_ADDR, x);
   
   cpu_mem_write_32(b + EFM32_CMU_HFBUSCLKEN0_ADDR, EFM32_CMU_HFBUSCLKEN0_MASK);
-  cpu_mem_write_32(b + EFM32_CMU_LFBCLKSEL_ADDR, EFM32_CMU_LFBCLKSEL_LFB(LFRCO));
-  cpu_mem_write_32(b + EFM32_CMU_LFACLKSEL_ADDR, EFM32_CMU_LFACLKSEL_LFA(LFRCO));
 
 #elif CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFM
 
@@ -68,13 +57,10 @@
 
 #endif
 
-  cpu_mem_write_32(b + EFM32_CMU_OSCENCMD_ADDR, EFM32_CMU_OSCENCMD_LFRCOEN);
-  while (!(cpu_mem_read_32(b + EFM32_CMU_STATUS_ADDR) & EFM32_CMU_STATUS_LFRCORDY))
-    ;
-
   cpu_mem_write_32(b + EFM32_CMU_HFPERCLKEN0_ADDR, EFM32_CMU_HFPERCLKEN0_MASK);
   cpu_mem_write_32(b + EFM32_CMU_LFACLKEN0_ADDR, EFM32_CMU_LFACLKEN0_MASK);
   cpu_mem_write_32(b + EFM32_CMU_LFBCLKEN0_ADDR, EFM32_CMU_LFBCLKEN0_MASK);
+
 }
 
 #endif
--- a/arch/efm32/boards/g8xxstk.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/boards/g8xxstk.c	Tue Apr 17 16:02:59 2018 +0200
@@ -27,6 +27,7 @@
 # include <device/class/cmu.h>
 # include <device/class/dma.h>
 # include <device/class/i2c.h>
+# include <device/class/uart.h>
 #endif
 
 #include <hexo/iospace.h>
@@ -194,7 +195,9 @@
 
                    DEV_STATIC_RES_DEV_IOMUX("/gpio"),
                    DEV_STATIC_RES_IOMUX("rx", EFM32_LOC1, EFM32_PE1, 0, 0),
-                   DEV_STATIC_RES_IOMUX("tx", EFM32_LOC1, EFM32_PE0, 0, 0)
+                   DEV_STATIC_RES_IOMUX("tx", EFM32_LOC1, EFM32_PE0, 0, 0),
+
+                   DEV_STATIC_RES_UART(115200, 8, 0, 0, 0)
                    );
 
 #endif
@@ -214,7 +217,9 @@
 
                    DEV_STATIC_RES_DEV_IOMUX("/gpio"),
                    DEV_STATIC_RES_IOMUX("tx",  EFM32_LOC0, EFM32_PD4, 0, 0),
-                   DEV_STATIC_RES_IOMUX("rx",  EFM32_LOC0, EFM32_PD5, 0, 0)
+                   DEV_STATIC_RES_IOMUX("rx",  EFM32_LOC0, EFM32_PD5, 0, 0),
+
+                   DEV_STATIC_RES_UART(9600, 8, 0, 0, 0)
                    );
 
 #endif
--- a/arch/efm32/boards/stk3200.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/boards/stk3200.c	Tue Apr 17 16:02:59 2018 +0200
@@ -26,6 +26,7 @@
 # include <device/class/iomux.h>
 # include <device/class/dma.h>
 # include <device/class/cmu.h>
+# include <device/class/uart.h>
 #endif
 
 #include <hexo/iospace.h>
@@ -213,7 +214,9 @@
 
                    DEV_STATIC_RES_DEV_IOMUX("/gpio"),
                    DEV_STATIC_RES_IOMUX("tx", EFM32_LOC0, EFM32_PD4, 0, 0),
-                   DEV_STATIC_RES_IOMUX("rx", EFM32_LOC0, EFM32_PD5, 0, 0)
+                   DEV_STATIC_RES_IOMUX("rx", EFM32_LOC0, EFM32_PD5, 0, 0),
+
+                   DEV_STATIC_RES_UART(9600, 8, 0, 0, 0)
                    );
 
 #endif
--- a/arch/efm32/boards/stk3x00_678.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/boards/stk3x00_678.c	Tue Apr 17 16:02:59 2018 +0200
@@ -28,6 +28,7 @@
 # include <device/class/dma.h>
 # include <device/class/usbdev.h>
 # include <device/class/i2c.h>
+# include <device/class/uart.h>
 #endif
 
 #include <hexo/iospace.h>
@@ -201,7 +202,9 @@
 
                    DEV_STATIC_RES_DEV_IOMUX("/gpio"),
                    DEV_STATIC_RES_IOMUX("rx", EFM32_LOC1, EFM32_PE1, 0, 0),
-                   DEV_STATIC_RES_IOMUX("tx", EFM32_LOC1, EFM32_PE0, 0, 0)
+                   DEV_STATIC_RES_IOMUX("tx", EFM32_LOC1, EFM32_PE0, 0, 0),
+
+                   DEV_STATIC_RES_UART(115200, 8, 0, 0, 0)
                    );
 
 #endif
@@ -221,7 +224,9 @@
 
                    DEV_STATIC_RES_DEV_IOMUX("/gpio"),
                    DEV_STATIC_RES_IOMUX("tx",  EFM32_LOC0, EFM32_PD4, 0, 0),
-                   DEV_STATIC_RES_IOMUX("rx",  EFM32_LOC0, EFM32_PD5, 0, 0)
+                   DEV_STATIC_RES_IOMUX("rx",  EFM32_LOC0, EFM32_PD5, 0, 0),
+
+                   DEV_STATIC_RES_UART(9600, 8, 0, 0, 0)
                    );
 
 #endif
@@ -298,6 +303,26 @@
 
 #endif
 
+#ifdef CONFIG_DRIVER_EFM32_I2C_SLAVE
+
+DEV_DECLARE_STATIC(i2c_dev, "i2cs0", 0, efm32_i2c_slave_drv,
+                   DEV_STATIC_RES_MEM(0x4000a400, 0x4000a800),
+# ifdef CONFIG_DEVICE_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_I2C1, 0),
+# else
+                   DEV_STATIC_RES_FREQ(14000000, 1),
+# endif
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_I2C1, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+
+                   DEV_STATIC_RES_DEV_IOMUX("/gpio"),
+
+                   DEV_STATIC_RES_IOMUX("scl", EFM32_LOC0, EFM32_PC5, 0, 0),
+                   DEV_STATIC_RES_IOMUX("sda", EFM32_LOC0, EFM32_PC4, 0, 0)
+                   );
+
+#endif
+
 #ifdef CONFIG_DRIVER_EFM32_PWM
 
 DEV_DECLARE_STATIC(pwm_dev, "pwm3", 0, efm32_pwm_drv,
--- a/arch/efm32/boards/stk6066a.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/boards/stk6066a.c	Tue Apr 17 16:02:59 2018 +0200
@@ -27,7 +27,8 @@
 # include <device/class/cmu.h>
 # include <device/class/timer.h>
 # include <device/class/dma.h>
-# include <arch/efm32/dma_source.h>
+# include <device/class/uart.h>
+# include <device/class/i2c.h>
 #endif
 
 #include <hexo/iospace.h>
@@ -35,6 +36,7 @@
 #include <arch/efm32/pin.h>
 #include <arch/efm32/gpio.h>
 #include <arch/efm32/cmu.h>
+#include <arch/efm32/dma_source.h>
 #include <arch/efm32/devaddr.h>
 #include <arch/efm32/cmu.h>
 #include <arch/efm32/emu.h>
@@ -42,72 +44,104 @@
 
 #define HFXO_FREQ  38400000
 
-void efm32_board_init()
+static void efm32_wait_button_released()
 {
-  uint32_t b, x;
-
-  b = EFM32_EMU_ADDR;
-
-  x = cpu_mem_read_32(b + EFR32_EMU_PWRCFG_ADDR);
-
-  EFR32_EMU_PWRCFG_PWRCFG_SET(x, DCDCTODVDD);                                                                                            
-  cpu_mem_write_32(b + EFR32_EMU_PWRCFG_ADDR, x);                                                                                     
-  cpu_mem_write_32(b + EFR32_EMU_DCDCCTRL_ADDR, 0x31);
-
-  x = cpu_mem_read_32(b + EFR32_EMU_PWRCFG_ADDR);
-  assert((x & EFR32_EMU_PWRCFG_MASK) == EFR32_EMU_PWRCFG_PWRCFG_DCDCTODVDD);
-
-  x = cpu_mem_read_32(b + EFR32_EMU_PWRCTRL_ADDR);
-  x |= 0x420;
-  cpu_mem_write_32(b + EFR32_EMU_PWRCTRL_ADDR, x);
-
-
-  b = EFM32_CMU_ADDR;
-
-  cpu_mem_write_32(b + EFM32_CMU_OSCENCMD_ADDR, EFM32_CMU_OSCENCMD_HFRCOEN);
-  while (!(cpu_mem_read_32(b + EFM32_CMU_STATUS_ADDR) & EFM32_CMU_STATUS_HFRCORDY))
-    ;
-  cpu_mem_write_32(b + EFM32_CMU_HFCLKSEL_ADDR, EFM32_CMU_HFCLKSEL_HF(HFRCO));
-  
-  x = cpu_mem_read_32(b + EFM32_CMU_HFCLKSTATUS_ADDR);
-  assert(EFM32_CMU_HFCLKSTATUS_SELECTED_GET(x) != EFM32_CMU_HFCLKSTATUS_SELECTED_HFXO);
-
-  /* Enable GPIO clock */
-  x = cpu_mem_read_32(b + EFM32_CMU_HFBUSCLKEN0_ADDR);
-  x |= EFM32_CMU_HFBUSCLKEN0_GPIO;
-  cpu_mem_write_32(b + EFM32_CMU_HFBUSCLKEN0_ADDR, x);
-
-  uint32_t gpio = EFM32_GPIO_ADDR;
   uint32_t button_pin = 86;
+  uint32_t x;
 
   /* wait for button to be released */
   uint32_t bank = button_pin / 16;
   uint32_t h = (button_pin >> 1) & 4;
 
-  x = cpu_mem_read_32(gpio + EFM32_GPIO_MODEL_ADDR(bank) + h);
+  x = cpu_mem_read_32(EFM32_GPIO_ADDR + EFM32_GPIO_MODEL_ADDR(bank) + h);
   EFM32_GPIO_MODEL_MODE_SET(button_pin % 8, x, INPUT);
-  cpu_mem_write_32(gpio + EFM32_GPIO_MODEL_ADDR(bank) + h, x);
+  cpu_mem_write_32(EFM32_GPIO_ADDR + EFM32_GPIO_MODEL_ADDR(bank) + h, x);
 
-  while (!(cpu_mem_read_32(gpio + EFM32_GPIO_DIN_ADDR(bank))
+  while (!(cpu_mem_read_32(EFM32_GPIO_ADDR + EFM32_GPIO_DIN_ADDR(bank))
            & EFM32_GPIO_DIN_DIN(button_pin % 16)))
     ;
+}
+
+void efm32_board_init()
+{
+  uint32_t x;
+  /* unlock registers */
+  cpu_mem_write_32(EFM32_EMU_ADDR + EFR32_EMU_PWRLOCK_ADDR, 0xADE8);
+
+  x = cpu_mem_read_32(EFM32_EMU_ADDR + EFR32_EMU_PWRCFG_ADDR);
+  EFR32_EMU_PWRCFG_PWRCFG_SET(x, DCDCTODVDD);
+  cpu_mem_write_32(EFM32_EMU_ADDR + EFR32_EMU_PWRCFG_ADDR, x);
+
+  x = cpu_mem_read_32(EFM32_EMU_ADDR + EFR32_EMU_PWRCFG_ADDR);
+  assert((x & EFR32_EMU_PWRCFG_MASK) == EFR32_EMU_PWRCFG_PWRCFG_DCDCTODVDD);
+
+  x = cpu_mem_read_32(EFM32_EMU_ADDR + EFR32_EMU_PWRCTRL_ADDR);
+  x |= EFR32_EMU_PWRCTRL_ANASW |
+       EFR32_EMU_PWRCTRL_REGPWRSEL;
+  cpu_mem_write_32(EFM32_EMU_ADDR + EFR32_EMU_PWRCTRL_ADDR, x);
+
+  x = cpu_mem_read_32(EFM32_EMU_ADDR + EFR32_EMU_DCDCLNFREQCTRL_ADDR);
+  EFR32_EMU_DCDCLNFREQCTRL_RCOBAND_SET(x, 4);
+  cpu_mem_write_32(EFM32_EMU_ADDR + EFR32_EMU_DCDCLNFREQCTRL_ADDR, x);
+
+  while (cpu_mem_read_32(EFM32_EMU_ADDR + EFR32_EMU_DCDCSYNC_ADDR) & 1);
+
+  x = cpu_mem_read_32(EFM32_EMU_ADDR + EFR32_EMU_DCDCCTRL_ADDR);  
+  EFR32_EMU_DCDCCTRL_DCDCMODE_SETVAL(x, 1);
+  cpu_mem_write_32(EFM32_EMU_ADDR + EFR32_EMU_DCDCCTRL_ADDR, x);
+
+  x = cpu_mem_read_32(EFM32_EMU_ADDR + EFR32_EMU_DCDCMISCCTRL_ADDR);
+  EFR32_EMU_DCDCMISCCTRL_PFETCNT_SET(x, 7);
+  EFR32_EMU_DCDCMISCCTRL_NFETCNT_SET(x, 7);
+  cpu_mem_write_32(EFM32_EMU_ADDR + EFR32_EMU_DCDCMISCCTRL_ADDR, x);
+
+  /* Enable GPIO clock */
+  x = cpu_mem_read_32(EFM32_CMU_ADDR + EFM32_CMU_HFBUSCLKEN0_ADDR);
+  x |= EFM32_CMU_HFBUSCLKEN0_GPIO;
+  cpu_mem_write_32(EFM32_CMU_ADDR + EFM32_CMU_HFBUSCLKEN0_ADDR, x);
+
+  /* Wait button to be released */
+  efm32_wait_button_released();
+
+  /* Select HFXO as HF clock */
+  x = EFM32_CMU_OSCENCMD_HFXOEN;
+  cpu_mem_write_32(EFM32_CMU_ADDR + EFM32_CMU_OSCENCMD_ADDR, x);
+
+  while (!(cpu_mem_read_32(EFM32_CMU_ADDR + EFM32_CMU_STATUS_ADDR) & EFM32_CMU_STATUS_HFXORDY))
+    ;
+
+  cpu_mem_write_32(EFM32_CMU_ADDR + EFM32_CMU_HFCLKSEL_ADDR, EFM32_CMU_HFCLKSEL_HF(HFXO));
+
+  x = cpu_mem_read_32(EFM32_CMU_ADDR + EFM32_CMU_HFCLKSTATUS_ADDR);
+  assert(EFM32_CMU_HFCLKSTATUS_SELECTED_GET(x) == EFM32_CMU_HFCLKSTATUS_SELECTED_HFXO);
 
   /* Set PA5 high for enabling VCOM */
-  x = cpu_mem_read_32(gpio + EFM32_GPIO_MODEL_ADDR(0));
+  x = cpu_mem_read_32(EFM32_GPIO_ADDR + EFM32_GPIO_MODEL_ADDR(0));
   EFM32_GPIO_MODEL_MODE_SET(5, x, PUSHPULL);
-  cpu_mem_write_32(gpio + EFM32_GPIO_MODEL_ADDR(0), x);
+  cpu_mem_write_32(EFM32_GPIO_ADDR + EFM32_GPIO_MODEL_ADDR(0), x);
 
   x = EFM32_GPIO_DOUT_DOUT(5);
-  cpu_mem_write_32(gpio + EFM32_GPIO_DOUT_ADDR(0) + 0x06000000, x);
+  cpu_mem_write_32(EFM32_GPIO_ADDR + EFM32_GPIO_DOUT_ADDR(0) + 0x06000000, x);
 
   /* Set PF4 and PF5 high for led */
-  x = cpu_mem_read_32(gpio + EFM32_GPIO_MODEL_ADDR(5));
+  x = cpu_mem_read_32(EFM32_GPIO_ADDR + EFM32_GPIO_MODEL_ADDR(5));
   EFM32_GPIO_MODEL_MODE_SET(4, x, PUSHPULL);
   EFM32_GPIO_MODEL_MODE_SET(5, x, PUSHPULL);
-  cpu_mem_write_32(gpio + EFM32_GPIO_MODEL_ADDR(5), x);
+  cpu_mem_write_32(EFM32_GPIO_ADDR + EFM32_GPIO_MODEL_ADDR(5), x);
+  
+  x = EFM32_GPIO_DOUT_DOUT(4) | EFM32_GPIO_DOUT_DOUT(5);
+  cpu_mem_write_32(EFM32_GPIO_ADDR + EFM32_GPIO_DOUT_ADDR(5) + 0x06000000, x);
 
-  x = EFM32_GPIO_DOUT_DOUT(4) | EFM32_GPIO_DOUT_DOUT(5);
-  cpu_mem_write_32(gpio + EFM32_GPIO_DOUT_ADDR(5) + 0x06000000, x);
+#if defined(CONFIG_DRIVER_EFR32_RADIO)
+  x = cpu_mem_read_32(EFM32_CMU_ADDR + EFM32_CMU_CTRL_ADDR);
+  x |= EFM32_CMU_CTRL_HFRADIOCLKEN;
+  cpu_mem_write_32(EFM32_CMU_ADDR + EFM32_CMU_CTRL_ADDR, x);
+
+  cpu_mem_write_32(EFM32_CMU_ADDR + EFM32_CMU_HFRADIOCLKEN0_ADDR, EFM32_CMU_HFRADIOCLKEN0_MASK);
+ #if (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12)
+  cpu_mem_write_32(EFM32_CMU_ADDR + EFM32_CMU_HFRADIOALTCLKEN0_ADDR, EFM32_CMU_HFRADIOALTCLKEN0_MASK);
+ #endif
+#endif 
 
 }
 
@@ -115,7 +149,7 @@
 
 DEV_DECLARE_STATIC(cpu_dev, "cpu", DEVICE_FLAG_CPU, arm32m_drv,
                    DEV_STATIC_RES_ID(0, 0),
-                   DEV_STATIC_RES_FREQ(40000000, 1),
+                   DEV_STATIC_RES_FREQ(HFXO_FREQ, 1),
                    );
 
 #endif
@@ -132,7 +166,8 @@
 
                    DEV_STATIC_RES_DEV_IOMUX("/gpio"),
                    DEV_STATIC_RES_IOMUX("rx", EFM32_LOC0, EFM32_PA1, 0, 0),
-                   DEV_STATIC_RES_IOMUX("tx", EFM32_LOC0, EFM32_PA0, 0, 0)
+                   DEV_STATIC_RES_IOMUX("tx", EFM32_LOC0, EFM32_PA0, 0, 0),
+                   DEV_STATIC_RES_UART(115200, 8, 0, 0, 0)
                    );
 
 #endif
@@ -148,7 +183,41 @@
 
                    DEV_STATIC_RES_DEV_IOMUX("/gpio"),
                    DEV_STATIC_RES_IOMUX("tx",  EFM32_LOC2, EFM32_PA2, 0, 0),
-                   DEV_STATIC_RES_IOMUX("rx",  EFM32_LOC2, EFM32_PA3, 0, 0)
+                   DEV_STATIC_RES_IOMUX("rx",  EFM32_LOC2, EFM32_PA3, 0, 0),
+
+                   DEV_STATIC_RES_UART(9600, 8, 0, 0, 0)
+                   );
+
+#endif
+
+#if defined(CONFIG_DRIVER_EFM32_I2C)
+
+DEV_DECLARE_STATIC(i2c0_dev, "i2c0", 0, efm32_i2c_drv,
+                   DEV_STATIC_RES_MEM(0x4000c000, 0x4000c400),
+                   DEV_STATIC_RES_FREQ(HFXO_FREQ, 1),
+
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_I2C0, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+
+                   DEV_STATIC_RES_DEV_IOMUX("/gpio"),
+                   DEV_STATIC_RES_IOMUX("sda", EFM32_LOC16, EFM32_PC11, 0, 0),
+                   DEV_STATIC_RES_IOMUX("scl", EFM32_LOC14, EFM32_PC10, 0, 0),
+                   DEV_STATIC_RES_I2C_BITRATE(100000),
+                   );
+
+#elif defined(CONFIG_DRIVER_EFM32_I2C_SLAVE)
+
+DEV_DECLARE_STATIC(i2c0_dev, "i2cs0", 0, efm32_i2c_slave_drv,
+                   DEV_STATIC_RES_MEM(0x4000c000, 0x4000c400),
+                   DEV_STATIC_RES_FREQ(HFXO_FREQ, 1),
+
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_I2C0, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+
+                   DEV_STATIC_RES_DEV_IOMUX("/gpio"),
+                   DEV_STATIC_RES_IOMUX("sda", EFM32_LOC16, EFM32_PC11, 0, 0),
+                   DEV_STATIC_RES_IOMUX("scl", EFM32_LOC14, EFM32_PC10, 0, 0),
+                   DEV_STATIC_RES_I2C_BITRATE(100000),
                    );
 
 #endif
@@ -231,13 +300,26 @@
    #error
   #endif
 
-    #ifdef CONFIG_DRIVER_EFM32_TIMER
+  #ifdef CONFIG_DRIVER_EFM32_TIMER
                    DEV_STATIC_RES_DEV_TIMER("/timer0")
-    #endif
+  #endif
                    );
 #endif
 
+#if defined(CONFIG_DRIVER_EFR32_RADIO)
+DEV_DECLARE_STATIC(radio_dev, "efr32_radio", 0, efr32_radio_drv,
+                   DEV_STATIC_RES_FREQ(HFXO_FREQ, 1),
+
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_MODEM, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   DEV_STATIC_RES_IRQ(1, EFM32_IRQ_RAC_SEQ, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   DEV_STATIC_RES_IRQ(2, EFM32_IRQ_RAC_RSM, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   DEV_STATIC_RES_IRQ(3, EFM32_IRQ_BUFC, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   DEV_STATIC_RES_IRQ(4, EFM32_IRQ_AGC, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   DEV_STATIC_RES_IRQ(5, EFM32_IRQ_SYNTH, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   DEV_STATIC_RES_IRQ(6, EFM32_IRQ_RFSENSE, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   DEV_STATIC_RES_IRQ(7, EFM32_IRQ_PROTIMER, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   DEV_STATIC_RES_IRQ(8, EFM32_IRQ_FRC, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
                    );
-
 #endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/boards/stk620xa.c	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,376 @@
+/*
+    This file is part of MutekH.
+    
+    MutekH is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation; version 2.1 of the
+    License.
+    
+    MutekH is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+    
+    You should have received a copy of the GNU Lesser General Public
+    License along with MutekH; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA.
+
+    Copyright Sebastien Cerdan <sebcerdan@gmail.com> (c) 2018
+
+*/
+
+#if defined(CONFIG_DEVICE)
+# include <device/resources.h>
+# include <device/irq.h>
+# include <device/class/iomux.h>
+# include <device/class/cmu.h>
+# include <device/class/dma.h>
+# include <device/class/usbdev.h>
+# include <device/class/i2c.h>
+# include <device/class/uart.h>
+#endif
+
+#include <hexo/iospace.h>
+#include <arch/efm32/irq.h>
+#include <arch/efm32/pin.h>
+#include <arch/efm32/clock.h>
+#include <arch/efm32/dma_source.h>
+#include <arch/efm32/gpio.h>
+#include <arch/efm32/cmu.h>
+#include <arch/efm32/devaddr.h>
+#include <mutek/startup.h>
+
+void efm32_board_init()
+{
+  uint32_t x;
+  uint32_t cmu = EFM32_CMU_ADDR;
+
+  /* Enable HF peripherals clock */
+  x = cpu_mem_read_32(cmu + EFM32_CMU_HFPERCLKDIV_ADDR);
+  x |= EFM32_CMU_HFPERCLKDIV_HFPERCLKEN;
+  cpu_mem_write_32(cmu + EFM32_CMU_HFPERCLKDIV_ADDR, endian_le32(x));
+  /* Enable GPIO clock */
+  x = cpu_mem_read_32(cmu + EFM32_CMU_HFPERCLKEN0_ADDR);
+  x |= EFM32_CMU_HFPERCLKEN0_GPIO;
+  cpu_mem_write_32(cmu + EFM32_CMU_HFPERCLKEN0_ADDR, endian_le32(x));
+
+  uint32_t gpio = EFM32_GPIO_ADDR;
+  uint32_t pin = EFM32_PE3;
+
+  /* Wait for button to be released */
+  uint32_t bank = pin / 16;
+  uint32_t h = (pin >> 1) & 4;
+
+  x = cpu_mem_read_32(gpio + EFM32_GPIO_MODEL_ADDR(bank) + h);
+  EFM32_GPIO_MODEL_MODE_SET(pin % 8, x, INPUT);
+  cpu_mem_write_32(gpio + EFM32_GPIO_MODEL_ADDR(bank) + h, x);
+
+  while (!(cpu_mem_read_32(gpio + EFM32_GPIO_DIN_ADDR(bank))
+           & EFM32_GPIO_DIN_DIN(pin % 16)))
+    ;
+
+  /* Set LED0 on  */
+  pin = EFM32_PF6;
+  bank = pin / 16;
+  h = (pin >> 1) & 4;
+
+  x = cpu_mem_read_32(gpio + EFM32_GPIO_MODEL_ADDR(bank) + h);
+  EFM32_GPIO_MODEL_MODE_SET(pin % 8, x, PUSHPULL);
+  cpu_mem_write_32(gpio + EFM32_GPIO_MODEL_ADDR(bank) + h, x);
+
+  cpu_mem_write_32(gpio + EFM32_GPIO_DOUTSET_ADDR(bank),
+                   EFM32_GPIO_DOUTSET_DOUTSET(pin % 16));
+
+#if CONFIG_MUTEK_PRINTK_ADDR == 0x4000c800 &&   \
+  CONFIG_DRIVER_EFM32_USART_PRINTK_PIN == EFM32_PB3
+
+  /* Enable VCOM  */
+  pin = EFM32_PA12;
+  bank = pin / 16;
+  h = (pin >> 1) & 4;
+
+  x = cpu_mem_read_32(gpio + EFM32_GPIO_MODEL_ADDR(bank) + h);
+  EFM32_GPIO_MODEL_MODE_SET(pin % 8, x, PUSHPULL);
+  cpu_mem_write_32(gpio + EFM32_GPIO_MODEL_ADDR(bank) + h, x);
+
+  cpu_mem_write_32(gpio + EFM32_GPIO_DOUTSET_ADDR(bank),
+                   EFM32_GPIO_DOUTSET_DOUTSET(pin % 16));
+#endif
+}
+
+#if defined(CONFIG_DRIVER_CPU_ARM32M)
+
+DEV_DECLARE_STATIC(cpu_dev, "cpu", DEVICE_FLAG_CPU, arm32m_drv,
+                   DEV_STATIC_RES_ID(0, 0),
+# ifdef CONFIG_CPU_ARM32M_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_CPU, 0)
+# else
+                   DEV_STATIC_RES_FREQ(14000000, 1),
+# endif
+                   );
+
+#endif
+
+#ifdef CONFIG_DRIVER_EFM32_RECMU
+
+DEV_DECLARE_STATIC(recmu_dev, "recmu", 0, efm32_recmu_drv,
+                   DEV_STATIC_RES_MEM(0x400ca000, 0x400ca400), /* RMU */
+                   DEV_STATIC_RES_MEM(0x400c6000, 0x400c6400), /* EMU */
+                   DEV_STATIC_RES_MEM(0x400c8000, 0x400c8400), /* CMU */
+
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_CMU, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+
+                   /* config 0: run on HFRCO @ 14Mhz */
+                   DEV_STATIC_RES_CMU_MUX(EFM32_CLOCK_LFRCO, EFM32_CLOCK_LFACLK, 0b0111, 1, 1),
+                   DEV_STATIC_RES_CMU_MUX(EFM32_CLOCK_HFRCO, EFM32_CLOCK_HFCLK,  0b0011, 1, 1),
+                   DEV_STATIC_RES_CMU_OSC(EFM32_CLOCK_HFRCO, 0b0001, 14000000, 1),
+                   /* config 1: run on HFRCO @ 28Mhz */
+                   DEV_STATIC_RES_CMU_OSC(EFM32_CLOCK_HFRCO, 0b0010, 28000000, 1),
+                   /* config 2: run on LFRCO @ 32khz */
+                   DEV_STATIC_RES_CMU_MUX(EFM32_CLOCK_LFRCO, EFM32_CLOCK_HFCLK,  0b0100, 1, 1),
+
+                   /* config 3: run on crystals HFXO @ 48Mhz, LFXO @ 32Khz */
+                   DEV_STATIC_RES_CMU_OSC(EFM32_CLOCK_LFXO, 0b1000, 32768, 1),
+                   DEV_STATIC_RES_CMU_OSC(EFM32_CLOCK_HFXO, 0b1000, 48000000, 1),
+                   DEV_STATIC_RES_CMU_MUX(EFM32_CLOCK_LFXO, EFM32_CLOCK_LFACLK, 0b1000, 1, 1),
+                   DEV_STATIC_RES_CMU_MUX(EFM32_CLOCK_HFXO, EFM32_CLOCK_HFCLK,  0b1000, 1, 1)
+                   );
+
+#endif
+
+
+#ifdef CONFIG_DRIVER_EFM32_MSC
+
+DEV_DECLARE_STATIC(msc_dev, "mem", 0, efm32_msc_drv,
+                   DEV_STATIC_RES_MEM(0x400c0000, 0x400c0400)
+                   );
+
+#endif
+
+#if defined(CONFIG_DRIVER_EFM32_DMA)
+
+DEV_DECLARE_STATIC(dma_dev, "dma", 0, efm32_dma_drv,
+                   DEV_STATIC_RES_MEM(0x400c2000, 0x400c4000),
+# ifdef CONFIG_DEVICE_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_DMA, 0),
+# else
+                   DEV_STATIC_RES_FREQ(14000000, 1),
+# endif
+
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_DMA, DEV_IRQ_SENSE_RISING_EDGE, 0, 1)
+                   );
+
+#endif
+
+#if defined(CONFIG_DRIVER_EFM32_USART_SPI)
+
+DEV_DECLARE_STATIC(usart0_dev, "spirf", 0, efm32_usart_spi_drv,
+
+                   DEV_STATIC_RES_MEM(0x4000c000, 0x4000c400),
+# ifdef CONFIG_DEVICE_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_USART0, 0),
+# else
+                   DEV_STATIC_RES_FREQ(14000000, 1),
+# endif
+
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_USART0_RX, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+
+#if defined(CONFIG_DRIVER_EFM32_DMA)
+                   DEV_STATIC_RES_DEV_PARAM("dma", "/dma"),
+                   /* Read channel must have higher priority than write channel */
+                   DEV_STATIC_RES_DMA((1 << 0), (EFM32_DMA_SOURCE_USART0 | (EFM32_DMA_SIGNAL_USART0RXDATAV << 8))),
+                   DEV_STATIC_RES_DMA((1 << 1), (EFM32_DMA_SOURCE_USART0 | (EFM32_DMA_SIGNAL_USART0TXEMPTY << 8))),
+#endif
+
+                   DEV_STATIC_RES_DEV_IOMUX("/gpio"),
+                   DEV_STATIC_RES_IOMUX("clk",  EFM32_LOC0, EFM32_PE12, 0, 0),
+                   DEV_STATIC_RES_IOMUX("miso", EFM32_LOC0, EFM32_PE11, 0, 0),
+                   DEV_STATIC_RES_IOMUX("mosi", EFM32_LOC0, EFM32_PE10, 0, 0),
+
+#ifdef CONFIG_DRIVER_EFM32_RTC
+                   DEV_STATIC_RES_DEV_TIMER("/rtc")
+#endif
+                   );
+
+#endif
+
+
+#if defined(CONFIG_DRIVER_EFM32_USART_CHAR)
+
+DEV_DECLARE_STATIC(usart2_dev, "usart2", 0, efm32_usart_drv,
+                   DEV_STATIC_RES_MEM(0x4000e000, 0x4000e400),
+# ifdef CONFIG_DEVICE_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_USART2, 0),
+# else
+                   DEV_STATIC_RES_FREQ(14000000, 1),
+# endif
+
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_USART2_RX, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   DEV_STATIC_RES_IRQ(1, EFM32_IRQ_USART2_TX, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+
+                   DEV_STATIC_RES_DEV_IOMUX("/gpio"),
+                   DEV_STATIC_RES_IOMUX("rx", EFM32_LOC1, EFM32_PB4, 0, 0),
+                   DEV_STATIC_RES_IOMUX("tx", EFM32_LOC1, EFM32_PB3, 0, 0),
+
+                   DEV_STATIC_RES_UART(115200, 8, 0, 0, 0)
+                   );
+
+#endif
+
+
+#ifdef CONFIG_DRIVER_EFM32_LEUART_CHAR
+
+DEV_DECLARE_STATIC(leuart0_dev, "leuart0", 0, efm32_leuart_drv,
+                   DEV_STATIC_RES_MEM(0x40084000, 0x40084400),
+# ifdef CONFIG_DEVICE_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_LEUART0, 0),
+# else
+                   DEV_STATIC_RES_FREQ(32768, 1),
+# endif
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_LEUART0, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+
+                   DEV_STATIC_RES_DEV_IOMUX("/gpio"),
+                   DEV_STATIC_RES_IOMUX("tx",  EFM32_LOC0, EFM32_PD4, 0, 0),
+                   DEV_STATIC_RES_IOMUX("rx",  EFM32_LOC0, EFM32_PD5, 0, 0),
+
+                   DEV_STATIC_RES_UART(9600, 8, 0, 0, 0)
+                   );
+
+#endif
+
+#ifdef CONFIG_DRIVER_EFM32_TIMER
+
+DEV_DECLARE_STATIC(timer0_dev, "timer0", 0, efm32_timer_drv,
+                   DEV_STATIC_RES_MEM(0x40010000, 0x40010400),
+# ifdef CONFIG_DEVICE_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_TIMER0, 0),
+# else
+                   DEV_STATIC_RES_FREQ(14000000, 1),
+# endif
+
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_TIMER0, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   );
+
+#endif
+
+
+
+#ifdef CONFIG_DRIVER_EFM32_RTC
+
+DEV_DECLARE_STATIC(rtc_dev, "rtc", 0, efm32_rtc_drv,
+                   DEV_STATIC_RES_MEM(0x40080000, 0x40080400),
+# ifdef CONFIG_DEVICE_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_RTC, 0),
+# else
+                   DEV_STATIC_RES_FREQ(32768, 1),
+# endif
+
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_RTC, DEV_IRQ_SENSE_RISING_EDGE, 0, 1)
+                   );
+
+#endif
+
+
+#ifdef CONFIG_DRIVER_EFM32_GPIO
+
+DEV_DECLARE_STATIC(gpio_dev, "gpio", 0, efm32_gpio_drv,
+                   DEV_STATIC_RES_MEM(0x40006000, 0x40007000),
+# ifdef CONFIG_DEVICE_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_GPIO, 0),
+# endif
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_GPIO_EVEN, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   DEV_STATIC_RES_IRQ(1, EFM32_IRQ_GPIO_ODD, DEV_IRQ_SENSE_RISING_EDGE, 0, 1)
+                   );
+
+#endif
+
+#ifdef CONFIG_DRIVER_EFM32_I2C
+
+DEV_DECLARE_STATIC(i2c_dev, "i2c1", 0, efm32_i2c_drv,
+                   DEV_STATIC_RES_MEM(0x4000a400, 0x4000a800),
+# ifdef CONFIG_DEVICE_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_I2C1, 0),
+# else
+                   DEV_STATIC_RES_FREQ(14000000, 1),
+# endif
+                   DEV_STATIC_RES_I2C_BITRATE(100000),
+                   DEV_STATIC_RES_DEV_TIMER("/rtc"),
+
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_I2C1, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+
+                   DEV_STATIC_RES_DEV_IOMUX("/gpio"),
+
+                   DEV_STATIC_RES_IOMUX("scl", EFM32_LOC2, EFM32_PE1, 0, 0),
+                   DEV_STATIC_RES_IOMUX("sda", EFM32_LOC2, EFM32_PE0, 0, 0)
+                   );
+
+#endif
+
+#ifdef CONFIG_DRIVER_EFM32_PWM
+
+DEV_DECLARE_STATIC(pwm_dev, "pwm3", 0, efm32_pwm_drv,
+                   DEV_STATIC_RES_MEM(0x40010c00, 0x40011000),
+# ifdef CONFIG_DEVICE_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_TIMER3, 0),
+# else
+                   DEV_STATIC_RES_FREQ(14000000, 1),
+# endif
+
+                   DEV_STATIC_RES_DEV_IOMUX("/gpio"),
+                   /* led0 */
+                   DEV_STATIC_RES_IOMUX("cc2", EFM32_LOC1, EFM32_PE2, 0, 0)
+                   );
+
+#endif
+
+#ifdef CONFIG_DRIVER_EFM32_AES
+
+DEV_DECLARE_STATIC(aes_dev, "aes", 0, efm32_aes_drv,
+                   DEV_STATIC_RES_MEM(0x400e0000, 0x400e0400),
+# ifdef CONFIG_DEVICE_CLOCK
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_AES, 0),
+# endif
+                   DEV_STATIC_RES_DEV_ICU("/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_AES, DEV_IRQ_SENSE_RISING_EDGE, 0, 1)
+                   );
+#endif
+
+#ifdef CONFIG_DRIVER_USB_SYNOPSYS_EFM32
+DEV_DECLARE_STATIC(usb_dev, "usb", 0, efm32_usbdev_drv,
+                   DEV_STATIC_RES_MEM(0x400c4000, 0x400c4400),
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_USB, 0),
+                   DEV_STATIC_RES_CLK_SRC("/recmu", EFM32_CLOCK_USBC, 1),
+                   DEV_STATIC_RES_DEV_PARAM("icu", "/cpu"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_IRQ_USB, DEV_IRQ_SENSE_RISING_EDGE, 0, 1),
+                   DEV_STATIC_RES_DEV_PARAM("iomux", "/gpio"),
+                   DEV_STATIC_RES_IOMUX("vbusen",  EFM32_LOC0, EFM32_PF5, 0, 0)
+                   );
+#endif
+
+#ifdef CONFIG_DRIVER_RFPACKET_SI446X
+DEV_DECLARE_STATIC(si446x_dev, "rfpacket", 0, si446x_drv,
+		   /* spi controller */
+		   DEV_STATIC_RES_DEV_PARAM("spi", "/spirf"),
+		   /* gpio controller */
+                   DEV_STATIC_RES_DEV_PARAM("gpio", "/gpio"),
+                   /* irq */
+                   DEV_STATIC_RES_DEV_PARAM("icu", "/gpio"),
+                   DEV_STATIC_RES_IRQ(0, EFM32_PE13, DEV_IRQ_SENSE_FALLING_EDGE, 0, 1),
+                   /* GPIO */
+                   DEV_STATIC_RES_GPIO("nirq", EFM32_PE13,  1),  
+                   DEV_STATIC_RES_GPIO("cts",  EFM32_PE14,  1), 
+                   DEV_STATIC_RES_GPIO("sdn",  EFM32_PE8,  1), 
+                   /* chip select */
+                   DEV_STATIC_RES_UINT_PARAM("gpio-cs-id", EFM32_PE9),
+);
+#endif
--- a/arch/efm32/drivers/Makefile	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/Makefile	Tue Apr 17 16:02:59 2018 +0200
@@ -3,7 +3,7 @@
 subdirs-$(CONFIG_DRIVER_EFM32_TIMER) += timer 
 subdirs-$(CONFIG_DRIVER_EFM32_RTC) += rtc 
 subdirs-$(CONFIG_DRIVER_EFM32_GPIO) += gpio
-subdirs-$(CONFIG_DRIVER_EFM32_I2C) += i2c
+subdirs += i2c
 subdirs-$(CONFIG_DRIVER_EFM32_RECMU) += recmu
 subdirs-$(CONFIG_DRIVER_EFM32_MSC) += msc
 subdirs-$(CONFIG_DRIVER_EFM32_AES) += aes
@@ -11,3 +11,5 @@
 subdirs-$(CONFIG_DRIVER_EFM32_DMA) += dma
 subdirs-$(CONFIG_DRIVER_EFR32_DMA) += ldma
 subdirs-$(CONFIG_DRIVER_EFM32_ADC) += adc
+subdirs-$(CONFIG_DRIVER_EFM32_BITBANG) += bitbang
+subdirs-$(CONFIG_DRIVER_EFR32_RADIO) += radio
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/bitbang/Makefile	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,3 @@
+
+objs += bitbang.o
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/bitbang/bitbang.c	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,630 @@
+/*
+    This file is part of MutekH.
+
+    MutekH is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation; version 2.1 of the
+    License.
+
+    MutekH is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with MutekH; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA.
+
+    Copyright (c) 2018 Sebastien CERDAN <sebcerdan@gmail.com>
+
+*/
+
+#include <string.h>
+
+#include <hexo/types.h>
+#include <hexo/endian.h>
+#include <hexo/iospace.h>
+#include <hexo/bit.h>
+
+#include <device/device.h>
+#include <device/resources.h>
+#include <device/driver.h>
+#include <device/class/bitbang.h>
+#include <device/class/timer.h>
+#include <device/class/iomux.h>
+#include <device/class/gpio.h>
+#include <device/class/dma.h>
+#include <device/class/bitbang.h>
+#include <device/irq.h>
+#include <device/clock.h>
+
+#include <mutek/mem_alloc.h>
+#include <mutek/kroutine.h>
+#include <mutek/printk.h>
+
+#include <arch/efm32/timer.h>
+
+DRIVER_PV(struct efm32_bitbang_ctx_s
+{
+  struct device_s                  *dev;
+  /* Timer used for bitbanging */
+  uintptr_t                        addr;
+  struct dev_irq_src_s             irq_ep;
+  dev_request_queue_root_t         queue;
+  /* DMA */                       
+  uint16_t                         dma_tx_link;
+  uint16_t                         dma_rx_link;
+  struct dev_dma_rq_s              dma_rq;
+  struct dev_dma_desc_s            dma_desc[2];
+  struct device_dma_s              dma;
+  struct device_iomux_s            iomux;
+
+  struct kroutine_s                kr;
+  uint32_t                         dvalue;
+  uint8_t                          div;
+  iomux_io_id_t                    id;
+
+  struct dev_clock_sink_ep_s       clk_ep;
+  struct dev_freq_s                freq;
+  struct dev_freq_s                sfreq;
+  bool_t                           pending;
+});
+
+STRUCT_COMPOSE(efm32_bitbang_ctx_s, dma_rq);
+STRUCT_COMPOSE(efm32_bitbang_ctx_s, kr);
+
+static void efm32_bitbang_ctx_start_tx(struct efm32_bitbang_ctx_s *pv, struct dev_bitbang_rq_s * rq);
+static void efm32_bitbang_ctx_start_rx(struct efm32_bitbang_ctx_s *pv, struct dev_bitbang_rq_s * rq);
+
+static void efm32_bitbang_freq(struct efm32_bitbang_ctx_s *pv)
+{
+  struct dev_bitbang_rq_s *rq = dev_bitbang_rq_s_cast(dev_request_queue_head(&pv->queue));
+
+  if ((pv->sfreq.num == rq->unit.num) && (rq->unit.denom == pv->sfreq.denom))
+    return;
+
+  pv->sfreq.num = rq->unit.num;
+  pv->sfreq.denom = rq->unit.denom;
+
+  /* Compute scale factor to the requested frequency. */
+  uint32_t scale = (pv->freq.num * rq->unit.denom) / (pv->freq.denom * rq->unit.num);
+
+  pv->div = scale > 1024 ? 10 : bit_msb_index(scale);
+}
+
+static void bitbang_process_next(struct efm32_bitbang_ctx_s *pv)
+{
+  struct dev_bitbang_rq_s *rq = dev_bitbang_rq_s_cast(dev_request_queue_head(&pv->queue));
+
+  pv->pending = 0;
+
+  if (rq == NULL)
+    return;
+
+  efm32_bitbang_freq(pv);
+
+  switch(rq->type)
+    {
+      case DEV_BITBANG_RD:
+        efm32_bitbang_ctx_start_rx(pv, rq);
+        break; 
+      case DEV_BITBANG_WR: 
+        efm32_bitbang_ctx_start_tx(pv, rq);
+        break; 
+      default:
+        rq->err = -ENOTSUP;
+        rq->base.drvdata = NULL;
+        dev_request_queue_pop(&pv->queue);
+        kroutine_exec(&rq->base.kr);
+        break;
+    }
+}
+
+
+static KROUTINE_EXEC(efm32_bitbang_process_next_kr)
+{
+  struct efm32_bitbang_ctx_s *pv = efm32_bitbang_ctx_s_from_kr(kr);
+
+  LOCK_SPIN_IRQ(&pv->dev->lock);
+  bitbang_process_next(pv);
+  LOCK_RELEASE_IRQ(&pv->dev->lock);
+}
+
+static void efm32_bitbang_end_wr_rq(struct efm32_bitbang_ctx_s *pv)
+{
+  LOCK_SPIN_IRQ(&pv->dev->lock);
+
+  struct dev_bitbang_rq_s *rq = dev_bitbang_rq_s_cast(dev_request_queue_head(&pv->queue));
+
+  assert(rq && rq->type == DEV_BITBANG_WR);
+
+  rq->err = 0;
+  rq->base.drvdata = NULL;
+
+  /* End current request */
+  dev_request_queue_pop(&pv->queue);
+  kroutine_exec(&rq->base.kr);
+
+  /* Process next request */
+  kroutine_exec(&pv->kr);
+end:
+  LOCK_RELEASE_IRQ(&pv->dev->lock);
+}
+
+static DEV_DMA_CALLBACK(sx127x_bitbang_tx_dma_done)
+{
+  assert(err == 0);
+
+  struct efm32_bitbang_ctx_s *pv = efm32_bitbang_ctx_s_from_dma_rq(rq);
+
+  /* Set pin as input */
+  DEVICE_OP(&pv->iomux, setup, pv->id, DEV_PIN_INPUT, IOMUX_INVALID_MUX, 0);
+
+  /* Stop timer */
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CMD_ADDR, endian_le32(EFM32_TIMER_CMD_STOP));
+
+  efm32_bitbang_end_wr_rq(pv);
+
+  return 0;
+}
+
+static void efm32_bitbang_end_rd_rq(struct efm32_bitbang_ctx_s *pv, error_t err, size_t size)
+{
+  struct dev_bitbang_rq_s *rq = dev_bitbang_rq_s_cast(dev_request_queue_head(&pv->queue));
+
+  if (rq == NULL)
+    return;
+
+  assert(rq->type == DEV_BITBANG_RD);
+
+  rq->count = size;
+  rq->err = err;
+  rq->base.drvdata = NULL;
+
+  dev_request_queue_pop(&pv->queue);
+  kroutine_exec(&rq->base.kr);
+}
+
+static DEV_DMA_CALLBACK(sx127x_bitbang_rx_dma_done)
+{
+  assert(err == 0);
+
+  struct efm32_bitbang_ctx_s *pv = efm32_bitbang_ctx_s_from_dma_rq(rq);
+
+  LOCK_SPIN_IRQ(&pv->dev->lock);
+
+  /* Turn off CC channel and stop timer */
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CTRL_ADDR, 0);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CMD_ADDR, endian_le32(EFM32_TIMER_CMD_STOP));
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CC_CTRL_ADDR(0), 0);
+
+  uint32_t x = cpu_mem_read_32(pv->addr + EFM32_TIMER_IF_ADDR);
+  x &= cpu_mem_read_32(pv->addr + EFM32_TIMER_IEN_ADDR);
+
+  pv->pending = 1;
+
+  if (x & EFM32_TIMER_IEN_OF)
+    /* Timer irq is pending */
+    goto end;
+
+  /* Buffer overflow */
+  efm32_bitbang_end_rd_rq(pv, -EIO, 0);
+
+  /* Process next request */
+  kroutine_exec(&pv->kr);
+
+end:
+  LOCK_RELEASE_IRQ(&pv->dev->lock);
+  return 0;
+}
+
+static void efm32_bitbang_ctx_start_rx(struct efm32_bitbang_ctx_s *pv, struct dev_bitbang_rq_s * rq)
+{
+  /* Timer */
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CMD_ADDR, endian_le32(EFM32_TIMER_CMD_STOP));
+  /* Timer top value is set to read timeout */
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_TOP_ADDR, rq->read_timeout);
+
+  uint32_t x = EFM32_TIMER_CTRL_MODE(UP) |
+               pv->div << 24|
+               EFM32_TIMER_CTRL_OSMEN |
+               EFM32_TIMER_CTRL_FALLA(RELOADSTART) |
+               EFM32_TIMER_CTRL_RISEA(RELOADSTART);
+
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CTRL_ADDR, endian_le32(x));
+
+  /* Set timer channel as input/capture mapped to external pin */
+  x = EFM32_TIMER_CC_CTRL_MODE(INPUTCAPTURE) |
+      EFM32_TIMER_CC_CTRL_FILT |
+      EFM32_TIMER_CC_CTRL_ICEDGE(BOTH);
+
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CC_CTRL_ADDR(0), endian_le32(x));
+
+  /* Enable Overflow irq */
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_IF_ADDR, 0);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_IEN_ADDR, EFM32_TIMER_IEN_OF);
+
+  /* Start DMA request */
+
+  struct dev_dma_rq_s *drq = &pv->dma_rq;
+
+  /* Desc 0 is used to discard first value */
+
+  struct dev_dma_desc_s *desc = &pv->dma_desc[0];
+
+  desc->src.reg.addr = pv->addr + EFM32_TIMER_CC_CCV_ADDR(0);
+  desc->src.reg.width = rq->sym_width;
+  desc->src.reg.size = 0;
+  desc->src.reg.burst = 1;
+
+  desc->dst.mem.addr = (uintptr_t)&pv->dvalue;
+  desc->dst.mem.stride = 0;
+  desc->dst.mem.inc = DEV_DMA_INC_1_UNITS;
+
+  desc = &pv->dma_desc[1];
+
+  desc->src.reg.addr = pv->addr + EFM32_TIMER_CC_CCV_ADDR(0);
+  desc->src.reg.width = rq->sym_width;
+  desc->src.reg.size = rq->count - 1;
+  desc->src.reg.burst = 1;
+
+  desc->dst.mem.addr = (uintptr_t)rq->symbols;
+  desc->dst.mem.stride = 0;
+  desc->dst.mem.inc = DEV_DMA_INC_1_UNITS;
+
+  drq->dev_link.src = pv->dma_rx_link;
+  drq->type = DEV_DMA_REG_MEM;
+  drq->desc_count_m1 = 1;
+  drq->f_done = sx127x_bitbang_rx_dma_done;
+
+  ensure(DEVICE_OP(&pv->dma, request, drq, NULL) == 0);
+}
+
+static void efm32_bitbang_ctx_start_tx(struct efm32_bitbang_ctx_s *pv, struct dev_bitbang_rq_s * rq)
+{
+  /* Set pin as output */
+  DEVICE_OP(&pv->iomux, setup, pv->id, DEV_PIN_PUSHPULL, IOMUX_INVALID_MUX, 0);
+
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CMD_ADDR, endian_le32(EFM32_TIMER_CMD_STOP));
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CTRL_ADDR, pv->div << 24);
+ 
+  uint32_t x = EFM32_TIMER_CC_CTRL_MODE(OUTPUTCOMPARE) |
+               EFM32_TIMER_CC_CTRL_COFOA(TOGGLE);
+
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CC_CTRL_ADDR(0), endian_le32(x));
+
+  pv->dvalue = 0xFFFF;
+
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_IEN_ADDR, 0);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_IF_ADDR, 0);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CNT_ADDR, 0);
+
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_TOP_ADDR, 1024);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_TOPB_ADDR, (uint32_t)rq->symbols);
+
+  struct dev_dma_rq_s *drq = &pv->dma_rq;
+
+  drq->dev_link.dst = pv->dma_tx_link;
+  drq->type = DEV_DMA_MEM_REG;
+  drq->desc_count_m1 = 1;
+  drq->f_done = sx127x_bitbang_tx_dma_done;
+
+  struct dev_dma_desc_s *desc = &pv->dma_desc[0];
+
+  desc->src.mem.addr = (uintptr_t)rq->symbols + (1 << rq->sym_width);
+  desc->src.mem.size = rq->count - 2;
+  desc->src.mem.width = rq->sym_width;
+  desc->src.mem.inc = DEV_DMA_INC_1_UNITS;
+  desc->src.mem.stride = 0;
+  desc->dst.reg.addr = pv->addr + EFM32_TIMER_TOPB_ADDR;
+  desc->dst.reg.burst = 1;
+
+  /* Desc 1 is used to wait end of TX */
+
+  desc = &pv->dma_desc[1];
+
+  desc->src.mem.size = 1;
+  desc->src.mem.width = rq->sym_width;
+  desc->src.mem.inc = DEV_DMA_INC_0_UNIT;
+  desc->src.mem.stride = 0;
+  desc->src.mem.addr = (uintptr_t)&pv->dvalue;
+  desc->dst.reg.addr = pv->addr + EFM32_TIMER_TOPB_ADDR;
+  desc->dst.reg.burst = 1;
+
+  /* Start DMA request */
+
+  ensure(DEVICE_OP(&pv->dma, request, drq, NULL) == 0);
+
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CMD_ADDR, endian_le32(EFM32_TIMER_CMD_START));
+}
+
+
+static error_t efm32_bitbang_cancel_rx(struct efm32_bitbang_ctx_s *pv)
+{
+  struct dev_dma_rq_s *drq = &pv->dma_rq;
+
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CMD_ADDR, endian_le32(EFM32_TIMER_CMD_STOP));
+
+  uint32_t x = cpu_mem_read_32(pv->addr + EFM32_TIMER_IF_ADDR);
+  x &= cpu_mem_read_32(pv->addr + EFM32_TIMER_IEN_ADDR);
+
+  if (x & EFM32_TIMER_IEN_OF)
+  /* Timer irq is pending */
+    return -EBUSY;
+
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_IEN_ADDR, 0);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_IF_ADDR, 0);
+  /* Turn off CC and stop timer */
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CC_CTRL_ADDR(0), 0);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CTRL_ADDR, 0);
+
+  /* Cancel dma request */ 
+  return DEVICE_OP(&pv->dma, cancel, drq);
+}
+
+static DEV_BITBANG_CANCEL(efm32_bitbang_cancel)
+{
+  struct device_s * dev = accessor->dev;
+  struct efm32_bitbang_ctx_s * pv  = dev->drv_pv;
+
+  error_t err = -EBUSY;
+
+  assert(rq);
+
+  LOCK_SPIN_IRQ(&dev->lock);
+
+  struct dev_bitbang_rq_s *hrq = dev_bitbang_rq_s_cast(dev_request_queue_head(&pv->queue));
+
+  if (rq == hrq)
+    {
+      switch(rq->type)
+        {
+          case DEV_BITBANG_RD:
+            if (pv->pending)
+              break;
+            err = efm32_bitbang_cancel_rx(pv);
+            if (err)
+              break;
+            rq->base.drvdata = NULL;
+            dev_request_queue_pop(&pv->queue);
+            bitbang_process_next(pv);
+            break; 
+          case DEV_BITBANG_WR:
+            break; 
+          default:
+            break;
+        }
+    }
+  else if (rq->base.drvdata == pv)
+  /* Request is in queue and is not being processed */
+    {
+      err = 0;
+      rq->base.drvdata = NULL;
+      dev_request_queue_remove(&pv->queue, dev_bitbang_rq_s_base(rq));
+    }
+
+  LOCK_RELEASE_IRQ(&dev->lock);
+
+  return err;
+}
+
+
+static DEV_BITBANG_REQUEST(efm32_bitbang_request)
+{
+  struct device_s * dev = accessor->dev;
+  struct efm32_bitbang_ctx_s *pv  = dev->drv_pv;
+
+  LOCK_SPIN_IRQ(&dev->lock);
+
+  bool_t empty = dev_request_queue_isempty(&pv->queue);
+  dev_request_queue_pushback(&pv->queue, dev_bitbang_rq_s_base(rq));
+  rq->base.drvdata = pv;
+
+  if (empty && !pv->pending)
+    bitbang_process_next(pv);
+
+  LOCK_RELEASE_IRQ(&dev->lock);
+}
+
+static DEV_IRQ_SRC_PROCESS(efm32_bitbang_irq_process)
+{
+  struct device_s *dev = ep->base.dev;
+  struct efm32_bitbang_ctx_s *pv = dev->drv_pv;
+
+  lock_spin(&dev->lock);
+
+  struct dev_dma_rq_s *drq = &pv->dma_rq;
+
+  /* Turn off CC and stop timer */
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CC_CTRL_ADDR(0), 0);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CTRL_ADDR, 0);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CMD_ADDR, endian_le32(EFM32_TIMER_CMD_STOP));
+
+  /* Clean irq */
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_IFC_ADDR, EFM32_TIMER_IFC_MASK);
+
+  pv->pending = 1;
+
+  /* Cancel dma request */ 
+  error_t err = DEVICE_OP(&pv->dma, cancel, drq);
+
+  if (err == -EBUSY)
+  /* DMA irq handler will be called sooner */
+    goto end;
+  
+  if (pv->dma_rq.cancel.size)
+    efm32_bitbang_end_rd_rq(pv, 0, pv->dma_rq.cancel.size - 1);
+  else
+    efm32_bitbang_end_rd_rq(pv, 0, pv->dma_rq.cancel.size);
+
+  /* Request is terminated here */
+  bitbang_process_next(pv);
+
+end:
+  lock_release(&dev->lock);
+}
+
+#ifdef CONFIG_DEVICE_CLOCK_VARFREQ
+static void efm32_bitbang_clk_changed(struct device_s *dev)
+{
+  struct efm32_bitbang_ctx_s *pv = dev->drv_pv;
+
+  efm32_bitbang_freq(pv);
+
+}
+#endif
+
+static DEV_INIT(efm32_bitbang_init)
+{
+  struct efm32_bitbang_ctx_s  *pv;
+
+  pv = mem_alloc(sizeof(struct efm32_bitbang_ctx_s), (mem_scope_sys));
+
+  if (!pv)
+    return -ENOMEM;
+
+  memset(pv, 0, sizeof(*pv));
+  dev->drv_pv = pv;
+
+  pv->dev = dev;
+  
+  dev_request_queue_init(&pv->queue);
+
+  /* Init GPIO stuff */
+
+  iomux_demux_t loc;
+
+  if (device_iomux_setup(dev, "<io", &loc, &pv->id, NULL))
+    goto err_mem;
+
+  if (device_get_param_dev_accessor(dev, "iomux", &pv->iomux.base, DRIVER_CLASS_IOMUX))
+    goto err_mem;
+
+  enum dev_clock_ep_flags_e flags = DEV_CLOCK_EP_FREQ_NOTIFY |
+                                    DEV_CLOCK_EP_POWER_CLOCK |
+                                    DEV_CLOCK_EP_GATING_SYNC;
+
+  if (dev_drv_clock_init(dev, &pv->clk_ep, 0, flags, &pv->freq))
+    goto err_mem;
+
+  kroutine_init_deferred(&pv->kr, efm32_bitbang_process_next_kr);
+
+  /* Timer initialisation */
+
+  if (device_res_get_uint(dev, DEV_RES_MEM, 0, &pv->addr, NULL))
+    goto err_clk;
+
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CMD_ADDR, endian_le32(EFM32_TIMER_CMD_STOP));
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_IEN_ADDR, 0);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_IF_ADDR, 0);
+ 
+  pv->div = EFM32_TIMER_CTRL_PRESC_DIV8;
+
+  uint32_t x;
+ 
+#if (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG1) || \
+    (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12)
+ /* Enable Channel output on pin */
+  x = EFM32_TIMER_ROUTEPEN_CCPEN(0);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_ROUTEPEN_ADDR, endian_le32(x));
+ 
+  x = EFM32_TIMER_ROUTELOC0_CCLOC(0, loc);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_ROUTELOC0_ADDR, endian_le32(x));
+#elif CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFM
+ /* Enable Channel output on pin */
+  x = EFM32_TIMER_ROUTE_CCPEN(0);
+  EFM32_TIMER_ROUTE_LOCATION_SETVAL(x, loc);
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_ROUTE_ADDR, endian_le32(x));
+#else
+# error
+#endif
+
+#if defined(CONFIG_DRIVER_EFM32_DMA) || defined(CONFIG_DRIVER_EFR32_DMA)
+
+  pv->dvalue = 0xFFFF;
+
+  uint32_t dma_tx_mask, dma_rx_mask;
+  uint32_t dma_tx_link, dma_rx_link;
+
+  if (device_res_get_dma(dev, 0, &dma_tx_mask, &dma_tx_link) ||
+      device_res_get_dma(dev, 1, &dma_rx_mask, &dma_rx_link) ||
+      device_get_param_dev_accessor(dev, "dma", &pv->dma.base, DRIVER_CLASS_DMA))
+    goto err_clk;
+
+  if (dma_tx_mask != dma_rx_mask)
+    goto err_clk;
+
+  pv->dma_rx_link = dma_rx_link;
+  pv->dma_tx_link = dma_tx_link;
+
+  struct dev_dma_rq_s *rq = &pv->dma_rq;
+  
+  rq->loop_count_m1 = 0;
+  rq->chan_mask = dma_tx_mask;
+  rq->cache_ptr = NULL;
+#else
+  goto err_clk;
+#endif
+
+  device_irq_source_init(dev, &pv->irq_ep, 1, &efm32_bitbang_irq_process);
+
+  if (device_irq_source_link(dev, &pv->irq_ep, 1, -1))
+    goto err_clk;
+
+  return 0;
+
+ err_clk:
+#ifdef CONFIG_DEVICE_CLOCK
+  dev_drv_clock_cleanup(dev, &pv->clk_ep);
+#endif
+ err_mem:
+  mem_free(pv);
+  return -1;
+}
+
+static DEV_CLEANUP(efm32_bitbang_cleanup)
+{
+  struct efm32_bitbang_ctx_s *pv = dev->drv_pv;
+
+  device_put_accessor(&pv->iomux.base);
+  device_put_accessor(&pv->dma.base);
+
+  device_irq_source_unlink(dev, &pv->irq_ep, 1);
+
+  cpu_mem_write_32(pv->addr + EFM32_TIMER_CMD_ADDR, endian_le32(EFM32_TIMER_CMD_STOP));
+
+#ifdef CONFIG_DEVICE_CLOCK
+  dev_drv_clock_cleanup(dev, &pv->clk_ep);
+#endif
+
+  mem_free(pv);
+
+  return 0;
+}
+
+static DEV_USE(efm32_bitbang_use)
+{
+    switch (op)
+      {
+#ifdef CONFIG_DEVICE_CLOCK_VARFREQ
+      case DEV_USE_CLOCK_SINK_FREQ_CHANGED: {
+        struct dev_clock_notify_s *chg = param;
+        struct dev_clock_sink_ep_s *sink = chg->sink;
+        struct device_s *dev = sink->dev;
+        struct efm32_bitbang_ctx_s *pv = dev->drv_pv;
+        pv->freq = chg->freq;
+        efm32_bitbang_clk_changed(dev);
+        return 0;
+    }
+#endif
+      default:
+        return dev_use_generic(param, op);
+      }
+}
+
+DRIVER_DECLARE(efm32_bitbang_drv, 0, "EFM32 bitbang", efm32_bitbang,
+               DRIVER_BITBANG_METHODS(efm32_bitbang));
+
+DRIVER_REGISTER(efm32_bitbang_drv);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/bitbang/bitbang.config	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,8 @@
+
+%config CONFIG_DRIVER_EFM32_BITBANG
+  desc Enable EFM32 BITBANG
+  parent CONFIG_ARCH_EFM32
+  depend CONFIG_DEVICE_GPIO
+  require CONFIG_EFM32_ARCHREV=EFM32_ARCHREV_EFM
+%config end
+
--- a/arch/efm32/drivers/i2c/Makefile	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/i2c/Makefile	Tue Apr 17 16:02:59 2018 +0200
@@ -1,2 +1,3 @@
-objs = i2c.o
+objs-$(CONFIG_DRIVER_EFM32_I2C) = i2c.o
+objs-$(CONFIG_DRIVER_EFM32_I2C_SLAVE) = i2c_slave.o
 
--- a/arch/efm32/drivers/i2c/i2c.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/i2c/i2c.c	Tue Apr 17 16:02:59 2018 +0200
@@ -448,9 +448,34 @@
   if (device_iomux_setup(dev, ",scl ,sda", loc, NULL, NULL))
     goto err_queue;
 
+#if (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG1) ||\
+    (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12)
+  uint32_t enable = 0;
+  uint32_t route = 0;
+
+  if (loc[0] != IOMUX_INVALID_DEMUX)
+    {
+      enable |= EFM32_I2C_ROUTEPEN_SCLPEN;
+      EFM32_I2C_ROUTELOC0_SCLLOC_SET(route, loc[0]);
+    }
+  if (loc[1] != IOMUX_INVALID_DEMUX)
+    {
+      enable |= EFM32_I2C_ROUTEPEN_SDAPEN;
+      EFM32_I2C_ROUTELOC0_SDALOC_SET(route, loc[1]);
+    }
+
+  if (enable == 0)
+    goto err_queue;
+
+  cpu_mem_write_32(pv->addr + EFM32_I2C_ROUTELOC0_ADDR, endian_le32(route));
+  cpu_mem_write_32(pv->addr + EFM32_I2C_ROUTEPEN_ADDR, endian_le32(enable));
+#elif CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFM
   uint32_t route = EFM32_I2C_ROUTE_SCLPEN | EFM32_I2C_ROUTE_SDAPEN;
   EFM32_I2C_ROUTE_LOCATION_SETVAL(route, loc[0]);
   cpu_mem_write_32(pv->addr + EFM32_I2C_ROUTE_ADDR, endian_le32(route));
+#else
+# error
+#endif
 
   device_irq_source_init(dev, &pv->irq_ep, 1, &efm32_i2c_irq);
   if (device_irq_source_link(dev, &pv->irq_ep, 1, -1))
@@ -522,6 +547,7 @@
   dev_drv_clock_cleanup(dev, &pv->clk_ep);
 #endif
 
+  device_iomux_cleanup(dev);
   mem_free(pv);
   return 0;
 }
--- a/arch/efm32/drivers/i2c/i2c.config	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/i2c/i2c.config	Tue Apr 17 16:02:59 2018 +0200
@@ -4,6 +4,12 @@
   parent CONFIG_ARCH_EFM32
   depend CONFIG_DEVICE_I2C
   depend CONFIG_DEVICE_IRQ
-  require CONFIG_EFM32_ARCHREV=EFM32_ARCHREV_EFM
 %config end
 
+%config CONFIG_DRIVER_EFM32_I2C_SLAVE
+  desc Enable EFM32 Slave I2C driver
+  parent CONFIG_ARCH_EFM32
+  depend CONFIG_DEVICE_I2C_SLAVE
+  depend CONFIG_DEVICE_IRQ
+%config end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/i2c/i2c_slave.c	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,660 @@
+/*
+    This file is part of MutekH.
+
+    MutekH is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation; version 2.1 of the
+    License.
+
+    MutekH is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this program.  If not, see
+    <http://www.gnu.org/licenses/>.
+
+    Copyright Sebastien Cerdan <sebcerdan@gmail.com> (c) 2014
+    Copyright Vincent DEFILIPPI <vincentdefilippi@gmail.com> (c) 2016
+    Copyright Nicolas Pouillon <nipo@ssji.net> (c) 2018
+*/
+
+#define LOGK_MODULE_ID "i2cs"
+
+#include <hexo/types.h>
+#include <hexo/endian.h>
+#include <hexo/iospace.h>
+#include <hexo/error.h>
+#include <hexo/interrupt.h>
+
+#include <mutek/mem_alloc.h>
+#include <mutek/printk.h>
+
+#include <device/resources.h>
+#include <device/device.h>
+#include <device/request.h>
+#include <device/driver.h>
+#include <device/irq.h>
+#include <device/class/i2c_slave.h>
+#include <device/class/iomux.h>
+#include <device/clock.h>
+
+#include <arch/efm32/i2c.h>
+
+#define IDLE_IRQ_MASK (0                        \
+                       | EFM32_I2C_IF_RXDATAV   \
+                       | EFM32_I2C_IF_ADDRA     \
+                       )
+
+#define TX_IRQ_MASK (0                          \
+                     | EFM32_I2C_IF_RSTART      \
+                     | EFM32_I2C_IF_SSTOP       \
+                     | EFM32_I2C_IF_ACK         \
+                     | EFM32_I2C_IF_NACK        \
+                     | EFM32_I2C_IF_ARBLOST     \
+                     )
+
+#define RX_IRQ_MASK (0                          \
+                     | EFM32_I2C_IF_RXDATAV     \
+                     | EFM32_I2C_IF_RSTART      \
+                     | EFM32_I2C_IF_SSTOP       \
+                     | EFM32_I2C_IF_ARBLOST     \
+                     )
+
+enum efm32_i2c_slave_state_e
+{
+  STATE_IDLE,
+  STATE_TRANSMITTING,
+  STATE_TRANSMITTING_UNDERFLOW,
+  STATE_RECEIVING,
+  STATE_RECEIVING_WAITING,
+  STATE_RECEIVING_BLOCKED,
+};
+
+struct efm32_i2c_slave_pv_s
+{
+  uintptr_t addr;
+  enum efm32_i2c_slave_state_e state;
+#ifdef CONFIG_DEVICE_CLOCK
+  struct dev_clock_sink_ep_s clk_ep;
+#endif
+  struct dev_irq_src_s irq_ep;
+  dev_request_queue_root_t queue;
+  struct dev_i2c_slave_rq_s *addr_sel;
+};
+
+DRIVER_PV(struct efm32_i2c_slave_pv_s);
+
+static
+void efm32_i2c_slave_saddr_setup(driver_pv_t *pv)
+{
+  uint8_t addr = 0x00;
+  uint8_t mask = 0x7f;
+
+  if (pv->addr_sel)
+    {
+      addr = pv->addr_sel->selection.saddr;
+      mask = pv->addr_sel->selection.saddr_mask;
+    }
+
+  logk_debug("%s addr: %02x mask: %02x", __func__, addr, mask);
+  
+  cpu_mem_write_32(pv->addr + EFM32_I2C_SADDR_ADDR,
+                   endian_le32(EFM32_I2C_SADDR_VAL_SHIFT_VAL(addr)));
+  cpu_mem_write_32(pv->addr + EFM32_I2C_SADDRMASK_ADDR,
+                   endian_le32(EFM32_I2C_SADDRMASK_VAL_SHIFT_VAL(mask)));
+}
+
+static
+void efm32_i2c_slave_data_queue_cancel(driver_pv_t *pv)
+{
+  for (;;)
+    {
+      struct dev_i2c_slave_rq_s *rq
+        = dev_i2c_slave_rq_s_cast(dev_request_queue_pop(&pv->queue));
+
+      logk_debug("%s %p", __func__, rq);
+
+      if (!rq)
+        break;
+
+      rq->error = -ECANCELED;
+      kroutine_exec(&rq->base.kr);
+    }
+}
+
+static
+void efm32_i2c_slave_rq_end(driver_pv_t *pv,
+                            struct dev_i2c_slave_rq_s *rq,
+                            error_t err)
+{
+  rq->error = err;
+  dev_request_queue_remove(&pv->queue, &rq->base);
+  kroutine_exec(&rq->base.kr);
+}
+
+static
+void efm32_i2c_slave_idle_setup(driver_pv_t *pv)
+{
+  logk_debug("%s", __func__);
+
+  pv->state = STATE_IDLE;
+  cpu_mem_write_32(pv->addr + EFM32_I2C_IEN_ADDR, endian_le32(IDLE_IRQ_MASK));
+
+  efm32_i2c_slave_saddr_setup(pv);
+}
+
+static
+void efm32_i2c_slave_tx_setup(driver_pv_t *pv)
+{
+  logk_debug("%s", __func__);
+
+  pv->state = STATE_TRANSMITTING_UNDERFLOW;
+  cpu_mem_write_32(pv->addr + EFM32_I2C_IEN_ADDR, endian_le32(TX_IRQ_MASK));
+}
+
+static
+void efm32_i2c_slave_rx_setup(driver_pv_t *pv)
+{
+  logk_debug("%s", __func__);
+
+  pv->state = STATE_RECEIVING_BLOCKED;
+  cpu_mem_write_32(pv->addr + EFM32_I2C_IEN_ADDR, endian_le32(RX_IRQ_MASK));
+}
+
+  static
+void efm32_i2c_slave_rx_byte(driver_pv_t *pv, struct dev_i2c_slave_rq_s *rq)
+{
+  uint8_t data = endian_le32(cpu_mem_read_32(pv->addr + EFM32_I2C_RXDATA_ADDR));
+
+  *rq->transfer.data = data;
+  rq->transfer.data++;
+  rq->transfer.size--;
+
+  logk_debug("%s %02x, %d bytes to go, %s at end", __func__,
+             data, rq->transfer.size, rq->transfer.end_ack ? "ACK" : "NACK");
+
+  if (rq->transfer.size)
+    {
+      cpu_mem_write_32(pv->addr + EFM32_I2C_CMD_ADDR,
+                       endian_le32(EFM32_I2C_CMD_ACK));
+    }
+  else if (!rq->transfer.end_ack)
+    {
+      cpu_mem_write_32(pv->addr + EFM32_I2C_CMD_ADDR,
+                       endian_le32(EFM32_I2C_CMD_NACK));
+
+      efm32_i2c_slave_rq_end(pv, rq, 0);
+      efm32_i2c_slave_data_queue_cancel(pv);
+      efm32_i2c_slave_idle_setup(pv);
+    }
+  else
+    {
+      efm32_i2c_slave_rq_end(pv, rq, 0);
+
+      rq = dev_i2c_slave_rq_s_cast(dev_request_queue_head(&pv->queue));
+
+      if (rq)
+          cpu_mem_write_32(pv->addr + EFM32_I2C_CMD_ADDR,
+                           endian_le32(EFM32_I2C_CMD_ACK));
+      else
+        pv->state = STATE_RECEIVING_BLOCKED;
+    }
+}
+
+static
+void efm32_i2c_slave_tx_byte(driver_pv_t *pv, struct dev_i2c_slave_rq_s *rq)
+{
+  uint8_t data = *rq->transfer.data;
+
+  assert(rq->transfer.size);
+
+  logk_debug("%s %02x", __func__, data);
+  
+  cpu_mem_write_32(pv->addr + EFM32_I2C_TXDATA_ADDR, endian_le32(data));
+  rq->transfer.data++;
+  rq->transfer.size--;
+}
+
+static
+DEV_IRQ_SRC_PROCESS(efm32_i2c_slave_irq)
+{
+  struct device_s *dev = ep->base.dev;
+  DEVICE_PV(pv, dev);
+
+  LOCK_SPIN_SCOPED(&dev->lock);
+
+  while (dev->start_count)
+    {
+      uint32_t rirq = endian_le32(cpu_mem_read_32(pv->addr + EFM32_I2C_IF_ADDR));
+      uint32_t mask = endian_le32(cpu_mem_read_32(pv->addr + EFM32_I2C_IEN_ADDR));
+      uint32_t irq = rirq & mask;
+
+      logk_debug("%s state %d irq %04x mask %04x left %04x", __func__, pv->state,
+                 rirq, mask, irq);
+
+      /* Reset interrupts flags */
+      cpu_mem_write_32(pv->addr + EFM32_I2C_IFC_ADDR, endian_le32(rirq));
+
+      if (!irq)
+        return;
+
+      /* End of data phase conditions */
+      if (irq & (EFM32_I2C_IF_RSTART | EFM32_I2C_IF_SSTOP | EFM32_I2C_IF_ARBLOST))
+        {
+          logk_debug(" terminated");
+
+          if (pv->state != STATE_IDLE) {
+            efm32_i2c_slave_data_queue_cancel(pv);
+            efm32_i2c_slave_idle_setup(pv);
+          }
+
+          if (!pv->addr_sel)
+            dev->start_count &= ~1;
+        }
+  
+      /* Slave address selection */
+      if (irq & EFM32_I2C_IF_ADDRA)
+        {
+          logk_debug(" addra");
+
+          assert(irq & EFM32_I2C_IF_RXDATAV);
+          assert(pv->state == STATE_IDLE);
+
+          struct dev_i2c_slave_rq_s *s = pv->addr_sel;
+          uint8_t data = endian_le32(cpu_mem_read_32(pv->addr + EFM32_I2C_RXDATA_ADDR));
+          uint8_t addr = data >> 1;
+          uint8_t read = data & 1;
+          
+          if (!s || ((s->selection.saddr ^ addr) & s->selection.saddr_mask))
+            {
+              cpu_mem_write_32(pv->addr + EFM32_I2C_CMD_ADDR,
+                               endian_le32(EFM32_I2C_CMD_NACK));
+            }
+          else
+            {
+              pv->addr_sel = NULL;
+              s->selection.saddr = addr;
+              s->selection.read = read;
+              s->error = 0;
+
+              kroutine_exec(&s->base.kr);
+
+              if (read)
+                {
+                  efm32_i2c_slave_tx_setup(pv);
+
+                  cpu_mem_write_32(pv->addr + EFM32_I2C_CMD_ADDR,
+                                   endian_le32(EFM32_I2C_CMD_ACK));
+                }
+              else
+                {
+                  efm32_i2c_slave_rx_setup(pv);
+                }
+            }
+
+          /* We do not want more data to be popped by rx path */
+          irq &= ~EFM32_I2C_IF_RXDATAV;
+        }
+
+      /* Data receive path */
+      if (irq & EFM32_I2C_IF_RXDATAV)
+        {
+          logk_debug(" rxdatav");
+
+          assert(pv->state == STATE_RECEIVING);
+
+          struct dev_i2c_slave_rq_s *rq
+            = dev_i2c_slave_rq_s_cast(dev_request_queue_head(&pv->queue));
+
+          if (rq)
+            efm32_i2c_slave_rx_byte(pv, rq);
+          else
+            pv->state = STATE_RECEIVING_WAITING;
+        }
+
+      /* Data transmit path, acked */
+      if (irq & EFM32_I2C_IF_ACK)
+        {
+          logk_debug(" ack");
+
+          assert(pv->state == STATE_TRANSMITTING);
+
+          struct dev_i2c_slave_rq_s *rq
+            = dev_i2c_slave_rq_s_cast(dev_request_queue_head(&pv->queue));
+
+          assert(rq);
+          
+          if (rq->transfer.size)
+            {
+              efm32_i2c_slave_tx_byte(pv, rq);
+            }
+          else
+            {
+              rq->transfer.end_ack = 1;
+              efm32_i2c_slave_rq_end(pv, rq, 0);
+
+              rq = dev_i2c_slave_rq_s_cast(dev_request_queue_head(&pv->queue));
+              if (rq)
+                efm32_i2c_slave_tx_byte(pv, rq);
+              else
+                pv->state = STATE_TRANSMITTING_UNDERFLOW;
+            }
+        }
+
+      /* Data transmit path, nacked */
+      if (irq & EFM32_I2C_IF_NACK)
+        {
+          logk_debug(" nack");
+
+          if (pv->state == STATE_TRANSMITTING)
+            {
+              struct dev_i2c_slave_rq_s *rq
+                = dev_i2c_slave_rq_s_cast(dev_request_queue_head(&pv->queue));
+
+              if (rq)
+                {
+                  rq->transfer.end_ack = 0;
+                  efm32_i2c_slave_rq_end(pv, rq, 0);
+                }
+              efm32_i2c_slave_data_queue_cancel(pv);
+              efm32_i2c_slave_idle_setup(pv);
+            }
+        }
+    }
+ 
+#ifdef CONFIG_DEVICE_CLOCK_GATING
+  dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER);
+#endif
+}
+
+static
+DEV_I2C_SLAVE_REQUEST(efm32_i2c_slave_request)
+{
+  struct device_s *dev = accessor->dev;
+  DEVICE_PV(pv, dev);
+
+  LOCK_SPIN_IRQ_SCOPED(&dev->lock);
+
+  logk_debug("%s state %d rq type %d", __func__, pv->state, rq->type);
+
+  switch (rq->type)
+    {
+    case DEV_I2C_SLAVE_SELECTION:
+      logk_debug(" slave select");
+
+      if (pv->addr_sel)
+        {
+          logk_debug(" busy");
+          rq->error = -ENOTSUP;
+          kroutine_exec(&rq->base.kr);
+          return;
+        }
+
+      pv->addr_sel = rq;
+
+      if (pv->state == STATE_IDLE)
+        {
+          logk_debug(" idle");
+          efm32_i2c_slave_data_queue_cancel(pv);
+          efm32_i2c_slave_idle_setup(pv);
+        }
+
+      dev->start_count |= 1;
+
+#ifdef CONFIG_DEVICE_CLOCK_GATING
+      dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER_CLOCK);
+#endif
+      break;
+
+    case DEV_I2C_SLAVE_TRANSMIT:
+      logk_debug(" transmit");
+
+      switch (pv->state)
+        {
+        case STATE_TRANSMITTING_UNDERFLOW:
+          logk_debug(" unlock underflow");
+          pv->state = STATE_TRANSMITTING;
+          efm32_i2c_slave_tx_byte(pv, rq);
+          /* fallthrough */
+
+        case STATE_TRANSMITTING:
+          dev_request_queue_pushback(&pv->queue, &rq->base);
+          break;
+
+        default:
+          logk_debug(" bad sequencing");
+          rq->error = -EINVAL;
+          kroutine_exec(&rq->base.kr);
+          return;
+        }
+      break;
+
+    case DEV_I2C_SLAVE_RECEIVE:
+      switch (pv->state)
+        {
+        case STATE_RECEIVING_BLOCKED:
+          logk_debug(" unlock blocked");
+          pv->state = STATE_RECEIVING;
+          dev_request_queue_pushback(&pv->queue, &rq->base);
+          cpu_mem_write_32(pv->addr + EFM32_I2C_CMD_ADDR,
+                           endian_le32(EFM32_I2C_CMD_ACK));
+          break;
+
+        case STATE_RECEIVING:
+          dev_request_queue_pushback(&pv->queue, &rq->base);
+          break;
+
+        case STATE_RECEIVING_WAITING:
+          logk_debug(" unlock waiting");
+          pv->state = STATE_RECEIVING;
+          dev_request_queue_pushback(&pv->queue, &rq->base);
+          efm32_i2c_slave_rx_byte(pv, rq);
+          break;
+
+        default:
+          logk_debug(" bad sequencing");
+          rq->error = -EINVAL;
+          kroutine_exec(&rq->base.kr);
+          return;
+        }
+      break;
+
+    default:
+      logk_debug(" wtf ?");
+      rq->error = -ENOTSUP;
+      kroutine_exec(&rq->base.kr);
+      return;
+    }
+}
+
+static DEV_USE(efm32_i2c_slave_use)
+{
+  switch (op)
+    {
+#ifdef CONFIG_DEVICE_CLOCK_VARFREQ
+    case DEV_USE_CLOCK_SINK_FREQ_CHANGED: {
+      struct dev_clock_notify_s *chg = param;
+      struct dev_clock_sink_ep_s *sink = chg->sink;
+      struct device_s *dev = sink->dev;
+      DEVICE_PV(pv, dev);
+# ifdef CONFIG_DEVICE_CLOCK_GATING
+      dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER_CLOCK);
+# endif
+# ifdef CONFIG_DEVICE_CLOCK_GATING
+      if (dev->start_count == 0)
+        dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER);
+# endif
+      return 0;
+    }
+#endif
+
+#ifdef CONFIG_DEVICE_CLOCK_GATING
+    case DEV_USE_START: {
+      struct device_accessor_s *acc = param;
+      struct device_s *dev = acc->dev;
+      DEVICE_PV(pv, dev);
+      if (dev->start_count == 0)
+        dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER_CLOCK);
+      return 0;
+    }
+
+    case DEV_USE_STOP: {
+      struct device_accessor_s *acc = param;
+      struct device_s *dev = acc->dev;
+      DEVICE_PV(pv, dev);
+      if (dev->start_count == 0)
+        dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER);
+      return 0;
+    }
+#endif
+
+    default:
+      return dev_use_generic(param, op);
+    }
+}
+
+static
+DEV_INIT(efm32_i2c_slave_init)
+{
+  struct efm32_i2c_slave_pv_s *pv;
+
+  /* allocate driver private context. */
+  pv = mem_alloc(sizeof(*pv), (mem_scope_sys));
+  if (!pv)
+    return -ENOMEM;
+
+  memset(pv, 0, sizeof(*pv));
+
+  dev->drv_pv = pv;
+
+  struct dev_freq_s freq;
+#ifdef CONFIG_DEVICE_CLOCK
+  /* enable clock */
+  if (dev_drv_clock_init(dev, &pv->clk_ep, 0, DEV_CLOCK_EP_FREQ_NOTIFY |
+                         DEV_CLOCK_EP_POWER_CLOCK | DEV_CLOCK_EP_GATING_SYNC, &freq))
+    goto err_mem;
+#else
+  if (device_get_res_freq(dev, &freq, 0))
+    goto err_mem;
+#endif
+
+  /* retreive the device base address from device tree. */
+  if(device_res_get_uint(dev, DEV_RES_MEM, 0, &pv->addr, NULL))
+    goto err_clk;
+
+  /* Reset Device by disabling controller (bus idle timeout has not effect). */
+  cpu_mem_write_32(pv->addr + EFM32_I2C_CTRL_ADDR, 0);
+
+  /* Send ABORT command as specified in reference manual*/
+  uint32_t cmd = EFM32_I2C_CMD_ABORT |
+    EFM32_I2C_CMD_CLEARTX |
+    EFM32_I2C_CMD_CLEARPC;
+
+  cpu_mem_write_32(pv->addr + EFM32_I2C_CMD_ADDR, endian_le32(cmd));
+
+  /* Disable and clear interrupts */
+  cpu_mem_write_32(pv->addr + EFM32_I2C_IEN_ADDR, 0);
+
+  /* setup pinmux */
+  iomux_demux_t loc[2];
+  if (device_iomux_setup(dev, ",scl ,sda", loc, NULL, NULL))
+    goto err_clk;
+
+#if (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG1) ||  \
+  (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12)
+  uint32_t enable = 0;
+  uint32_t route = 0;
+
+  if (loc[0] != IOMUX_INVALID_DEMUX)
+    {
+      enable |= EFM32_I2C_ROUTEPEN_SCLPEN;
+      EFM32_I2C_ROUTELOC0_SCLLOC_SET(route, loc[0]);
+    }
+  if (loc[1] != IOMUX_INVALID_DEMUX)
+    {
+      enable |= EFM32_I2C_ROUTEPEN_SDAPEN;
+      EFM32_I2C_ROUTELOC0_SDALOC_SET(route, loc[1]);
+    }
+
+  if (enable == 0)
+    goto err_clk;
+
+  cpu_mem_write_32(pv->addr + EFM32_I2C_ROUTELOC0_ADDR, endian_le32(route));
+  cpu_mem_write_32(pv->addr + EFM32_I2C_ROUTEPEN_ADDR, endian_le32(enable));
+#elif CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFM
+  uint32_t route = EFM32_I2C_ROUTE_SCLPEN | EFM32_I2C_ROUTE_SDAPEN;
+  EFM32_I2C_ROUTE_LOCATION_SETVAL(route, loc[0]);
+  cpu_mem_write_32(pv->addr + EFM32_I2C_ROUTE_ADDR, endian_le32(route));
+#else
+# error
+#endif
+
+  device_irq_source_init(dev, &pv->irq_ep, 1, &efm32_i2c_slave_irq);
+  if (device_irq_source_link(dev, &pv->irq_ep, 1, -1))
+    goto err_clk;
+
+  /* Enable controller */
+  uint32_t x = EFM32_I2C_CTRL_EN | EFM32_I2C_CTRL_SLAVE;
+  cpu_mem_write_32(pv->addr + EFM32_I2C_CTRL_ADDR, endian_le32(x));
+
+  /* Clear interrupts flags */
+  cpu_mem_write_32(pv->addr + EFM32_I2C_IFC_ADDR, endian_le32(-1));
+  cpu_mem_write_32(pv->addr + EFM32_I2C_IEN_ADDR, endian_le32(IDLE_IRQ_MASK));
+
+#ifdef CONFIG_DEVICE_CLOCK_GATING
+  dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER);
+#endif
+
+  dev_request_queue_init(&pv->queue);
+  pv->addr_sel = NULL;
+  
+  return 0;
+
+ err_link:
+  device_irq_source_unlink(dev, &pv->irq_ep, 1);
+
+ err_clk:
+#ifdef CONFIG_DEVICE_CLOCK
+  dev_drv_clock_cleanup(dev, &pv->clk_ep);
+#endif
+
+ err_mem:
+  mem_free(pv);
+  return -EINVAL;
+}
+
+static
+DEV_CLEANUP(efm32_i2c_slave_cleanup)
+{
+  DEVICE_PV(pv, dev);
+
+  if (pv->addr_sel || !dev_request_queue_isempty(&pv->queue))
+    return -EBUSY;
+
+  dev_request_queue_destroy(&pv->queue);
+
+#ifdef CONFIG_DEVICE_CLOCK_GATING
+  dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER_CLOCK);
+#endif
+
+  device_irq_source_unlink(dev, &pv->irq_ep, 1);
+
+  /* disable I2C device and interrupts. */
+  cpu_mem_write_32(pv->addr + EFM32_I2C_IEN_ADDR, 0);
+  cpu_mem_write_32(pv->addr + EFM32_I2C_CTRL_ADDR, 0);
+
+#ifdef CONFIG_DEVICE_CLOCK
+  dev_drv_clock_cleanup(dev, &pv->clk_ep);
+#endif
+
+  device_iomux_cleanup(dev);
+  mem_free(pv);
+  return 0;
+}
+
+DRIVER_DECLARE(efm32_i2c_slave_drv, 0, "EFM32 i2c slave", efm32_i2c_slave,
+               DRIVER_I2C_SLAVE_METHODS(efm32_i2c_slave));
+
+DRIVER_REGISTER(efm32_i2c_slave_drv);
--- a/arch/efm32/drivers/ldma/dma.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/ldma/dma.c	Tue Apr 17 16:02:59 2018 +0200
@@ -646,6 +646,9 @@
   uint32_t xfercnt = endian_le32(cpu_mem_read_32(pv->addr + EFR32_LDMA_CH_CTRL_ADDR(chan)));
   xfercnt = EFR32_LDMA_CH_CTRL_XFERCNT_GET(xfercnt);
 
+  rq->cancel.size = 0;
+  rq->cancel.desc_idx = 0;
+
   if (rq->loop_count_m1)
   /* 2D copy */
     return -ENOTSUP;
--- a/arch/efm32/drivers/leuart/leuart_char.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/leuart/leuart_char.c	Tue Apr 17 16:02:59 2018 +0200
@@ -42,6 +42,7 @@
 #include <device/irq.h>
 #include <device/class/char.h>
 #include <device/class/iomux.h>
+#include <device/class/uart.h>
 #include <device/clock.h>
 
 #if CONFIG_DRIVER_EFM32_LEUART_SWFIFO > 0
@@ -70,9 +71,7 @@
 #endif
   uint32_t                      mode;
 
-#ifdef CONFIG_DEVICE_CLOCK_VARFREQ
-  uint32_t                      bauds;
-#endif
+  struct dev_uart_config_s      cfg;
   struct dev_freq_s             freq;
 
   struct dev_clock_sink_ep_s    clk_ep;
@@ -87,10 +86,10 @@
   EFM32_LEUART_STARTED_WRITE = 2,
 };
 
-static uint32_t efm32_leuart_char_bauds(struct device_s *dev, uint32_t bauds)
+static uint32_t efm32_leuart_char_bauds(struct device_s *dev)
 {
   struct efm32_leuart_context_s *pv = dev->drv_pv;
-  return (256ULL * pv->freq.num) / (bauds * pv->freq.denom) - 256;
+  return (256ULL * pv->freq.num) / (pv->cfg.baudrate * pv->freq.denom) - 256;
 }
 
 static void efm32_leuart_try_read(struct device_s *dev)
@@ -346,7 +345,7 @@
       dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER_CLOCK);
 # endif
       efm32_leuart_write_reg(pv->addr, EFM32_LEUART_CLKDIV_ADDR,
-                       endian_le32(efm32_leuart_char_bauds(dev, pv->bauds)));
+                       endian_le32(efm32_leuart_char_bauds(dev)));
 # ifdef CONFIG_DEVICE_CLOCK_GATING
       if (dev->start_count == 0)
         dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER);
@@ -482,11 +481,11 @@
 #endif
 
   /* setup baud rate */
-#ifdef CONFIG_DEVICE_CLOCK_VARFREQ
-  pv->bauds = CONFIG_DRIVER_EFM32_LEUART_RATE;
-#endif
+  if (device_get_res_uart(dev, &pv->cfg))
+    pv->cfg.baudrate = CONFIG_DRIVER_EFM32_LEUART_RATE;
+
   efm32_leuart_write_reg(pv->addr, EFM32_LEUART_CLKDIV_ADDR,
-                         endian_le32(efm32_leuart_char_bauds(dev, CONFIG_DRIVER_EFM32_LEUART_RATE)));
+                         endian_le32(efm32_leuart_char_bauds(dev)));
 
   /* enable the uart */
   efm32_leuart_write_reg(pv->addr, EFM32_LEUART_CMD_ADDR,
@@ -542,6 +541,7 @@
   dev_request_queue_destroy(&pv->read_q);
   dev_request_queue_destroy(&pv->write_q);
 
+  device_iomux_cleanup(dev);
   mem_free(pv);
 
   return 0;
--- a/arch/efm32/drivers/msc/Makefile	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/msc/Makefile	Tue Apr 17 16:02:59 2018 +0200
@@ -1,3 +1,3 @@
 
-objs = msc.o flash.o
+objs = msc.o
 
--- a/arch/efm32/drivers/msc/flash.S	Wed Feb 07 15:11:17 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,205 +0,0 @@
-/*
-    This file is part of MutekH.
-    
-    MutekH is free software; you can redistribute it and/or modify it
-    under the terms of the GNU Lesser General Public License as
-    published by the Free Software Foundation; version 2.1 of the
-    License.
-    
-    MutekH is distributed in the hope that it will be useful, but
-    WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-    Lesser General Public License for more details.
-    
-    You should have received a copy of the GNU Lesser General Public
-    License along with MutekH; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-    02110-1301 USA.
-
-    Copyright Alexandre Becoulet <alexandre.becoulet@free.fr> (c) 2014
-*/
-
-#include <hexo/asm.h>
-#include <arch/efm32/msc.h>
-
-.syntax unified
-
-/*
-  This function erases a page of flash. The msc_addr parameter
-  must point to the Memory System Controller registers.
-
-  The size of the page is device dependent. The return value
-  contains the error bits of the MSC status register.
-*/
-#define EFM32_FLASH_ERASE_CODESIZE 0x14
-FUNC_START(.text, efm32_flash_erase)
-
-	push	{r4, r5, r6, r7, lr}
-
-	/* copy code to stack */
-	movs	r4,	#EFM32_FLASH_ERASE_CODESIZE
-	ldr	r5,	= 3f
-	sub	sp,	#EFM32_FLASH_ERASE_CODESIZE
-	mov	r7,	sp
-1:
-	subs	r4,	#4
-	ldr	r6,	[r5, r4]
-	str	r6,	[r7, r4]
-	bne	1b
-
-	/* disable irqs */
-	mrs	r6,	primask
-	cpsid	i
-
-	/* unlock and enable flash write feature */
-	ldr	r5,	= EFM32_MSC_LOCK_LOCKKEY_UNLOCK
-	str	r5,	[r0, #EFM32_MSC_LOCK_ADDR]
-
-	movs	r5,	#EFM32_MSC_WRITECTRL_WREN
-	str	r5,	[r0, #EFM32_MSC_WRITECTRL_ADDR]
-
-	/* barrier and jump to code on stack */
-	dsb
-	isb
-
-	adds	r7,	#1
-	blx	r7
-
-	/* lock access to flash write registers */
-	movs	r5,	#0
-	str	r5,	[r0, #EFM32_MSC_WRITECTRL_ADDR]
-	str	r5,	[r0, #EFM32_MSC_LOCK_ADDR]
-
-	/* return MSC status error bits */
-	ldr	r0,	[r0, #EFM32_MSC_STATUS_ADDR]
-	movs	r1,	#(EFM32_MSC_STATUS_LOCKED | EFM32_MSC_STATUS_INVADDR)
-	ands	r0,	r1
-
-	/* restore irqs and return */
-	msr	primask,	r6
-
-	add	sp, #EFM32_FLASH_ERASE_CODESIZE
-	pop	{r4, r5, r6, r7, pc}
-
-	.align	2
-3:
-	/* set address */
-	str	r1,	[r0, #EFM32_MSC_ADDRB_ADDR]
-	movs	r5,	#EFM32_MSC_WRITECMD_LADDRIM
-	str	r5,	[r0, #EFM32_MSC_WRITECMD_ADDR]
-
-	/* erase page */
-	movs	r5,	#EFM32_MSC_WRITECMD_ERASEPAGE
-	str	r5,	[r0, #EFM32_MSC_WRITECMD_ADDR]
-
-1:
-	/* wait for completion */
-	ldr	r5,	[r0, #EFM32_MSC_STATUS_ADDR]
-	lsrs	r5,	#(EFM32_MSC_STATUS_BUSY_SHIFT+1)
-	bcs	1b
-
-	bx	lr
-	.align	2
-
-FUNC_END(efm32_flash_erase)
-
-/*
-  This function writes data to a page of flash. The msc_addr
-  parameter must point to the Memory System Controller
-  registers. The write operation can not span across multiple pages.
-
-  The return value indicates if the new data in flash is different
-  from the passed data buffer.
-*/
-#define EFM32_FLASH_WRITE_CODESIZE 0x28
-FUNC_START(.text, efm32_flash_write)
-
-	push	{r4, r5, r6, r7, lr}
-
-	/* copy code to stack */
-	movs	r4,	#EFM32_FLASH_WRITE_CODESIZE
-	ldr	r5,	= 3f
-	sub	sp,	#EFM32_FLASH_WRITE_CODESIZE
-	mov	r7,	sp
-1:
-	subs	r4,	#4
-	ldr	r6,	[r5, r4]
-	str	r6,	[r7, r4]
-	bne	1b
-
-	/* disable irqs */
-	mrs	r6,	primask
-	cpsid	i
-
-	/* unlock and enable flash write feature */
-	ldr	r5,	= EFM32_MSC_LOCK_LOCKKEY_UNLOCK
-	str	r5,	[r0, #EFM32_MSC_LOCK_ADDR]
-
-	movs	r5,	#EFM32_MSC_WRITECTRL_WREN
-	str	r5,	[r0, #EFM32_MSC_WRITECTRL_ADDR]
-
-	/* barrier and jump to code on stack */
-	dsb
-	isb
-
-	adds	r7,	#1
-	blx	r7
-
-	/* lock access to flash write registers */
-	movs	r5,	#0
-	str	r5,	[r0, #EFM32_MSC_WRITECTRL_ADDR]
-	str	r5,	[r0, #EFM32_MSC_LOCK_ADDR]
-
-	/* return value */
-	movs	r0,	r7
-
-	/* restore irqs and return */
-	msr	primask,	r6
-
-	add	sp, #EFM32_FLASH_WRITE_CODESIZE
-	pop	{r4, r5, r6, r7, pc}
-
-	.align	2
-3:
-	movs	r7,	#0
-4:
-	/* set address */
-	str	r1,	[r0, #EFM32_MSC_ADDRB_ADDR]
-	movs	r5,	#EFM32_MSC_WRITECMD_LADDRIM
-	str	r5,	[r0, #EFM32_MSC_WRITECMD_ADDR]
-2:
-	/* set data */
-	ldr	r4,	[r2]
-	str	r4,	[r0, #EFM32_MSC_WDATA_ADDR]
-
-	/* write once */
-	movs	r5,	#EFM32_MSC_WRITECMD_WRITEONCE
-	str	r5,	[r0, #EFM32_MSC_WRITECMD_ADDR]
-
-1:
-	/* wait for completion */
-	ldr	r5,	[r0, #EFM32_MSC_STATUS_ADDR]
-	lsrs	r5,	#(EFM32_MSC_STATUS_BUSY_SHIFT+1)
-	bcs	1b
-
-	/* readback and diff */
-	ldr	r5,	[r1]
-	eors	r5,	r4
-	orrs	r7,	r5
-
-	/* repeat */
-	adds	r2,	#4
-	adds	r1,	#4
-	subs	r3,	#1
-#if CONFIG_EFM32_FAMILY == EFM32_FAMILY_GECKO
-	bne	4b
-#else
-	bne	2b
-#endif
-
-	bx	lr
-	.align	2
-
-FUNC_END(efm32_flash_write)
-
-
--- a/arch/efm32/drivers/msc/msc.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/msc/msc.c	Tue Apr 17 16:02:59 2018 +0200
@@ -23,34 +23,19 @@
 #include <hexo/types.h>
 #include <hexo/endian.h>
 #include <hexo/iospace.h>
+#include <hexo/flash.h>
 
 #include <mutek/mem_alloc.h>
 #include <arch/efm32/msc.h>
 
 #include <device/resources.h>
 #include <device/device.h>
-#include <device/irq.h>
 #include <device/class/mem.h>
 
-uint32_t efm32_flash_erase(uintptr_t msc_addr, uintptr_t flash_addr);
-
-uint32_t efm32_flash_write(uintptr_t msc_addr, uintptr_t flash_addr,
-                           const uint32_t *data, uint32_t words_count);
-
 DRIVER_PV(struct efm32_msc_context_s
 {
 });
 
-#if (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG1) ||\
-    (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12)
-#  define EFM32_MSC_ADDR 0x400e0000
-#elif CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFM
-#  define EFM32_MSC_ADDR 0x400c0000
-#else
-#  error
-#endif
-
-
 static DEV_MEM_INFO(efm32_msc_info)
 {
 #if 0
@@ -68,19 +53,20 @@
     case 0:                     /* RAM */
       info->type = DEV_MEM_RAM;
       info->size = cpu_mem_read_16(0x0fe081fa) << 10;
-      info->flags |= DEV_MEM_WRITABLE | DEV_MEM_VOLATILE |
+      info->flags |= DEV_MEM_VOLATILE |
         DEV_MEM_MAPPED_READ | DEV_MEM_MAPPED_WRITE |
         DEV_MEM_PARTIAL_WRITE | DEV_MEM_PARTIAL_READ |
-        DEV_MEM_CROSS_READ | DEV_MEM_CROSS_WRITE;
+        DEV_MEM_CROSS_READ | DEV_MEM_CROSS_WRITE |
+        DEV_MEM_PAGE_READ | DEV_MEM_PAGE_WRITE;
       info->map_base = 0x20000000;
       break;
     case 1:                     /* FLASH code */
     case 2:                     /* FLASH userdata */
       info->type = DEV_MEM_FLASH;
       info->partial_log2 = 2;
-      info->flags |= DEV_MEM_WRITABLE | DEV_MEM_ERASE_ONE |
+      info->flags |= DEV_MEM_ERASE_ONE |
         DEV_MEM_MAPPED_READ | DEV_MEM_PARTIAL_WRITE | DEV_MEM_PARTIAL_READ |
-        DEV_MEM_CROSS_READ;
+        DEV_MEM_CROSS_READ | DEV_MEM_PAGE_READ | DEV_MEM_PAGE_WRITE;
 #if (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFM)
       info->erase_cycles_p = 12; /* 20480 cycles */
 #else
@@ -103,7 +89,7 @@
           info->size = 1;
           info->map_base = 0x0fe00000;
         }
-      info->erase_log2 = EFM32_FLASH_PAGE_SIZE;
+      info->erase_log2 = info->page_log2;
       break;
     default:
       UNREACHABLE();
@@ -112,47 +98,6 @@
   return 0;
 }
 
-static uint32_t efm32_msc_flash_op(uintptr_t base, uint_fast8_t page_log2, struct dev_mem_rq_s *rq)
-{
-  uint32_t err = 0;
-
-  if (rq->type & (DEV_MEM_OP_PARTIAL_READ | DEV_MEM_OP_PAGE_READ))
-    dev_mem_mapped_op_helper(base, page_log2, rq);
-
-  if (rq->type & DEV_MEM_OP_PAGE_ERASE)
-    {
-      size_t i;
-      for (i = 0; !err && i < rq->size; i++)
-        {
-          CPU_INTERRUPT_SAVESTATE_DISABLE;
-          err |= efm32_flash_erase(EFM32_MSC_ADDR, base + rq->addr + (i << page_log2));
-          CPU_INTERRUPT_RESTORESTATE;
-        }
-    }
-
-  if (rq->type & DEV_MEM_OP_PAGE_WRITE)
-    {
-      size_t i;
-      for (i = 0; !err && i < rq->size; i++)
-        {
-          uintptr_t mask = (1 << rq->sc_log2) - 1;
-          CPU_INTERRUPT_SAVESTATE_DISABLE;
-          err |= efm32_flash_write(EFM32_MSC_ADDR, base + rq->addr + (i << page_log2),
-                   (void*)(rq->sc_data[i >> rq->sc_log2] + ((i & mask) << page_log2)),
-                   1 << (page_log2 - 2));
-          CPU_INTERRUPT_RESTORESTATE;
-        }
-    }
-  else if (rq->type & DEV_MEM_OP_PARTIAL_WRITE)
-    {
-      CPU_INTERRUPT_SAVESTATE_DISABLE;
-      err |= efm32_flash_write(EFM32_MSC_ADDR, base + rq->addr, (void*)rq->data, rq->size >> 2);
-      CPU_INTERRUPT_RESTORESTATE;
-    }
-
-  return err;
-}
-
 static DEV_MEM_REQUEST(efm32_msc_request)
 {
 #if 0
@@ -164,21 +109,18 @@
   switch (accessor->number)
     {
     case 0:                     /* RAM */
-      if (rq->type & (DEV_MEM_OP_PARTIAL_READ | DEV_MEM_OP_PARTIAL_WRITE |
-                      DEV_MEM_OP_PAGE_READ | DEV_MEM_OP_PAGE_WRITE))
-        dev_mem_mapped_op_helper(0x20000000, 0, rq);
+      rq->err = dev_mem_mapped_op_helper(0x20000000, 0x20000000 + CONFIG_EFM32_RAMSIZE, rq);
       break;
     case 1:                     /* FLASH code */
-      if (efm32_msc_flash_op(0x00000000, EFM32_FLASH_PAGE_SIZE, rq))
-        rq->err = -EIO;
+      rq->err = dev_mem_flash_op(0, CONFIG_EFM32_FLASHSIZE, EFM32_FLASH_PAGE_SIZE, rq);
       break;
     case 2:                     /* FLASH userdata */
 #if CONFIG_EFM32_FAMILY == EFM32_FAMILY_GIANT
-      if (efm32_msc_flash_op(0x0fe00000, 11, rq))
+      rq->err = dev_mem_flash_op(0x0fe00000, 0x0fe00000 + (1 << 11), 11, rq);
 #else
-      if (efm32_msc_flash_op(0x0fe00000, EFM32_FLASH_PAGE_SIZE, rq))
+      rq->err = dev_mem_flash_op(0x0fe00000, 0x0fe00000 + (1 << EFM32_FLASH_PAGE_SIZE),
+                                 EFM32_FLASH_PAGE_SIZE, rq);
 #endif
-        rq->err = -EIO;
       break;
     default:
       UNREACHABLE();
@@ -207,6 +149,9 @@
 
 static DEV_INIT(efm32_msc_init)
 {
+  if (((cpu_mem_read_8(0x0fe081e7) + 10) & 0xff) != EFM32_FLASH_PAGE_SIZE)
+    return -EINVAL;
+
 #if 0
   struct efm32_msc_context_s	*pv;
 
@@ -223,8 +168,6 @@
     return -1;
   assert(addr == EFM32_MSC_ADDR);
 
-  assert(((cpu_mem_read_8(0x0fe081e7) + 10) & 0xff) == EFM32_FLASH_PAGE_SIZE);
-
   return 0;
 
 #if 0
--- a/arch/efm32/drivers/pwm/pwm.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/pwm/pwm.c	Tue Apr 17 16:02:59 2018 +0200
@@ -143,6 +143,8 @@
     return -ERANGE; 
 
   uint32_t x = (pv->duty[channel].num * top) / pv->duty[channel].denom;
+  if (pv->duty[channel].num == pv->duty[channel].denom)
+    x = top + 1;
 
   cpu_mem_write_32(pv->addr + EFM32_TIMER_CC_CCV_ADDR(channel), endian_le32(x));
 
@@ -383,6 +385,7 @@
 
   dev_drv_clock_cleanup(dev, &pv->clk_ep);
 
+  device_iomux_cleanup(dev);
   mem_free(pv);
 
   return 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/radio/Makefile	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,14 @@
+
+objs = common.o protimer.o sequencer.o
+
+objs-$(CONFIG_DRIVER_EFR32_RFPACKET) += rfpacket.o
+objs-$(CONFIG_DRIVER_EFR32_BLE_ADVERTISE) += ble_advertise.o
+
+$(LOCAL_OBJ_DIR)/%.o: $(LOCAL_SRC_DIR)/%.seq $(OBJ_DIR)/config.h
+	@echo 'SEQ     $(notdir $@)'
+	$(CC) -E -x c $(CFLAGS) $(CPUCFLAGS) $(ARCHCFLAGS) $(INCS) -I $(LOCAL_SRC_DIR) $< -o $@.i
+	perl $(MUTEK_SRC_DIR)/scripts/decl_filter.pl --parse-decl $(CC) \
+                $(CFLAGS) $(CPUCFLAGS) $(ARCHCFLAGS) $(INCS) -I $(LOCAL_SRC_DIR) < $@.i > $@.ii
+	perl -I $(MUTEK_SRC_DIR)/arch/efm32 $(MUTEK_SRC_DIR)/arch/efm32/seq_asm.pl $@.ii -o $@.bin
+	perl $(MUTEK_SRC_DIR)/scripts/blob2c.pl $@.bin -n seqcode -S seqcode_size -D 4 > $@.c
+	$(CC) -x c -c $(CFLAGS) $(CPUCFLAGS) $(ARCHCFLAGS) $(INCS) $@.c -o $@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/radio/ble_advertise.c	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,899 @@
+/*
+   This file is part of MutekH.
+
+   MutekH is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; version 2.1 of the
+   License.
+
+   MutekH is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with MutekH; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.
+
+   Copyright (c) 2017 Sebastien Cerdan <sebcerdan@gmail.com>
+
+ */
+
+#include <ble/protocol/advertise.h>
+#include <ble/protocol/gap.h>
+#include <mutek/buffer_pool.h>
+
+#include "common.h"
+
+#define EFR32_RADIO_BUFFER_SIZE 4096
+
+enum efr32_radio_ble_state
+{
+  EFR32_RADIO_STATE_IDLE,
+  EFR32_RADIO_STATE_ADV,
+  EFR32_RADIO_STATE_SCAN_RQ,
+  EFR32_RADIO_STATE_SCAN_RSP,
+};
+
+DRIVER_PV(struct radio_efr32_ble_ctx_s
+{
+  struct radio_efr32_ctx_s      pv;
+
+  uint8_t                       chan_idx;
+  struct ble_addr_s             ble_addr;
+  struct buffer_s *             adv_packet;
+  struct buffer_s *             scan_rsp_packet;
+  struct buffer_s *             tx_buffer;
+  struct buffer_s *             ble_rx_buffer;
+  struct buffer_pool_s          pool;
+  enum efr32_radio_ble_state    state;
+});
+
+STRUCT_COMPOSE(radio_efr32_ble_ctx_s, pv);
+
+static inline void efr32_radio_fsm(struct radio_efr32_ble_ctx_s *pv);;
+static inline void efr32_radio_change_adv_channel(struct radio_efr32_ble_ctx_s *pv);
+static error_t efr32_radio_reset(struct radio_efr32_ble_ctx_s *ctx);
+
+static void efr32_radio_set_state(struct radio_efr32_ble_ctx_s *pv, enum efr32_radio_ble_state state)
+{
+  efr32_radio_printk("drv: st %d\n", state);
+  pv->state = state;
+}
+
+static KROUTINE_EXEC(efr32_radio_kr_op)
+{
+  struct radio_efr32_ctx_s *pv = radio_efr32_ctx_s_from_kr(kr);
+
+  /* Protimer init */
+  efr32_protimer_init(&pv->pti);
+  efr32_protimer_start_counter(&pv->pti);
+
+  dev_timer_value_t value = efr32_protimer_get_value(&pv->pti);
+  efr32_protimer_request_start(&pv->pti, value, value + 10000000, 0);
+}
+
+static void efr32_radio_start_rx(struct radio_efr32_ble_ctx_s *ctx)
+{
+  /* Clear buffer */
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(1), EFR32_BUFC_CMD_CLEAR); 
+
+  ctx->ble_rx_buffer = buffer_pool_alloc(&ctx->pool);
+
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_ADDR_ADDR(1), (uint32_t)ctx->ble_rx_buffer->data);
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_WRITEOFFSET_ADDR(1), 0);
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_READOFFSET_ADDR(1), buffer_size(ctx->ble_rx_buffer));
+
+  /* Check RAC state */
+  assert(EFR32_RAC_STATUS_STATE_GET(endian_le32(cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_STATUS_ADDR))) == EFR32_RAC_STATUS_STATE_OFF);
+  assert(ctx->ble_rx_buffer);
+
+  /* Enable RX */
+  uint32_t x = cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_RXENSRCEN_ADDR);
+  x |= 0x2;
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_RXENSRCEN_ADDR, x);
+}
+
+static void efr32_radio_start_tx(struct radio_efr32_ble_ctx_s *ctx, struct buffer_s * buffer)
+{
+  assert(buffer);
+
+  /* Check RAC state */
+  assert(EFR32_RAC_STATUS_STATE_GET(endian_le32(cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_STATUS_ADDR))) == EFR32_RAC_STATUS_STATE_OFF);
+
+  /* Clear buffer */
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(0), EFR32_BUFC_CMD_CLEAR); 
+
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_ADDR_ADDR(0), (uint32_t)buffer->data);
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_WRITEOFFSET_ADDR(0), buffer->data[buffer->begin + 1] + 2); 
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_READOFFSET_ADDR(0), 0);
+
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(0), EFR32_BUFC_CMD_PREFETCH);
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_CMD_ADDR, EFR32_RAC_CMD_TXEN);
+}
+
+static inline void efr32_radio_fsm(struct radio_efr32_ble_ctx_s *ctx)
+{
+  assert(EFR32_RAC_STATUS_STATE_GET(endian_le32(cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_STATUS_ADDR))) == EFR32_RAC_STATUS_STATE_OFF);
+
+  switch (ctx->state)
+    {
+      case EFR32_RADIO_STATE_IDLE:
+        if (ctx->pv.dev->start_count == 0)
+        {
+          ctx->chan_idx = 37;
+          break;
+        }
+        cpu_mem_write_32(EFR32_RADIO_SEQ_RAM_ADDR + 0x1F00, 0);
+        efr32_radio_set_state(ctx, EFR32_RADIO_STATE_ADV);
+        efr32_radio_start_tx(ctx, ctx->adv_packet);
+        break;
+      case EFR32_RADIO_STATE_ADV:
+        efr32_radio_set_state(ctx, EFR32_RADIO_STATE_SCAN_RQ);
+        efr32_radio_start_rx(ctx);
+        break;
+      case EFR32_RADIO_STATE_SCAN_RQ:
+        efr32_radio_set_state(ctx, EFR32_RADIO_STATE_SCAN_RSP);
+        efr32_radio_start_tx(ctx, ctx->scan_rsp_packet);
+        break;
+      case EFR32_RADIO_STATE_SCAN_RSP:
+        efr32_radio_set_state(ctx, EFR32_RADIO_STATE_IDLE);
+        efr32_radio_printk("*%d", ctx->chan_idx);
+        efr32_radio_change_adv_channel(ctx);
+        break;
+    }
+}
+
+static inline void efr32_radio_tx_irq(struct radio_efr32_ble_ctx_s *ctx, uint32_t irq)
+{
+  assert(irq & EFR32_FRC_IF_TXDONE);
+  assert(ctx->ble_rx_buffer == NULL);
+  return efr32_radio_fsm(ctx);
+}
+
+static inline void efr32_radio_change_adv_channel(struct radio_efr32_ble_ctx_s *ctx)
+{
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+
+  if (ctx->chan_idx == 39)
+    ctx->chan_idx = 37;
+  else
+    ctx->chan_idx++;
+
+  uint8_t chan_number = 39;
+  if (ctx->chan_idx == 37)
+    chan_number = 0; 
+  else if (ctx->chan_idx == 38)
+    chan_number = 12; 
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_WHITEINIT_ADDR, 0x40 | ctx->chan_idx);
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_CHCTRL_ADDR, chan_number);
+
+  efr32_radio_set_state(ctx, EFR32_RADIO_STATE_IDLE);
+
+  dev_timer_value_t value = efr32_protimer_get_value(&pv->pti);
+  efr32_protimer_request_start(&pv->pti, value, value + 480000,  0);
+}
+
+static void efr32_protimer_irq(struct device_s *dev)
+{
+  struct radio_efr32_ble_ctx_s *ctx = dev->drv_pv;
+
+  while (1)
+    {
+      uint32_t irq = endian_le32(cpu_mem_read_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IF_ADDR));
+      irq &= endian_le32(cpu_mem_read_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IEN_ADDR));
+
+      if (!irq)
+        break;
+
+      cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IFC_ADDR, endian_le32(irq));
+
+      /* Timer class interrupts */
+      if (!(irq & (EFR32_PROTIMER_IF_CC(EFR32_PROTIMER_CHANNEL) | EFR32_PROTIMER_IF_WRAPCNTOF)))
+        break;
+
+#if EFR32_PROTIMER_HW_WIDTH < 64
+      /* Compare channel interrupt */ 
+      if (irq & EFR32_PROTIMER_IF_CC(EFR32_PROTIMER_CHANNEL))
+         efr32_protimer_disable_compare(&pv->pti, EFR32_PROTIMER_CHANNEL);
+
+      /* Update the software part of the counter */
+      if (irq & EFR32_PROTIMER_IF_WRAPCNTOF)
+        pv->pti.swvalue++;
+#endif
+
+      /* CC channel irq */
+      efr32_radio_fsm(ctx);
+    }
+}
+
+static inline void efr32_radio_rx_irq(struct radio_efr32_ble_ctx_s *ctx, uint32_t irq)
+{
+  assert(ctx->ble_rx_buffer);
+
+  if (irq != EFR32_FRC_IF_RXDONE)
+    goto rx_error;
+
+  ctx->ble_rx_buffer->begin = 0;
+  ctx->ble_rx_buffer->end = cpu_mem_read_32(EFR32_BUFC_ADDR + EFR32_BUFC_WRITEOFFSET_ADDR(1)) - 2;
+
+  struct ble_addr_s addr;
+  ble_advertise_packet_rxaddr_get(ctx->ble_rx_buffer, &addr);
+
+  /* CRC failed or not a scan request or bad address */
+  if (!ctx->ble_rx_buffer->data[ctx->ble_rx_buffer->end + 1] ||
+       ble_advertise_packet_type_get(ctx->ble_rx_buffer) != BLE_SCAN_REQ ||
+       ble_addr_cmp(&ctx->ble_addr, &addr))
+    goto rx_error;
+
+  buffer_refdec(ctx->ble_rx_buffer);
+  ctx->ble_rx_buffer = NULL;
+  return efr32_radio_fsm(ctx);
+
+rx_error:
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(1), EFR32_BUFC_CMD_CLEAR);
+
+  buffer_refdec(ctx->ble_rx_buffer);
+  ctx->ble_rx_buffer = NULL;
+
+  return efr32_radio_change_adv_channel(ctx);
+}
+
+static DEV_IRQ_SRC_PROCESS(efr32_radio_irq)
+{
+  struct device_s *dev = ep->base.dev;
+  struct radio_efr32_ble_ctx_s *ctx = dev->drv_pv;
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+
+  lock_spin(&dev->lock);
+
+  uint32_t irq = 0;
+
+  switch (ep - pv->irq_ep)
+  {
+    case 0:
+      irq = cpu_mem_read_32(EFR32_MODEM_ADDR + EFR32_MODEM_IF_ADDR);
+      irq &= cpu_mem_read_32(EFR32_MODEM_ADDR + EFR32_MODEM_IEN_ADDR);
+      efr32_radio_printk("modem irq: 0x%x\n", irq);
+    case 1:
+    case 2:
+      efr32_radio_printk("Rac irq: 0x%x\n", cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_IF_ADDR));
+      break;
+    case 3:
+      irq = cpu_mem_read_32(EFR32_BUFC_ADDR + EFR32_BUFC_IF_ADDR);
+      irq &= cpu_mem_read_32(EFR32_BUFC_ADDR + EFR32_BUFC_IEN_ADDR);
+      cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_IFC_ADDR, irq);
+      break;
+    case 7:
+      efr32_protimer_irq(dev);
+      break;
+    case 8:
+        while(1)
+        {
+          irq = cpu_mem_read_32(EFR32_FRC_ADDR + EFR32_FRC_IF_ADDR);
+          irq &= cpu_mem_read_32(EFR32_FRC_ADDR + EFR32_FRC_IEN_ADDR);
+
+          /* Clear irqs */
+          cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_IFC_ADDR, irq);
+       
+          if (irq == 0)
+            break;
+       
+          if (irq & EFR32_TX_IRQ_FRC_MSK)
+            efr32_radio_tx_irq(ctx, irq);
+
+          if (irq & EFR32_RX_IRQ_FRC_MSK)
+            efr32_radio_rx_irq(ctx, irq);
+        }
+      break;
+    default:
+      efr32_radio_printk("irq: %d\n", ep - pv->irq_ep);
+      abort();
+      break;
+  }
+
+  lock_release(&dev->lock);
+}
+
+static DEV_USE(efr32_radio_use)
+{
+  struct device_accessor_s *accessor = param;
+
+  switch (op)
+    {
+    case DEV_USE_START: {
+      struct device_s *dev = accessor->dev;
+      struct radio_efr32_ble_ctx_s *ctx = dev->drv_pv;
+      if (dev->start_count == 0)
+        kroutine_exec(&ctx->pv.kr);
+      return 0;
+    }
+
+    case DEV_USE_STOP: {
+      return 0;
+    }
+
+    default:
+      return dev_use_generic(param, op);
+    }
+}
+
+static DEV_INIT(efr32_radio_init);
+static DEV_CLEANUP(efr32_radio_cleanup);
+
+DRIVER_DECLARE(efr32_radio_ble_drv, 0, "EFR32 BLE radio", efr32_radio, NULL);
+DRIVER_REGISTER(efr32_radio_ble_drv);
+
+static SLAB_GROW(efr32_grow)
+{
+  return 42;
+}
+
+static DEV_INIT(efr32_radio_init)
+{
+  struct radio_efr32_ble_ctx_s *ctx;
+
+  /* allocate private driver data */
+  ctx = mem_alloc(sizeof(*ctx), (mem_scope_sys));
+
+  if (!ctx)
+    return -ENOMEM;
+
+  memset(ctx, 0, sizeof(*ctx));
+
+  dev->drv_pv = ctx;
+  ctx->pv.dev = dev;
+
+  buffer_pool_init(&ctx->pool, 128, efr32_grow, mem_scope_sys);
+
+  ctx->ble_addr.type = BLE_ADDR_RANDOM;
+  ctx->ble_addr.addr[0] = 0x11;
+  ctx->ble_addr.addr[1] = 0x22;
+  ctx->ble_addr.addr[2] = 0x33;
+  ctx->ble_addr.addr[3] = 0x44;
+  ctx->ble_addr.addr[4] = 0x55;
+  ctx->ble_addr.addr[5] = 0x66;
+
+  ctx->chan_idx = 37;
+
+  ctx->adv_packet = buffer_pool_alloc(&ctx->pool);
+  ctx->scan_rsp_packet = buffer_pool_alloc(&ctx->pool);
+
+  ble_adv_ind_set(ctx->adv_packet, &ctx->ble_addr); 
+  ble_adv_data_append(ctx->adv_packet, BLE_GAP_FLAGS, (const uint8_t []){ BLE_GAP_FLAGS_GENERAL_ADV | BLE_GAP_FLAGS_BREDR_NOT_SUPPORTED }, 1);
+  ble_adv_data_append(ctx->adv_packet, BLE_GAP_APPEARANCE, (const uint8_t []){
+    BLE_GAP_APPEARANCE_GENERIC_MEDIA_PLAYER & 0xff,
+    BLE_GAP_APPEARANCE_GENERIC_MEDIA_PLAYER >> 8,
+    }, 2);
+
+  ble_adv_scan_rsp_set(ctx->scan_rsp_packet, &ctx->ble_addr); 
+  ble_adv_data_string_append(ctx->scan_rsp_packet, BLE_GAP_COMPLETE_LOCAL_NAME, "MutekH on EFR32"); 
+
+  if (efr32_radio_reset(ctx))
+    goto err_mem;
+
+  ctx->pv.freq.num = EFR32_RADIO_HFXO_CLK;
+  ctx->pv.freq.denom = 1;
+
+  device_get_res_freq(dev, &ctx->pv.freq, 0);
+
+  assert(ctx->pv.freq.denom == 1);
+
+  device_irq_source_init(dev, ctx->pv.irq_ep, EFR32_RADIO_IRQ_COUNT,
+      &efr32_radio_irq);
+
+  if (device_irq_source_link(dev, ctx->pv.irq_ep, EFR32_RADIO_IRQ_COUNT, -1))
+    goto err_mem;
+
+#ifdef CONFIG_DRIVER_EFR32_DEBUG
+  efr32_radio_debug_init(&ctx->pv);
+#endif
+
+  return 0;
+
+err_mem:
+  mem_free(ctx);
+  return -1;
+}
+
+static DEV_CLEANUP(efr32_radio_cleanup)
+{
+  struct radio_efr32_ble_ctx_s *ctx = dev->drv_pv;
+
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CMD_ADDR, endian_le32(EFR32_PROTIMER_CMD_STOP));
+
+  buffer_pool_cleanup(&ctx->pool);
+  device_irq_source_unlink(dev, ctx->pv.irq_ep, EFR32_RADIO_IRQ_COUNT);
+
+  mem_free(ctx);
+
+  return 0;
+}
+
+static error_t efr32_radio_reset(struct radio_efr32_ble_ctx_s *ctx)
+{
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_DFLCTRL_ADDR, EFR32_FRC_DFLCTRL_DFLMODE(SINGLEBYTE) |
+                                                      EFR32_FRC_DFLCTRL_DFLOFFSET(1) |
+                                                      EFR32_FRC_DFLCTRL_DFLBITS(8) |
+                                                      EFR32_FRC_DFLCTRL_MINLENGTH(1));
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_MAXLENGTH_ADDR, EFR32_FRC_MAXLENGTH_MAXLENGTH(256));
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_WCNTCMP1_ADDR, EFR32_FRC_WCNTCMP1_LENGTHFIELDLOC(1));
+
+  /* Whitenning  */
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_WHITEPOLY_ADDR, EFR32_FRC_WHITEPOLY_POLY(68));
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_WHITEINIT_ADDR, EFR32_FRC_WHITEINIT_WHITEINIT(101));
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_FECCTRL_ADDR, EFR32_FRC_FECCTRL_BLOCKWHITEMODE(WHITE) |
+                                                      EFR32_FRC_FECCTRL_CONVMODE(DISABLE) |
+                                                      EFR32_FRC_FECCTRL_INTERLEAVEMODE(DISABLE));
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_CTRL_ADDR, EFR32_FRC_CTRL_BITORDER(LSB) |
+                                                   EFR32_FRC_CTRL_TXFCDMODE(FCDMODE2) |
+                                                   EFR32_FRC_CTRL_RXFCDMODE(FCDMODE2) |
+                                                   EFR32_FRC_CTRL_BITSPERWORD(7));
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_RXCTRL_ADDR, EFR32_FRC_RXCTRL_BUFRESTOREFRAMEERROR | EFR32_FRC_RXCTRL_BUFRESTORERXABORTED);
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_TRAILRXDATA_ADDR, EFR32_FRC_TRAILRXDATA_RSSI | EFR32_FRC_TRAILRXDATA_CRCOK);
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_FCD_ADDR(0), EFR32_FRC_FCD_WORDS(255) |
+                                                     EFR32_FRC_FCD_INCLUDECRC |
+                                                     EFR32_FRC_FCD_CALCCRC);
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_FCD_ADDR(1), EFR32_FRC_FCD_WORDS(255) |
+                                                     EFR32_FRC_FCD_INCLUDECRC |
+                                                     EFR32_FRC_FCD_CALCCRC |
+                                                     EFR32_FRC_FCD_SKIPWHITE);
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_FCD_ADDR(2), EFR32_FRC_FCD_WORDS(255) |
+                                                     EFR32_FRC_FCD_BUFFER(1) |
+                                                     EFR32_FRC_FCD_INCLUDECRC |
+                                                     EFR32_FRC_FCD_CALCCRC);
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_FCD_ADDR(3), EFR32_FRC_FCD_WORDS(255) |
+                                                     EFR32_FRC_FCD_BUFFER(1) |
+                                                     EFR32_FRC_FCD_INCLUDECRC |
+                                                     EFR32_FRC_FCD_CALCCRC |
+                                                     EFR32_FRC_FCD_SKIPWHITE);
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_MIRRORIF_ADDR, EFR32_FRC_MIRRORIF_TXDONEM | EFR32_FRC_MIRRORIF_IFMIRRORCLEAR);
+
+  /* CRC configuration */
+  cpu_mem_write_32(EFR32_CRC_ADDR + EFR32_CRC_CTRL_ADDR, EFR32_CRC_CTRL_CRCWIDTH(CRCWIDTH24) |
+                              EFR32_CRC_CTRL_INPUTBITORDER(LSB) |
+                              EFR32_CRC_CTRL_BYTEREVERSE(MSB) |
+                              EFR32_CRC_CTRL_BITREVERSE(MSB) |
+                              EFR32_CRC_CTRL_BITSPERWORD(7));
+
+  cpu_mem_write_32(EFR32_CRC_ADDR + EFR32_CRC_INIT_ADDR, EFR32_CRC_INIT_INIT(0xaaaaaa));
+  cpu_mem_write_32(EFR32_CRC_ADDR + EFR32_CRC_POLY_ADDR, EFR32_CRC_POLY_POLY(0xda6000));
+
+  /* Frequency */
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_CALCTRL_ADDR, EFR32_SYNTH_CALCTRL_NUMCYCLES(1) |
+                                                        EFR32_SYNTH_CALCTRL_CAPCALCYCLEWAIT(CYCLES1) |
+                                                        EFR32_SYNTH_CALCTRL_STARTUPTIMING(10) |
+                                                        EFR32_SYNTH_CALCTRL_AUXCALCYCLES(4) |
+                                                        EFR32_SYNTH_CALCTRL_AUXCALCYCLEWAIT(CYCLES64));
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_VCDACCTRL_ADDR, EFR32_SYNTH_VCDACCTRL_VCDACVAL(35));
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_FREQ_ADDR, EFR32_SYNTH_FREQ_FREQ(32795306));
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_IFFREQ_ADDR, EFR32_SYNTH_IFFREQ_IFFREQ(14563) |
+                                                       EFR32_SYNTH_IFFREQ_LOSIDE);
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_DIVCTRL_ADDR, EFR32_SYNTH_DIVCTRL_LODIVFREQCTRL(LODIV1) |
+                                                        EFR32_SYNTH_DIVCTRL_AUXLODIVFREQCTRL(LODIV1));
+
+  /* Channel configuration */
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_CHSP_ADDR, EFR32_SYNTH_CHSP_CHSP(27306));
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_CHCTRL_ADDR, 0);
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_VCOGAIN_ADDR, EFR32_SYNTH_VCOGAIN_VCOGAIN(42));
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_AUXVCDACCTRL_ADDR, EFR32_SYNTH_AUXVCDACCTRL_VALUE(7));
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_CAPCALCYCLECNT_ADDR, EFR32_SYNTH_CAPCALCYCLECNT_CAPCALCYCLECNT(127));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_CTRL_ADDR, EFR32_RAC_CTRL_ACTIVEPOL |
+                                                   EFR32_RAC_CTRL_PAENPOL |
+                                                   EFR32_RAC_CTRL_LNAENPOL);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_IEN_ADDR, EFR32_RAC_IF_SEQ(235));
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_LVDSCTRL_ADDR, EFR32_RAC_LVDSCTRL_LVDSCURR(3));
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_LVDSIDLESEQ_ADDR, EFR32_RAC_LVDSIDLESEQ_LVDSIDLESEQ(188));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_HFXORETIMECTRL_ADDR, EFR32_RAC_HFXORETIMECTRL_LIMITH(6) |
+                                                             EFR32_RAC_HFXORETIMECTRL_LIMITL(7));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_WAITSNSH_ADDR, EFR32_RAC_WAITSNSH_WAITSNSH(1));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_SEQCTRL_ADDR, EFR32_RAC_SEQCTRL_COMPACT |
+                                                      EFR32_RAC_SEQCTRL_COMPINVALMODE(NEVER));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_PRESC_ADDR, EFR32_RAC_PRESC_STIMER(7));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_SYNTHREGCTRL_ADDR, EFR32_RAC_SYNTHREGCTRL_MMDLDOAMPCURR(3) |
+                                                           EFR32_RAC_SYNTHREGCTRL_MMDLDOVREFTRIM(3) |
+                                                           EFR32_RAC_SYNTHREGCTRL_VCOLDOAMPCURR(3) |
+                                                           EFR32_RAC_SYNTHREGCTRL_VCOLDOVREFTRIM(3) |
+                                                           EFR32_RAC_SYNTHREGCTRL_CHPLDOAMPCURR(3) |
+                                                           EFR32_RAC_SYNTHREGCTRL_CHPLDOVREFTRIM(3));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_VCOCTRL_ADDR, EFR32_RAC_VCOCTRL_VCOAMPLITUDE(10) |
+                                                      EFR32_RAC_VCOCTRL_VCODETAMPLITUDE(7) |
+                                                      EFR32_RAC_VCOCTRL_VCODETEN |
+                                                      EFR32_RAC_VCOCTRL_VCODETMODE |
+                                                      EFR32_RAC_VCOCTRL_VCOAREGCURR(1) |
+                                                      EFR32_RAC_VCOCTRL_VCOCREGCURR(2) |
+                                                      EFR32_RAC_VCOCTRL_VCODIVCURR(15));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_MMDCTRL_ADDR, EFR32_RAC_MMDCTRL_MMDDIVDCDC(85) |
+                                                      EFR32_RAC_MMDCTRL_MMDDIVRSDCDC(1) |
+                                                      EFR32_RAC_MMDCTRL_MMDDIVRSDIG(2) |
+                                                      EFR32_RAC_MMDCTRL_MMDENRSDIG);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_CHPCTRL_ADDR, EFR32_RAC_CHPCTRL_CHPBIAS(6) |
+                                                      EFR32_RAC_CHPCTRL_CHPCURR(5));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_CHPCAL_ADDR, EFR32_RAC_CHPCAL_PSRC(4) |
+                                                     EFR32_RAC_CHPCAL_NSRC(4));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_LPFCTRL_ADDR, EFR32_RAC_LPFCTRL_LPFINPUTCAP(3) |
+                                                      EFR32_RAC_LPFCTRL_LPFSWITCHINGEN |
+                                                      EFR32_RAC_LPFCTRL_LPFGNDSWITCHINGEN |
+                                                      EFR32_RAC_LPFCTRL_LPFBWTX(8));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_AUXCTRL_ADDR, EFR32_RAC_AUXCTRL_CHPCURR(1) |
+                                                      EFR32_RAC_AUXCTRL_LDOAMPCURR(3) |
+                                                      EFR32_RAC_AUXCTRL_LDOVREFTRIM(3) |
+                                                      EFR32_RAC_AUXCTRL_LPFRES(1));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL_ADDR, EFR32_RAC_RFENCTRL_DEMEN);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL0_ADDR, EFR32_RAC_RFENCTRL0_CASCODEDIS |
+                                                        EFR32_RAC_RFENCTRL0_STRIPESLICEDIS);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_PACTRL0_ADDR, EFR32_RAC_PACTRL0__2P4RFVDDSEL |
+                                                      EFR32_RAC_PACTRL0_CASCODE(EN2SLICES) |
+                                                      EFR32_RAC_PACTRL0_SLICE(EN2SLICES) |
+                                                      EFR32_RAC_PACTRL0_STRIPE(28) |
+                                                      EFR32_RAC_PACTRL0_DACGLITCHCTRL);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_PAPKDCTRL_ADDR, EFR32_RAC_PAPKDCTRL_VTHSEL(23) |
+                                                        EFR32_RAC_PAPKDCTRL_CAPSEL(3) |
+                                                        EFR32_RAC_PAPKDCTRL_I2VCM(1) |
+                                                        EFR32_RAC_PAPKDCTRL_PKDBIASTH(4));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_PABIASCTRL0_ADDR, EFR32_RAC_PABIASCTRL0_LDOBIAS |
+                                                          EFR32_RAC_PABIASCTRL0_PABIAS(1) |
+                                                          EFR32_RAC_PABIASCTRL0_BUF0BIAS(2) |
+                                                          EFR32_RAC_PABIASCTRL0_BUF12BIAS(1) |
+                                                          EFR32_RAC_PABIASCTRL0_TXPOWER);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_PABIASCTRL1_ADDR, EFR32_RAC_PABIASCTRL1_VLDO(5) |
+                                                          EFR32_RAC_PABIASCTRL1_VLDOFB(2) |
+                                                          EFR32_RAC_PABIASCTRL1_VCASCODEHV(5) |
+                                                          EFR32_RAC_PABIASCTRL1_VCASCODELV(4) |
+                                                          EFR32_RAC_PABIASCTRL1__2P4VDDPATHRESHOLD(2));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_RFBIASCTRL_ADDR, EFR32_RAC_RFBIASCTRL_LDOVREF(4) |
+                                                         EFR32_RAC_RFBIASCTRL_LDOAMPCURR(3));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_RFBIASCAL_ADDR, EFR32_RAC_RFBIASCAL_VREF(22) |
+                                                        EFR32_RAC_RFBIASCAL_BIAS(28) |
+                                                        EFR32_RAC_RFBIASCAL_TEMPCO(48));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_LNAMIXCTRL1_ADDR, EFR32_RAC_LNAMIXCTRL1_TRIMAUXPLLCLK(E0) |
+                                                          EFR32_RAC_LNAMIXCTRL1_TRIMTRSWGATEV(3) |
+                                                          EFR32_RAC_LNAMIXCTRL1_TRIMVCASLDO |
+                                                          EFR32_RAC_LNAMIXCTRL1_TRIMVREGMIN(1));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_IFPGACTRL_ADDR, EFR32_RAC_IFPGACTRL_VLDO(3) |
+                                                        EFR32_RAC_IFPGACTRL_BANDSEL(2P4) |
+                                                        EFR32_RAC_IFPGACTRL_CASCBIAS(7) |
+                                                        EFR32_RAC_IFPGACTRL_TRIMVCASLDO |
+                                                        EFR32_RAC_IFPGACTRL_TRIMVCM(3) |
+                                                        EFR32_RAC_IFPGACTRL_TRIMVREGMIN(1));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_IFPGACAL_ADDR, EFR32_RAC_IFPGACAL_IRAMP(2) |
+                                                       EFR32_RAC_IFPGACAL_IRPHASE(10) |
+                                                       EFR32_RAC_IFPGACAL_OFFSETI(64));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_IFFILTCTRL_ADDR, EFR32_RAC_IFFILTCTRL_BANDWIDTH(13) |
+                                                         EFR32_RAC_IFFILTCTRL_CENTFREQ(3) |
+                                                         EFR32_RAC_IFFILTCTRL_VCM(2) |
+                                                         EFR32_RAC_IFFILTCTRL_VREG(4));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_IFADCCTRL_ADDR, EFR32_RAC_IFADCCTRL_VLDOSERIES(3) |
+                                                        EFR32_RAC_IFADCCTRL_VLDOSERIESCURR(3) |
+                                                        EFR32_RAC_IFADCCTRL_VLDOSHUNT(2) |
+                                                        EFR32_RAC_IFADCCTRL_VLDOCLKGEN(3) |
+                                                        EFR32_RAC_IFADCCTRL_VCM(E2) |
+                                                        EFR32_RAC_IFADCCTRL_OTA1CURRENT(2) |
+                                                        EFR32_RAC_IFADCCTRL_OTA2CURRENT(2) |
+                                                        EFR32_RAC_IFADCCTRL_OTA3CURRENT(2) |
+                                                        EFR32_RAC_IFADCCTRL_REGENCLKDELAY(3) |
+                                                        EFR32_RAC_IFADCCTRL_INVERTCLK);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_PACTUNECTRL_ADDR, EFR32_RAC_PACTUNECTRL_PACTUNERX(4) |
+                                                           EFR32_RAC_PACTUNECTRL_SGPACTUNERX(4));
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_RCTUNE_ADDR, EFR32_RAC_RCTUNE_IFADCRCTUNE(34) |
+                                                           EFR32_RAC_RCTUNE_IFFILT(34));
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_APC_ADDR, EFR32_RAC_APC_AMPCONTROLLIMITSW(255));
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_CHPCTRL1_ADDR, EFR32_RAC_CHPCTRL1_BYPREPLDORX |
+                                                           EFR32_RAC_CHPCTRL1_TRIMREPLDO(1));
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_MMDCTRL1_ADDR, EFR32_RAC_MMDCTRL1_BYPREPLDORX |
+                                                           EFR32_RAC_MMDCTRL1_TRIMREPLDO(1));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_FREQOFFEST_ADDR, EFR32_MODEM_FREQOFFEST_CORRVAL(111) |
+                                                           EFR32_MODEM_FREQOFFEST_SOFTVAL(198));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_MIXCTRL_ADDR, EFR32_MODEM_MIXCTRL_MODE(NORMAL) |
+                                                        EFR32_MODEM_MIXCTRL_DIGIQSWAPEN);
+
+  /* Modulation */
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CTRL0_ADDR, EFR32_MODEM_CTRL0_MAPFSK(MAP0) |
+                                                      EFR32_MODEM_CTRL0_CODING(NRZ) |
+                                                      EFR32_MODEM_CTRL0_MODFORMAT(FSK2) |
+                                                      EFR32_MODEM_CTRL0_DSSSSHIFTS(NOSHIFT) |
+                                                      EFR32_MODEM_CTRL0_DSSSDOUBLE(DIS) |
+                                                      EFR32_MODEM_CTRL0_DIFFENCMODE(DIS) |
+                                                      EFR32_MODEM_CTRL0_SHAPING(ASYMMETRIC) |
+                                                      EFR32_MODEM_CTRL0_DEMODRAWDATASEL(DIS) |
+                                                      EFR32_MODEM_CTRL0_FRAMEDETDEL(DEL32));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CTRL1_ADDR, EFR32_MODEM_CTRL1_SYNCBITS(31) |
+                                                      EFR32_MODEM_CTRL1_COMPMODE(NOLOCK) |
+                                                      EFR32_MODEM_CTRL1_RESYNCPER(1) |
+                                                      EFR32_MODEM_CTRL1_PHASEDEMOD(BDD));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CTRL2_ADDR, EFR32_MODEM_CTRL2_SQITHRESH(200) |
+                                                      EFR32_MODEM_CTRL2_TXPINMODE(OFF) |
+                                                      EFR32_MODEM_CTRL2_DATAFILTER(LEN7) |
+                                                      EFR32_MODEM_CTRL2_RATESELMODE(NOCHANGE) |
+                                                      EFR32_MODEM_CTRL2_DMASEL(SOFT));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CTRL3_ADDR, EFR32_MODEM_CTRL3_PRSDINSEL(PRSCH0) |
+                                                      EFR32_MODEM_CTRL3_ANTDIVMODE(ANTENNA0) |
+                                                      EFR32_MODEM_CTRL3_TSAMPMODE(OFF) |
+                                                      EFR32_MODEM_CTRL3_TSAMPDEL(2));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CTRL4_ADDR, EFR32_MODEM_CTRL4_ADCSATLEVEL(CONS64));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_TXBR_ADDR, EFR32_MODEM_TXBR_TXBRNUM(24) |
+                                                     EFR32_MODEM_TXBR_TXBRDEN(5));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_RXBR_ADDR, EFR32_MODEM_RXBR_RXBRNUM(1) |
+                                                     EFR32_MODEM_RXBR_RXBRDEN(2) |
+                                                     EFR32_MODEM_RXBR_RXBRINT(3));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CF_ADDR, EFR32_MODEM_CF_DEC0(DF3) |
+                                                   EFR32_MODEM_CF_DEC1(1) |
+                                                   EFR32_MODEM_CF_CFOSR(CF7) |
+                                                   EFR32_MODEM_CF_DEC1GAIN(ADD0));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_PRE_ADDR, EFR32_MODEM_PRE_BASE(2) |
+                                                    EFR32_MODEM_PRE_BASEBITS(1) |
+                                                    EFR32_MODEM_PRE_PREERRORS(1) |
+                                                    EFR32_MODEM_PRE_TXBASES(4));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SYNC0_ADDR, EFR32_MODEM_SYNC0_SYNC0(2391391958));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_TIMING_ADDR, EFR32_MODEM_TIMING_TIMTHRESH(140) |
+                                                       EFR32_MODEM_TIMING_FDM0THRESH(3) |
+                                                       EFR32_MODEM_TIMING_FASTRESYNC(DIS));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_MODINDEX_ADDR, EFR32_MODEM_MODINDEX_MODINDEXM(20) |
+                                                         EFR32_MODEM_MODINDEX_FREQGAINE(2) |
+                                                         EFR32_MODEM_MODINDEX_FREQGAINM(3));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SHAPING0_ADDR, EFR32_MODEM_SHAPING0_COEFF0(1) |
+                                                         EFR32_MODEM_SHAPING0_COEFF1(4) |
+                                                         EFR32_MODEM_SHAPING0_COEFF2(11) |
+                                                         EFR32_MODEM_SHAPING0_COEFF3(25));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SHAPING1_ADDR, EFR32_MODEM_SHAPING1_COEFF4(44) |
+                                                         EFR32_MODEM_SHAPING1_COEFF5(64) |
+                                                         EFR32_MODEM_SHAPING1_COEFF6(76) |
+                                                         EFR32_MODEM_SHAPING1_COEFF7(89));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SHAPING2_ADDR, EFR32_MODEM_SHAPING2_COEFF8(96) |
+                                                         EFR32_MODEM_SHAPING2_COEFF9(91) |
+                                                         EFR32_MODEM_SHAPING2_COEFF10(83) |
+                                                         EFR32_MODEM_SHAPING2_COEFF11(71));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SHAPING3_ADDR, EFR32_MODEM_SHAPING3_COEFF12(54) |
+                                                         EFR32_MODEM_SHAPING3_COEFF13(37) |
+                                                         EFR32_MODEM_SHAPING3_COEFF14(27) |
+                                                         EFR32_MODEM_SHAPING3_COEFF15(17));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SHAPING4_ADDR, EFR32_MODEM_SHAPING4_COEFF17(10) |
+                                                         EFR32_MODEM_SHAPING4_COEFF18(13) |
+                                                         EFR32_MODEM_SHAPING4_COEFF19(15) |
+                                                         EFR32_MODEM_SHAPING4_COEFF20(14) |
+                                                         EFR32_MODEM_SHAPING4_COEFF21(12));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SHAPING5_ADDR, EFR32_MODEM_SHAPING5_COEFF22(9) |
+                                                         EFR32_MODEM_SHAPING5_COEFF23(7) |
+                                                         EFR32_MODEM_SHAPING5_COEFF24(6) |
+                                                         EFR32_MODEM_SHAPING5_COEFF25(5) |
+                                                         EFR32_MODEM_SHAPING5_COEFF26(4) |
+                                                         EFR32_MODEM_SHAPING5_COEFF27(3) |
+                                                         EFR32_MODEM_SHAPING5_COEFF28(2) |
+                                                         EFR32_MODEM_SHAPING5_COEFF29(2));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SHAPING6_ADDR, EFR32_MODEM_SHAPING6_COEFF30(1) |
+                                                         EFR32_MODEM_SHAPING6_COEFF31(1) |
+                                                         EFR32_MODEM_SHAPING6_COEFF32(1) |
+                                                         EFR32_MODEM_SHAPING6_COEFF33(1) |
+                                                         EFR32_MODEM_SHAPING6_COEFF34(1));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_RAMPCTRL_ADDR, EFR32_MODEM_RAMPCTRL_RAMPRATE2(4));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_RAMPLEV_ADDR, EFR32_MODEM_RAMPLEV_RAMPLEV2(180));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DCCOMP_ADDR, EFR32_MODEM_DCCOMP_DCESTIEN |
+                                                       EFR32_MODEM_DCCOMP_DCCOMPEN |
+                                                       EFR32_MODEM_DCCOMP_DCCOMPGEAR(3) |
+                                                       EFR32_MODEM_DCCOMP_DCLIMIT(FULLSCALE));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DCESTI_ADDR, EFR32_MODEM_DCESTI_DCCOMPESTIVALI(32650) |
+                                                       EFR32_MODEM_DCESTI_DCCOMPESTIVALQ(236));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SRCCHF_ADDR, EFR32_MODEM_SRCCHF_SRCRATIO1(143) |
+                                                       EFR32_MODEM_SRCCHF_SRCENABLE1 |
+                                                       EFR32_MODEM_SRCCHF_SRCRATIO2(838) |
+                                                       EFR32_MODEM_SRCCHF_SRCENABLE2 |
+                                                       EFR32_MODEM_SRCCHF_BWSEL(2) |
+                                                       EFR32_MODEM_SRCCHF_INTOSR);
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DSATHD0_ADDR, EFR32_MODEM_DSATHD0_SPIKETHD(50) |
+                                                        EFR32_MODEM_DSATHD0_UNMODTHD(4) |
+                                                        EFR32_MODEM_DSATHD0_FDEVMINTHD(8) |
+                                                        EFR32_MODEM_DSATHD0_FDEVMAXTHD(100));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DSATHD1_ADDR, EFR32_MODEM_DSATHD1_POWABSTHD(2000) |
+                                                        EFR32_MODEM_DSATHD1_POWRELTHD(MODE3) |
+                                                        EFR32_MODEM_DSATHD1_DSARSTCNT(2) |
+                                                        EFR32_MODEM_DSATHD1_RSSIJMPTHD(6) |
+                                                        EFR32_MODEM_DSATHD1_PWRFLTBYP |
+                                                        EFR32_MODEM_DSATHD1_FREQSCALE);
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DSACTRL_ADDR, EFR32_MODEM_DSACTRL_DSAMODE(ENABLED) |
+                                                        EFR32_MODEM_DSACTRL_ARRTHD(4) |
+                                                        EFR32_MODEM_DSACTRL_ARRTOLERTHD0(2) |
+                                                        EFR32_MODEM_DSACTRL_ARRTOLERTHD1(4) |
+                                                        EFR32_MODEM_DSACTRL_FREQAVGSYM |
+                                                        EFR32_MODEM_DSACTRL_DSARSTON);
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_VITERBIDEMOD_ADDR, EFR32_MODEM_VITERBIDEMOD_VTDEMODEN |
+                                                             EFR32_MODEM_VITERBIDEMOD_VITERBIKSI1(62) |
+                                                             EFR32_MODEM_VITERBIDEMOD_VITERBIKSI2(42) |
+                                                             EFR32_MODEM_VITERBIDEMOD_VITERBIKSI3(28));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_VTCORRCFG0_ADDR, EFR32_MODEM_VTCORRCFG0_EXPECTPATT(355197) |
+                                                           EFR32_MODEM_VTCORRCFG0_EXPSYNCLEN(126) |
+                                                           EFR32_MODEM_VTCORRCFG0_BUFFHEAD(12));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DIGMIXCTRL_ADDR, EFR32_MODEM_DIGMIXCTRL_DIGMIXFREQ(87377) |
+                                                           EFR32_MODEM_DIGMIXCTRL_DIGMIXMODE);
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_VTCORRCFG1_ADDR, EFR32_MODEM_VTCORRCFG1_CORRSHFTLEN(48) |
+                                                           EFR32_MODEM_VTCORRCFG1_VTFRQLIM(110));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_VTTRACK_ADDR, EFR32_MODEM_VTTRACK_FREQTRACKMODE(MODE1) |
+                                                           EFR32_MODEM_VTTRACK_TIMTRACKTHD(2) |
+                                                           EFR32_MODEM_VTTRACK_TIMEACQUTHD(238) |
+                                                           EFR32_MODEM_VTTRACK_TIMEOUTMODE |
+                                                           EFR32_MODEM_VTTRACK_TIMGEAR(GEAR0));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_BREST_ADDR, EFR32_MODEM_BREST_BRESTINT(7));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CGCLKSTOP_ADDR, EFR32_MODEM_CGCLKSTOP_FORCEOFF(57343));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_POE_ADDR, EFR32_MODEM_POE_POEI(511));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_RSSI_ADDR, EFR32_AGC_RSSI_RSSIFRAC(2) |
+                                                   EFR32_AGC_RSSI_RSSIINT(209));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_FRAMERSSI_ADDR, EFR32_AGC_FRAMERSSI_FRAMERSSIFRAC(1) |
+                                                           EFR32_AGC_FRAMERSSI_FRAMERSSIINT(195));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_CTRL0_ADDR, EFR32_AGC_CTRL0_PWRTARGET(248) |
+                                                    EFR32_AGC_CTRL0_MODE(CONT) |
+                                                    EFR32_AGC_CTRL0_RSSISHIFT(78));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_CTRL1_ADDR, EFR32_AGC_CTRL1_RSSIPERIOD(3));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_CTRL2_ADDR, EFR32_AGC_CTRL2_HYST(3) |
+                                                    EFR32_AGC_CTRL2_FASTLOOPDEL(5) |
+                                                    EFR32_AGC_CTRL2_CFLOOPDEL(29) |
+                                                    EFR32_AGC_CTRL2_ADCRSTFASTLOOP(GAINREDUCTION) |
+                                                    EFR32_AGC_CTRL2_ADCRSTSTARTUP);
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_IFPEAKDET_ADDR, EFR32_AGC_IFPEAKDET_PKDTHRESH1(2) |
+                                                           EFR32_AGC_IFPEAKDET_PKDTHRESH2(8));
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_MANGAIN_ADDR, EFR32_AGC_MANGAIN_MANGAINLNAATTEN(12));
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_RFPEAKDET_ADDR, EFR32_AGC_RFPEAKDET_RFPKDTHRESH1(5) |
+                                                           EFR32_AGC_RFPEAKDET_RFPKDTHRESH2(13));
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_GAINRANGE_ADDR, EFR32_AGC_GAINRANGE_MAXGAIN(60) |
+                                                           EFR32_AGC_GAINRANGE_MINGAIN(122));
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_GAININDEX_ADDR, EFR32_AGC_GAININDEX_NUMINDEXPGA(12) |
+                                                        EFR32_AGC_GAININDEX_NUMINDEXDEGEN(3) |
+                                                        EFR32_AGC_GAININDEX_NUMINDEXSLICES(6) |
+                                                        EFR32_AGC_GAININDEX_NUMINDEXATTEN(12));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_SLICECODE_ADDR, EFR32_AGC_SLICECODE_SLICECODEINDEX0(3) |
+                                                        EFR32_AGC_SLICECODE_SLICECODEINDEX1(4) |
+                                                        EFR32_AGC_SLICECODE_SLICECODEINDEX2(5) |
+                                                        EFR32_AGC_SLICECODE_SLICECODEINDEX3(6) |
+                                                        EFR32_AGC_SLICECODE_SLICECODEINDEX4(8) |
+                                                        EFR32_AGC_SLICECODE_SLICECODEINDEX5(10) |
+                                                        EFR32_AGC_SLICECODE_SLICECODEINDEX6(12));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_ATTENCODE1_ADDR, EFR32_AGC_ATTENCODE1_ATTENCODEINDEX1(1) |
+                                                         EFR32_AGC_ATTENCODE1_ATTENCODEINDEX2(2) |
+                                                         EFR32_AGC_ATTENCODE1_ATTENCODEINDEX3(3) |
+                                                         EFR32_AGC_ATTENCODE1_ATTENCODEINDEX4(4) |
+                                                         EFR32_AGC_ATTENCODE1_ATTENCODEINDEX5(5) |
+                                                         EFR32_AGC_ATTENCODE1_ATTENCODEINDEX6(6));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_ATTENCODE2_ADDR, EFR32_AGC_ATTENCODE2_ATTENCODEINDEX7(7) |
+                                                         EFR32_AGC_ATTENCODE2_ATTENCODEINDEX8(8) |
+                                                         EFR32_AGC_ATTENCODE2_ATTENCODEINDEX9(9) |
+                                                         EFR32_AGC_ATTENCODE2_ATTENCODEINDEX10(10) |
+                                                         EFR32_AGC_ATTENCODE2_ATTENCODEINDEX11(11) |
+                                                         EFR32_AGC_ATTENCODE2_ATTENCODEINDEX12(12));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_ATTENCODE3_ADDR, EFR32_AGC_ATTENCODE3_ATTENCODEINDEX13(13) |
+                                                         EFR32_AGC_ATTENCODE3_ATTENCODEINDEX14(14) |
+                                                         EFR32_AGC_ATTENCODE3_ATTENCODEINDEX15(15) |
+                                                         EFR32_AGC_ATTENCODE3_ATTENCODEINDEX16(16) |
+                                                         EFR32_AGC_ATTENCODE3_ATTENCODEINDEX17(17) |
+                                                         EFR32_AGC_ATTENCODE3_ATTENCODEINDEX18(18));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_GAINSTEPLIM_ADDR, EFR32_AGC_GAINSTEPLIM_FASTSTEPDOWN(5) |
+                                                          EFR32_AGC_GAINSTEPLIM_FASTSTEPUP(2) |
+                                                          EFR32_AGC_GAINSTEPLIM_CFLOOPSTEPMAX(1) |
+                                                          EFR32_AGC_GAINSTEPLIM_ADCATTENMODE(DISABLE));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_LOOPDEL_ADDR, EFR32_AGC_LOOPDEL_PKDWAIT(15) |
+                                                      EFR32_AGC_LOOPDEL_IFPGADEL(7) |
+                                                      EFR32_AGC_LOOPDEL_LNASLICESDEL(7));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_MININDEX_ADDR, EFR32_AGC_MININDEX_INDEXMINATTEN(6) |
+                                                       EFR32_AGC_MININDEX_INDEXMINDEGEN(30) |
+                                                       EFR32_AGC_MININDEX_INDEXMINPGA(18));
+
+  /* Sequencer code initialisaton */
+  efr32_radio_seq_init(pv, seqcode, 4 * seqcode_size);
+
+  /* Clear buffer */
+  for (uint8_t i = 0; i < 4; i++)
+    cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(i), EFR32_BUFC_CMD_CLEAR);
+
+  // TX/RX buffers initialisation 
+
+  uint32_t x = bit_ctz32(EFR32_RADIO_BUFFER_SIZE) - 6;
+
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_ADDR_ADDR(2), (uint32_t)pv->rx_length_buffer);
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CTRL_ADDR(2), 0);
+
+  /* Enable irq */
+  x =  cpu_mem_read_32(EFR32_FRC_ADDR + EFR32_FRC_IEN_ADDR);
+  x |= 0x1FF;
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_IFC_ADDR, x); 
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_IEN_ADDR, x); 
+
+  efr32_radio_set_state(ctx, EFR32_RADIO_STATE_IDLE);
+
+  kroutine_init_deferred(&pv->kr, &efr32_radio_kr_op);
+  
+  return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/radio/common.c	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,125 @@
+/*
+   This file is part of MutekH.
+
+   MutekH is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; version 2.1 of the
+   License.
+
+   MutekH is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with MutekH; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.
+
+   Copyright (c) 2017 Sebastien Cerdan <sebcerdan@gmail.com>
+
+*/
+
+#include "common.h"
+
+#ifdef CONFIG_DRIVER_EFR32_DEBUG
+
+#define EFR32_RADIO_DEBUG_SIZE 0x1000
+#define EFR32_RADIO_DEBUG_ADDR (CONFIG_LOAD_ROM_RW_ADDR + 0x40000 - EFR32_RADIO_DEBUG_SIZE)
+
+void efr32_radio_debug_port(struct radio_efr32_ctx_s *pv, uint8_t val)
+{
+  uint32_t x, a;
+
+  uint8_t bitidx = 0;
+  uint8_t bitcnt = 4;
+
+  assert(val < 16);
+
+  uint32_t msk = (1 << bitcnt) - 1;
+
+  a = 0x4000a000 + 0xC + 1 * 0x30;
+
+  x = (cpu_mem_read_32(a) & ~(msk << bitidx)) | ((val & msk) << bitidx);
+
+  cpu_mem_write_32(a, x);
+}
+
+void efr32_radio_debug_init(struct radio_efr32_ctx_s *pv)
+{
+  uint32_t * p = EFR32_RADIO_DEBUG_ADDR;
+
+  memset(p, 0, EFR32_RADIO_DEBUG_SIZE);
+
+  p[0] = EFR32_RADIO_DEBUG_ADDR;
+  uint32_t *base = EFR32_RADIO_DEBUG_ADDR;
+  pv->pdbg = base + 1;
+
+  /* Set PB6 to PB9 in output */
+  uintptr_t a = 0x4000a004 + 1 * 0x30;
+  uint32_t x = cpu_mem_read_32(a);
+  cpu_mem_write_32(a, x | (0x44 << 24));
+
+  a = 0x4000a008 + 1 * 0x30;
+  x = cpu_mem_read_32(a);
+  cpu_mem_write_32(a, x | 0x44);
+
+  efr32_radio_debug_port(pv, 0xF); 
+}
+
+void efr32_radio_print_debug(char *p, struct radio_efr32_ctx_s *pv)
+{
+  efr32_radio_printk(p);
+
+  uint32_t *base = EFR32_RADIO_DEBUG_ADDR;
+  uint32_t *end = (uint32_t *)base[0];
+
+  if (pv->pdbg == NULL)
+    pv->pdbg = base + 1;
+
+  efr32_radio_printk("start 0x%x\n", pv->pdbg);
+  efr32_radio_printk("end   0x%x\n", end);
+
+  if (end < pv->pdbg)
+    return;
+
+  while(1)
+  { 
+    if (pv->pdbg == (uint32_t *)(EFR32_RADIO_DEBUG_ADDR + EFR32_RADIO_DEBUG_SIZE))
+      pv->pdbg = base + 1;
+
+    efr32_radio_printk("0x%x\n", *pv->pdbg);
+
+    pv->pdbg += 1;
+
+    if (pv->pdbg >= end)
+      break;
+  }
+}
+
+#endif
+
+void efr32_radio_seq_init(struct radio_efr32_ctx_s *pv, const uint8_t *seq, size_t count)
+{
+  assert(count < 0xFF6C);
+
+  /* Check RAC state */
+  assert(EFR32_RAC_STATUS_STATE_GET(endian_le32(cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_STATUS_ADDR))) == EFR32_RAC_STATUS_STATE_OFF);
+
+  /* Sequencer Interrupt Vector Base Address */
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_VECTADDR_ADDR, EFR32_RADIO_SEQ_RAM_ADDR);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_SEQCTRL_ADDR, 0x1);
+
+  uintptr_t p = (uintptr_t)EFR32_RADIO_SEQ_RAM_ADDR;
+
+  memcpy((uint8_t *)p, seq, count);
+
+  /* Set register R6 = sp of sequencer */
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_R_ADDR(6), EFR32_SEQ_STACK_POINTER_ADDR);
+
+  /* Init end of Seq RAM with 0 */
+  memset((uint8_t *)(p + 0x1F00), 0, 0x100);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/radio/common.h	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,119 @@
+/*
+   This file is part of MutekH.
+
+   MutekH is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; version 2.1 of the
+   License.
+
+   MutekH is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with MutekH; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.
+
+   Copyright (c) 2017 Sebastien Cerdan <sebcerdan@gmail.com>
+
+ */
+
+
+#ifndef COMMON_H_
+# define COMMON_H_
+
+#include <hexo/iospace.h>
+
+#include <mutek/printk.h>
+#include <mutek/mem_alloc.h>
+
+#include <device/device.h>
+#include <device/resources.h>
+#include <device/irq.h>
+#include <device/class/iomux.h>
+#include <device/class/cmu.h>
+#include <device/class/timer.h>
+#include <device/class/dma.h>
+#include <device/class/rfpacket.h>
+
+#include <arch/efm32/dma_source.h>
+#include <arch/efm32/irq.h>
+#include <arch/efm32/pin.h>
+#include <arch/efm32/gpio.h>
+#include <arch/efm32/devaddr.h>
+#include <arch/efm32/cmu.h>
+#include <arch/efm32/emu.h>
+#include <arch/efm32/prs.h>
+
+#include <arch/efm32/efr/frc.h>
+#include <arch/efm32/efr/rac.h>
+#include <arch/efm32/efr/bufc.h>
+#include <arch/efm32/efr/synth.h>
+#include <arch/efm32/efr/agc.h>
+#include <arch/efm32/efr/modem.h>
+#include <arch/efm32/efr/crc.h>
+
+#include "protimer.h"
+
+#ifdef CONFIG_DRIVER_EFR32_DEBUG
+# define efr32_radio_printk(...) do { printk(__VA_ARGS__); } while(0)
+#else
+# define efr32_radio_printk(...) do { } while(0)
+
+#define EFR32_RADIO_DEBUG_SIZE 0x1000
+#define EFR32_RADIO_DEBUG_ADDR (CONFIG_LOAD_ROM_RW_ADDR + 0x40000 - EFR32_RADIO_DEBUG_SIZE)
+
+#endif
+
+#define EFR32_RX_IRQ_FRC_MSK      (EFR32_FRC_IF_RXDONE     |      \
+                                   EFR32_FRC_IF_RXOF       |      \
+                                   EFR32_FRC_IF_BLOCKERROR |      \
+                                   EFR32_FRC_IF_FRAMEERROR)
+
+#define EFR32_TX_IRQ_FRC_MSK      (EFR32_FRC_IF_TXDONE     |      \
+                                   EFR32_FRC_IF_TXUF       |      \
+                                   EFR32_FRC_IF_TXABORTED  |      \
+                                   EFR32_FRC_IF_TXAFTERFRAMEDONE)
+
+#define EFR32_SEQ_DEADLINE_ADDR 0x21001F00 
+#define EFR32_RADIO_SEQ_RAM_ADDR 0x21000000
+#define EFR32_SEQ_STACK_POINTER_ADDR 0x21001F80 
+
+#define EFR32_RADIO_IRQ_COUNT 9
+#define EFR32_RADIO_HFXO_CLK 38400000L
+
+extern const unsigned char seqcode[];
+extern const size_t seqcode_size;
+
+
+struct radio_efr32_ctx_s
+{
+  struct device_s               *dev;
+
+  struct dev_irq_src_s          irq_ep[EFR32_RADIO_IRQ_COUNT];
+  struct dev_freq_s             freq;
+  dev_timer_value_t             deadline;
+
+  uint8_t                       rx_length_buffer[64];
+
+  uint32_t*                     pdbg;
+
+  /* Used for memory copy */
+  struct kroutine_s             kr;
+  struct efr32_protimer_s       pti;
+};
+
+STRUCT_COMPOSE(radio_efr32_ctx_s, kr);
+
+void efr32_radio_print_debug(char *p, struct radio_efr32_ctx_s *pv);
+void efr32_radio_dump_registers(struct radio_efr32_ctx_s *pv);
+void efr32_radio_dump_range(struct radio_efr32_ctx_s *pv, char * str, uintptr_t start, size_t size);
+void efr32_radio_debug_port(struct radio_efr32_ctx_s *pv, uint8_t val);
+void efr32_radio_debug_init(struct radio_efr32_ctx_s *pv);
+
+void efr32_radio_seq_init(struct radio_efr32_ctx_s *pv, const uint8_t *seq, size_t count);
+
+
+#endif /* !COMMON_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/radio/debug.seq	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,118 @@
+/*
+   This file is part of MutekH.
+
+   MutekH is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; version 2.1 of the
+   License.
+
+   MutekH is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with MutekH; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.
+
+   Copyright (c) 2017 Sebastien Cerdan <sebcerdan@gmail.com>
+
+ */
+
+#ifdef CONFIG_DRIVER_EFR32_DEBUG
+
+  #define DEBUG_RAM_ADDR 0x2003F000
+  #define DEBUG_RAM_SIZE 0x1000
+
+  #define PRINT_PC()
+  #define GPIO_LOG(N)                 \
+       cst32            r4, N;        \
+       call             _gpio        
+
+  #define STORE_REG(R)                 \
+       mov              r4, R;         \
+       call             _store
+
+  #define STACK_TEST(N)                                      \
+       cst32            r0, EFR32_SEQ_STACK_POINTER_ADDR;    \
+       ld.rac           r1, [EFR32_RAC_ADDR + EFR32_RAC_R_ADDR(6)];      \
+       xor              r0, r1;                              \
+       jz               __next_op##N;                        \
+       GPIO_LOG(0xe);                                        \
+  __next_op##N:	        				     \
+
+_ttg_led:        // toggle led pin
+        push             r0
+        push             r1
+
+        cst32            r1, (0x4600a000 + 0x18 + 5 * 0x30)      
+        cst32            r0, 0x00000010      
+        st               [r1], r0         
+
+        pop              r1
+        pop              r0
+        ret
+
+_gpio:          // write R4 to gpio
+        push             r0
+        push             r1
+        push             r2
+
+        /* set pin pb6 to pb9 */
+        cst32            r1, (0x4000a000 + 0xc + 1 * 0x30)
+        ld               r0, [r1]           
+        cst32            r2, 0xFFFFFC3F
+        and              r2, r0
+
+        cst32            r0, 0xF
+        and              r4, r0
+        rol              r4, 6 
+        or               r4, r2
+
+        st               [r1], r4          
+
+        pop              r2
+        pop              r1
+        pop              r0
+
+        ret
+
+_store:          // write r4 to debug memory
+        push             r0
+        push             r1
+        push             r2
+        cst32            r0, DEBUG_RAM_ADDR
+        ld               r1, [r0]
+        addi             r1, 4
+        jmp              _test_addr
+    _store_word: 
+        st               [r0], r1   
+        st               [r1], r4
+        pop              r2
+        pop              r1
+        pop              r0
+        ret
+
+_test_addr:
+/*
+        mov              r2, r1
+        ror              r1, 8
+        ror              r1, 7
+        andi             r1, 0x01            
+        jnz              _reset_addr
+        mov              r1, r2
+        */
+        jmp              _store_word
+
+_reset_addr:
+        cst32            r1, DEBUG_RAM_ADDR + 4
+        jmp              _store_word
+
+#else
+  #define PRINT_PC()
+  #define GPIO_LOG(N)
+  #define STORE_REG(R)
+  #define STACK_TEST(N)
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/radio/protimer.c	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,168 @@
+/*
+   This file is part of MutekH.
+
+   MutekH is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; version 2.1 of the
+   License.
+
+   MutekH is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with MutekH; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.
+
+   Copyright (c) 2017 Sebastien Cerdan <sebcerdan@gmail.com>
+
+ */
+
+#include "protimer.h"
+
+void efr32_protimer_disable_compare(struct efr32_protimer_s *pv, uint8_t channel)
+{
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CC_CTRL_ADDR(channel), 0);
+}
+
+dev_timer_value_t efr32_protimer_get_value(struct efr32_protimer_s *pv)
+{
+  uint32_t basepre = endian_le32(cpu_mem_read_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_BASEPRE_ADDR));
+  uint64_t wrap = endian_le32(cpu_mem_read_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_LWRAPCNT_ADDR));
+#if EFR32_PROTIMER_HW_WIDTH < 64
+  uint16_t pre  = basepre & EFR32_PRECNT_MASK;
+  uint32_t base = ((basepre >> 16) & EFR32_BASECNT_MASK) << EFR32_PRECNT_WIDTH;
+  basepre = base | pre;
+#endif
+
+  dev_timer_value_t value = (wrap << (EFR32_PRECNT_WIDTH + EFR32_BASECNT_WIDTH)) | basepre;
+
+#if EFR32_PROTIMER_HW_WIDTH < 64
+  if (value < EFR32_PROTIMER_HW_MASK / 2)      /* check if a wrap just occured */
+    {
+      uint32_t x = endian_le32(cpu_mem_read_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IF_ADDR));
+      if (x & EFR32_PROTIMER_IF_WRAPCNTOF)
+        value += 1ULL << EFR32_PROTIMER_HW_WIDTH;
+    }
+  value += (pv->swvalue << EFR32_PROTIMER_HW_WIDTH);
+#endif
+  return value;
+}
+
+bool_t efr32_protimer_request_start(struct efr32_protimer_s *pv,
+                                    dev_timer_value_t value,
+                                    dev_timer_value_t deadline,
+                                    uint8_t channel)
+{
+#if EFR32_PROTIMER_HW_WIDTH < 64
+  /* enable hw comparator if software part of the counter match */
+  if (((deadline ^ value) & EFR32_PROTIMER_SW_MASK))
+    return 0;
+#endif
+
+  /* Disable channel compare */
+  efr32_protimer_disable_compare(pv, channel);
+
+  /* Write value for comparaison */
+  uint32_t v = deadline & EFR32_PRECNT_MASK;
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CC_PRE_ADDR(channel),
+                   endian_le32(v));
+  
+  v = (deadline >> EFR32_PRECNT_WIDTH) & EFR32_BASECNT_MASK;
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CC_BASE_ADDR(channel),
+                   endian_le32(v));
+
+  v = deadline >> (EFR32_PRECNT_WIDTH + EFR32_BASECNT_WIDTH); 
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CC_WRAP_ADDR(channel),
+                   endian_le32(v));
+
+  v = EFR32_PROTIMER_CC_CTRL_ENABLE |
+      EFR32_PROTIMER_CC_CTRL_CCMODE(COMPARE) |
+      EFR32_PROTIMER_CC_CTRL_PREMATCHEN |
+      EFR32_PROTIMER_CC_CTRL_BASEMATCHEN |
+      EFR32_PROTIMER_CC_CTRL_WRAPMATCHEN ;
+
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CC_CTRL_ADDR(channel),
+                   endian_le32(v));
+
+  /* hw compare for == only, check for race condition */
+  if (deadline <= efr32_protimer_get_value(pv))
+    {
+      uint32_t x = EFR32_PROTIMER_IF_CC(channel);
+      cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IFS_ADDR, x);
+      return 1;
+    } 
+
+  return 0;
+}
+
+void efr32_protimer_stop_counter(struct efr32_protimer_s *pv)
+{
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CMD_ADDR, endian_le32(EFR32_PROTIMER_CMD_STOP));
+#ifdef CONFIG_DEVICE_CLOCK_GATING
+  if (endian_le32(cpu_mem_read_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IF_ADDR))
+      & (EFR32_PROTIMER_IF_CC(EFR32_PROTIMER_CHANNEL) | EFR32_PROTIMER_IF_WRAPCNTOF))
+    return;
+  dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER);
+#endif
+}
+
+void efr32_protimer_start_counter(struct efr32_protimer_s *pv)
+{
+#ifdef CONFIG_DEVICE_CLOCK_GATING
+  dev_clock_sink_gate(&pv->clk_ep, DEV_CLOCK_EP_POWER_CLOCK);
+#endif
+
+  uint32_t x = cpu_mem_read_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CTRL_ADDR);
+
+  EFR32_PROTIMER_CTRL_PRECNTSRC_SET(x, CLOCK);
+  EFR32_PROTIMER_CTRL_BASECNTSRC_SET(x, PRECNTOF);
+  EFR32_PROTIMER_CTRL_WRAPCNTSRC_SET(x, BASECNTOF);
+
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CTRL_ADDR, x);
+
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_PRECNT_ADDR, 0);
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_BASECNT_ADDR, 0);
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_WRAPCNT_ADDR, 0);
+
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_PRECNTTOP_ADDR, EFR32_PRECNT_MASK << 8);
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_BASECNTTOP_ADDR, EFR32_BASECNT_MASK);
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_WRAPCNTTOP_ADDR, 0xFFFFFFFF);
+
+  /* Start counter */
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CMD_ADDR, endian_le32(EFR32_PROTIMER_CMD_START));
+}
+
+void efr32_protimer_init(struct efr32_protimer_s *pv)
+{
+  /* Timer init */
+
+  pv->cap = DEV_TIMER_CAP_HIGHRES | 
+            DEV_TIMER_CAP_REQUEST |
+            DEV_TIMER_CAP_TICKLESS |
+            DEV_TIMER_CAP_STOPPABLE |
+            DEV_TIMER_CAP_KEEPVALUE;
+
+# ifdef CONFIG_DEVICE_CLOCK_VARFREQ
+  if (pv->clk_ep.flags & DEV_CLOCK_EP_VARFREQ)
+    pv->cap |= DEV_TIMER_CAP_VARFREQ | DEV_TIMER_CAP_CLKSKEW;
+# endif
+
+  /* Stop timer */
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CMD_ADDR, EFR32_PROTIMER_CMD_STOP);
+
+  /* Enable interrupts */
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IFC_ADDR, EFR32_PROTIMER_IFC_MASK);
+
+  uint32_t x = EFR32_PROTIMER_IF_CC(EFR32_PROTIMER_CHANNEL);
+#if EFR32_PROTIMER_HW_WIDTH < 64
+  x |= EFR32_PROTIMER_IF_WRAPCNTOF;
+#endif
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IEN_ADDR, x);
+
+#if EFR32_PROTIMER_HW_WIDTH < 64
+  pv->swvalue = 0;
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/radio/protimer.h	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,64 @@
+/*
+   This file is part of MutekH.
+
+   MutekH is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; version 2.1 of the
+   License.
+
+   MutekH is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with MutekH; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.
+
+   Copyright (c) 2017 Sebastien Cerdan <sebcerdan@gmail.com>
+
+ */
+
+#ifndef PROTIMER_H_
+# define PROTIMER_H_
+
+#include <hexo/iospace.h>
+#include <device/device.h>
+#include <device/resources.h>
+#include <device/class/timer.h>
+#include <device/class/cmu.h>
+
+#include <arch/efm32/devaddr.h>
+#include <arch/efm32/efr/protimer.h>
+
+/* Timer class parameters */
+#define EFR32_PROTIMER_CHANNEL           0
+#define EFR32_PRECNT_WIDTH               16
+#define EFR32_PRECNT_MASK                ((1 << EFR32_PRECNT_WIDTH) - 1)
+#define EFR32_BASECNT_WIDTH              16
+#define EFR32_BASECNT_MASK               ((1 << EFR32_BASECNT_WIDTH) - 1)
+#define EFR32_PROTIMER_HW_WIDTH          (32 + EFR32_BASECNT_WIDTH + EFR32_PRECNT_WIDTH)
+
+struct efr32_protimer_s
+{
+#if EFR32_PROTIMER_HW_WIDTH < 64
+  uint64_t                       swvalue;
+#endif
+  /* Timer queue */
+  dev_request_pqueue_root_t      queue;
+  dev_timer_cfgrev_t             rev;
+  enum dev_timer_capabilities_e  cap:8;
+  struct dev_clock_sink_ep_s     clk_ep;
+};
+
+void efr32_protimer_stop_counter(struct efr32_protimer_s *pv);
+void efr32_protimer_start_counter(struct efr32_protimer_s *pv);
+void efr32_protimer_init(struct efr32_protimer_s *pv);
+void efr32_protimer_disable_compare(struct efr32_protimer_s *pv, uint8_t channel);
+
+dev_timer_value_t efr32_protimer_get_value(struct efr32_protimer_s *pv);
+bool_t efr32_protimer_request_start(struct efr32_protimer_s *pv, dev_timer_value_t value,
+                                          dev_timer_value_t deadline, uint8_t channel);
+
+#endif /* !PROTIMER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/radio/radio.config	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,21 @@
+%config CONFIG_DRIVER_EFR32_RADIO
+  desc Enable EFR32 Radio Frequency driver
+  parent CONFIG_ARCH_EFM32
+  require CONFIG_EFM32_ARCHREV=EFM32_ARCHREV_EFR_XG12
+%config end
+
+%config CONFIG_DRIVER_EFR32_BLE_ADVERTISE
+  desc Enable EFR32 ble advertise support
+  parent CONFIG_DRIVER_EFR32_RADIO
+  depend CONFIG_BLE
+%config end
+
+%config CONFIG_DRIVER_EFR32_RFPACKET
+  desc Enable EFR32 rfpacket driver 
+  parent CONFIG_DRIVER_EFR32_RADIO
+%config end
+
+%config CONFIG_DRIVER_EFR32_DEBUG
+  desc Enable EFR32 debug support
+  parent CONFIG_DRIVER_EFR32_RADIO
+%config end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/radio/rfpacket.c	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,1788 @@
+/*
+   This file is part of MutekH.
+
+   MutekH is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; version 2.1 of the
+   License.
+
+   MutekH is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with MutekH; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.
+
+   Copyright (c) 2017 Sebastien Cerdan <sebcerdan@gmail.com>
+
+ */
+
+#include "common.h"
+#include "protimer.h"
+
+/* LBT parameters */
+#define EFR32_ETSI_LBT_TIME              5000ULL     /*us*/
+#define EFR32_MAX_LBT_RETRY_COUNT        4
+
+/* Protimer Radio class parameters */  
+#define EFR32_PROTIMER_RX_START_CHANNEL  1
+#define EFR32_PROTIMER_RX_STOP_CHANNEL   2
+#define EFR32_PROTIMER_TX_CHANNEL        3
+
+#define EFR32_RADIO_THRESHOLD 16
+
+#define EFR32_RADIO_RFP_BUFFER_SIZE 256
+
+enum efr32_radio_rfp_state
+{
+  EFR32_RFP_STATE_IDLE,
+  EFR32_RFP_STATE_RX,
+  EFR32_RFP_STATE_RX_PENDING_RX,
+  EFR32_RFP_STATE_RX_DONE_PENDING_RX,
+  EFR32_RFP_STATE_RXC,                             /* 4 */
+  EFR32_RFP_STATE_RXC_STOPPING_PENDING_RX,
+  EFR32_RFP_STATE_RXC_PENDING_RX,
+  EFR32_RFP_STATE_TX,
+  EFR32_RFP_STATE_TX_LBT,                          /* 8 */
+};
+
+DRIVER_PV(struct radio_efr32_rfp_ctx_s
+{
+  struct radio_efr32_ctx_s      pv;
+
+  dev_timer_value_t             deadline;
+  dev_request_queue_root_t      queue;
+  struct dev_rfpacket_rq_s      *rx_cont;
+  struct dev_rfpacket_rq_s      *next_rx_cont;
+  struct dev_rfpacket_rx_s      *rx;
+  uint8_t                       sg_buffer[EFR32_RADIO_RFP_BUFFER_SIZE];
+  enum efr32_radio_rfp_state    state;
+  /* Current config */
+  const struct dev_rfpacket_rf_cfg_s *rf_cfg;
+  const struct dev_rfpacket_pk_cfg_s *pk_cfg;
+});
+
+STRUCT_COMPOSE(radio_efr32_rfp_ctx_s, pv);
+
+static void efr32_rfp_idle(struct radio_efr32_rfp_ctx_s *ctx);
+static void efr32_rfp_timer_irq(struct device_s *dev);
+static void efr32_rfp_end_rq(struct radio_efr32_rfp_ctx_s *ctx, error_t err);
+static error_t efr32_rfp_init(struct radio_efr32_rfp_ctx_s *ctx);
+
+static void efr32_radio_set_state(struct radio_efr32_rfp_ctx_s *pv, enum efr32_radio_rfp_state state)
+{
+  efr32_radio_printk("drv: st %d\n", state);
+  pv->state = state;
+}
+
+static inline error_t efr32_rf_config(struct radio_efr32_rfp_ctx_s *ctx,
+                                      struct dev_rfpacket_rq_s *rq)
+{
+  const struct dev_rfpacket_rf_cfg_s *rfcfg = rq->rf_cfg;
+
+  if ((rfcfg != ctx->rf_cfg) || rfcfg->cache.dirty)
+  /* Test if new RF configuration or previous configuration modified */
+    {
+      ctx->rf_cfg = (struct dev_rfpacket_rf_cfg_s *)rfcfg;
+
+      if (rfcfg->mod != DEV_RFPACKET_GFSK)
+	return -ENOTSUP;
+
+      if (rfcfg->frequency != 868000000)
+	return -ENOTSUP;
+
+      if (rfcfg->drate != 38400)
+	return -ENOTSUP;
+    }
+
+  return 0;
+}
+
+static inline error_t efr32_pkt_config(struct radio_efr32_rfp_ctx_s *ctx,
+                                       struct dev_rfpacket_rq_s *rq)
+{
+  const struct dev_rfpacket_pk_cfg_s *pkcfg = rq->pk_cfg;
+
+  /* Test if new Packet configuration or previous configuration modified */
+  if ((pkcfg == ctx->pk_cfg) && !pkcfg->cache.dirty)
+    return 0;
+
+  ctx->pk_cfg = (struct dev_rfpacket_pk_cfg_s *)pkcfg;
+
+  if (rq->pk_cfg->format != DEV_RFPACKET_FMT_SLPC)
+    return -ENOTSUP;
+
+  const struct dev_rfpacket_pk_cfg_basic_s *cfg = const_dev_rfpacket_pk_cfg_basic_s_cast(rq->pk_cfg);
+
+  /** Configure Sync Word */
+
+  uint8_t sw = cfg->sw_len + 1;
+
+  if ((sw >> 5) || (sw % 4))
+    return -ENOTSUP;
+  
+  uint32_t x = EFR32_MODEM_CTRL1_SYNCBITS(cfg->sw_len);
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CTRL1_ADDR, x);
+
+  x = cfg->sw_value;
+
+  x = ((x & 0x55555555) << 1) | ((0xAAAAAAAA & x) >> 1);
+  x = ((x & 0x33333333) << 2) | ((0xCCCCCCCC & x) >> 2);
+  x = ((x & 0x0F0F0F0F) << 4) | ((0xF0F0F0F0 & x) >> 4);
+  x = ((x & 0xFF00FF00) >> 8) | ((0x00FF00FF & x) << 8);
+  x = ((x & 0xFFFF0000) >> 16) | ((0x0000FFFF & x) << 16);
+  x = x >> (32 - sw);
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SYNC0_ADDR, x);
+
+  /** Configure Preamble */
+
+  if ((cfg->pb_pattern_len + 1) >> 4)
+    return -ENOTSUP;
+
+  x = EFR32_MODEM_PRE_BASE(cfg->pb_pattern_len);
+
+  uint32_t msk = (1 << (cfg->pb_pattern_len + 1)) - 1;
+  uint32_t preamble = cfg->pb_pattern & msk;
+
+  if (preamble == (0xAAAAAAAA & msk))
+    EFR32_MODEM_PRE_BASEBITS_SET(x, 1); /* TYPE 1010 */
+  else if (preamble == (0x55555555 & msk))
+    EFR32_MODEM_PRE_BASEBITS_SET(x, 0); /* TYPE 0101 */
+  else
+    return -ENOTSUP;
+
+  EFR32_MODEM_PRE_TXBASES_SET(x, cfg->tx_pb_len/(cfg->pb_pattern_len + 1));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_PRE_ADDR, x);
+
+  /** Configure CRC */
+
+  x =  EFR32_CRC_CTRL_BITSPERWORD(7) |
+       EFR32_CRC_CTRL_INPUTBITORDER(MSB) |
+       EFR32_CRC_CTRL_BITREVERSE(LSB);
+
+
+  uint32_t w;
+
+  switch (cfg->crc)
+    {
+    case 0:
+    case 0x07:
+      w = EFR32_CRC_CTRL_CRCWIDTH_CRCWIDTH8;
+      break;
+    case 0x8005:
+    case 0x1021:
+    case 0x3d65: 
+      w = EFR32_CRC_CTRL_CRCWIDTH_CRCWIDTH16;
+      break;
+    case 0x65b:  
+      w = EFR32_CRC_CTRL_CRCWIDTH_CRCWIDTH24;
+      break;
+    case 0x814141ab:
+    case 0x04c11db7:
+      w = EFR32_CRC_CTRL_CRCWIDTH_CRCWIDTH32;
+      break;
+    default:
+      return -ENOTSUP;
+    }
+
+  x |= (w << EFR32_CRC_CTRL_CRCWIDTH_IDX);
+
+  cpu_mem_write_32(EFR32_CRC_ADDR + EFR32_CRC_CTRL_ADDR, x);
+
+  /* Reverse bits */
+
+  uint32_t v = cfg->crc;
+  x = 0;
+
+  for (uint8_t i = 0; i < ((w + 1) << 3); i++)
+    {
+      x <<= 1;
+      x = v & 1 ? x | 1 : x;
+      v >>= 1;
+    }
+
+  cpu_mem_write_32(EFR32_CRC_ADDR + EFR32_CRC_POLY_ADDR, x);
+  cpu_mem_write_32(EFR32_CRC_ADDR + EFR32_CRC_INIT_ADDR, 0x0);
+
+  return 0;
+}
+
+static void efr32_rfp_set_cca_threshold(struct radio_efr32_rfp_ctx_s *ctx, struct dev_rfpacket_rq_s *rq)
+{
+  const struct dev_rfpacket_rf_cfg_fsk_s * c = const_dev_rfpacket_rf_cfg_fsk_s_cast(rq->rf_cfg);
+
+  int16_t r = c->fairtx.lbt.rssi >> 3;
+  int8_t v = (r & 0x7F) | (r < 0 ? 0x80 : 0); 
+
+  /* Saturate rssi threshold */
+  if (r < -128)
+    v = -128;
+
+  if (r > 127)
+    v = 127;
+
+  uint32_t x = cpu_mem_read_32(EFR32_AGC_ADDR + EFR32_AGC_CTRL1_ADDR);
+  EFR32_AGC_CTRL1_CCATHRSH_SET(x, v & 0xFF);
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_CTRL1_ADDR, x);
+}
+
+
+static void efr32_rfp_start_tx_lbt(struct radio_efr32_rfp_ctx_s *ctx, struct dev_rfpacket_rq_s *rq)
+{
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_TOUTCNTTOP_ADDR(0), EFR32_PROTIMER_TOUTCNTTOP_PCNTTOP(4));
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_TOUTCOMP_ADDR(0), EFR32_PROTIMER_TOUTCOMP_PCNTCOMP(1));
+
+  /* Time granularity is based on T0UF */
+
+  uint32_t x = /* Time between 2 retries */
+               EFR32_PROTIMER_LBTCTRL_FIXEDBACKOFF |
+               EFR32_PROTIMER_LBTCTRL_STARTEXP(1) |
+               EFR32_PROTIMER_LBTCTRL_MAXEXP(1) |
+               /* Number of consecutive successfull CCA before generating LBT success */ 
+               EFR32_PROTIMER_LBTCTRL_CCAREPEAT(1) |
+               /* Time between 2 CCA measures */
+               EFR32_PROTIMER_LBTCTRL_CCADELAY(1) |
+               /* Number of CCA failure before generating LBTFAILURE */ 
+               EFR32_PROTIMER_LBTCTRL_RETRYLIMIT(EFR32_MAX_LBT_RETRY_COUNT - 1);
+
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_LBTCTRL_ADDR, x);
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_RANDOM_ADDR, 1);
+
+#if (CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12)
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_LBTSTATE1_ADDR, EFR32_PROTIMER_LBTSTATE1_EXP(1));
+#endif
+
+  x = EFR32_PROTIMER_RXCTRL_RXSETEVENT(0, ALWAYS) |
+      EFR32_PROTIMER_RXCTRL_RXCLREVENT(0, ALWAYS) |
+
+      EFR32_PROTIMER_RXCTRL_RXSETEVENT(1, TOUT0MATCHLBT) |     
+      EFR32_PROTIMER_RXCTRL_RXCLREVENT(1, CCAACK);
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_RXCTRL_ADDR, x);
+
+  x = EFR32_PROTIMER_TXCTRL_TXSETEVENT(0, ALWAYS) |
+      EFR32_PROTIMER_TXCTRL_TXSETEVENT(1, LBTSUCCESS);
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_TXCTRL_ADDR, x);
+
+  uint32_t nbsym = (EFR32_ETSI_LBT_TIME * rq->rf_cfg->drate)/1000000;
+  nbsym = bit_ctz(pow2_up(nbsym));
+
+  assert(nbsym < 15);
+
+  /* Configure AGC */
+  x = cpu_mem_read_32(EFR32_AGC_ADDR + EFR32_AGC_CTRL0_ADDR);
+  EFR32_AGC_CTRL0_MODE_SET(x, CONT);
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_CTRL0_ADDR, x);
+
+  x = cpu_mem_read_32(EFR32_AGC_ADDR + EFR32_AGC_CTRL1_ADDR);
+  EFR32_AGC_CTRL1_RSSIPERIOD_SET(x, nbsym);
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_CTRL1_ADDR, x);
+
+  efr32_rfp_set_cca_threshold(ctx, rq);
+
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CMD_ADDR, EFR32_PROTIMER_CMD_LBTSTART);
+}
+
+static void efr32_rfp_try_restart_tx(struct radio_efr32_rfp_ctx_s *ctx)
+{
+  dev_timer_value_t time = efr32_protimer_get_value(&ctx->pv.pti);
+
+  struct dev_rfpacket_rq_s *rq = dev_rfpacket_rq_s_cast(dev_request_queue_head(&ctx->queue));
+
+  assert(rq->type == DEV_RFPACKET_RQ_TX_FAIR);
+
+  if (ctx->deadline <= time)
+  /* Deadline reached */
+    {
+      efr32_rfp_end_rq(ctx, -ETIMEDOUT);
+      return;
+    }
+
+  efr32_rfp_start_tx_lbt(ctx, rq);
+}
+
+static void efr32_rfp_start_tx(struct radio_efr32_rfp_ctx_s *ctx)
+{
+  cpu_mem_write_32(EFR32_SEQ_DEADLINE_ADDR, 0);
+
+  struct dev_rfpacket_rq_s *rq;
+  rq = dev_rfpacket_rq_s_cast(dev_request_queue_head(&ctx->queue));
+
+  assert(rq);
+
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+  dev_timer_value_t time = efr32_protimer_get_value(&pv->pti);
+  dev_timer_value_t start = rq->deadline ? rq->deadline : time;
+
+  /* Check RAC state */
+  uint32_t x = endian_le32(cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_STATUS_ADDR));
+  assert(EFR32_RAC_STATUS_STATE_GET(x) == EFR32_RAC_STATUS_STATE_OFF);
+
+  /* Clear buffer */
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(0), EFR32_BUFC_CMD_CLEAR); 
+
+  /* Fill buffer */
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_WRITEDATA_ADDR(0), rq->tx_size);
+
+  uint8_t *p = (uint8_t *)rq->tx_buf;
+
+  for(uint16_t i = 0; i < rq->tx_size; i++)
+    cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_WRITEDATA_ADDR(0), (uint32_t)p[i]);
+
+  /* Set channel */
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_CHCTRL_ADDR, rq->channel); 
+
+  /* Enable TX */
+  switch (rq->type)
+    {
+      case DEV_RFPACKET_RQ_TX:
+        cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_CMD_ADDR, EFR32_RAC_CMD_TXEN);
+        break;
+      case DEV_RFPACKET_RQ_TX_FAIR:
+        ctx->deadline = start + rq->lifetime;
+        efr32_rfp_start_tx_lbt(ctx, rq);
+        break;
+      default:
+        abort();
+    }
+}
+
+static void efr32_rfp_disable(struct radio_efr32_rfp_ctx_s *ctx)
+{
+  /* Disable RX */
+  uint32_t x = cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_RXENSRCEN_ADDR);
+  x &= ~0xF;
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_RXENSRCEN_ADDR, 0);
+  
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_CMD_ADDR, EFR32_FRC_CMD_RXABORT);
+
+  /* Disable TX */
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_CMD_ADDR, EFR32_RAC_CMD_TXDIS);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_FORCESTATE_ADDR, EFR32_RAC_STATUS_STATE_OFF);
+
+  /* Check RAC state */
+  while(1)
+  /* Use state change interrupt here or schedule a timer interrupt instead of active waiting */
+    {
+      x = endian_le32(cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_STATUS_ADDR));
+      if (EFR32_RAC_STATUS_STATE_GET(x) == EFR32_RAC_STATUS_STATE_OFF)
+        break;
+    }
+
+  /* Clear irq */
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_IF_ADDR, 0);
+}
+
+static void efr32_rfp_start_rx_scheduled(struct radio_efr32_rfp_ctx_s *ctx, struct dev_rfpacket_rq_s *rq)
+{
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+ 
+#if EFR32_PROTIMER_HW_WIDTH < 64
+  assert(0);
+#endif
+  dev_timer_value_t time = efr32_protimer_get_value(&pv->pti);
+  dev_timer_value_t start = rq->deadline ? rq->deadline : time;
+  
+  ctx->deadline = start + rq->lifetime;
+
+  if (ctx->deadline < time)
+  /* Deadline reached */
+    return efr32_rfp_end_rq(ctx, 0);
+ 
+  uint32_t x = EFR32_PROTIMER_RXCTRL_RXSETEVENT(0, ALWAYS) |
+               EFR32_PROTIMER_RXCTRL_RXCLREVENT(0, ALWAYS) |
+               EFR32_PROTIMER_RXCTRL_RXSETEVENT(1, CC1)    |     
+               EFR32_PROTIMER_RXCTRL_RXCLREVENT(1, CC2);
+
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_RXCTRL_ADDR, x);
+
+  /* RX scheduled looks not to work as expected if no minimal delay */
+  if ((start <= time) || (start - time) < 128)
+    start = time + 128;
+
+  efr32_protimer_request_start(&pv->pti, time, start, EFR32_PROTIMER_RX_START_CHANNEL);
+  efr32_protimer_request_start(&pv->pti, time, ctx->deadline, EFR32_PROTIMER_RX_STOP_CHANNEL);
+}
+
+static void efr32_rfp_start_rx(struct radio_efr32_rfp_ctx_s *ctx, struct dev_rfpacket_rq_s *rq)
+{
+  uint32_t x;
+  cpu_mem_write_32(EFR32_SEQ_DEADLINE_ADDR, 0);
+  /* Check RAC state */
+  x = endian_le32(cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_STATUS_ADDR));
+  assert(EFR32_RAC_STATUS_STATE_GET(x) == EFR32_RAC_STATUS_STATE_OFF);
+  /* Clear buffer */
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(1), EFR32_BUFC_CMD_CLEAR); 
+
+  switch (rq->type)
+  {
+    case DEV_RFPACKET_RQ_RX_CONT:
+      assert(ctx->rx_cont);
+      efr32_radio_set_state(ctx, EFR32_RFP_STATE_RXC);
+      /* Enable RX */
+      x = cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_RXENSRCEN_ADDR);
+      x |= 0x2;
+      cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_RXENSRCEN_ADDR, x);
+      break;
+    case DEV_RFPACKET_RQ_RX:
+      efr32_radio_set_state(ctx, EFR32_RFP_STATE_RX);
+      /* Scheduled RX */
+      efr32_rfp_start_rx_scheduled(ctx, rq);
+      break;
+    default:
+      assert(1);
+  }
+}
+
+
+static inline void efr32_rfp_process_group(struct radio_efr32_rfp_ctx_s *ctx, bool_t group)
+{
+  struct dev_rfpacket_rq_s * rq;
+
+  while (1)
+  {
+    rq = dev_rfpacket_rq_s_cast(dev_request_queue_head(&ctx->queue));
+
+    if (!rq || rq->err_group != group)
+      break;
+
+    rq->err = -ECANCELED;
+    dev_request_queue_pop(&ctx->queue);
+    kroutine_exec(&rq->base.kr);
+  }
+}
+
+static void efr32_rfp_test_timeout(struct radio_efr32_rfp_ctx_s *ctx)
+{
+  efr32_radio_set_state(ctx, EFR32_RFP_STATE_RX);
+
+  dev_timer_value_t time = efr32_protimer_get_value(&ctx->pv.pti);
+
+  if (ctx->deadline <= time)
+    {
+      efr32_rfp_end_rq(ctx, 0);
+      return;
+    }
+}
+
+static void efr32_rfp_read_done(struct radio_efr32_rfp_ctx_s *ctx)
+{
+  switch (ctx->state)
+    {
+      case EFR32_RFP_STATE_RX_DONE_PENDING_RX:
+        efr32_rfp_idle(ctx);
+        break;
+      case EFR32_RFP_STATE_RX_PENDING_RX:
+      case EFR32_RFP_STATE_RX:
+        efr32_rfp_test_timeout(ctx);
+        break;
+      case EFR32_RFP_STATE_RXC:
+      case EFR32_RFP_STATE_RXC_PENDING_RX:
+        assert(ctx->rx_cont);
+        efr32_rfp_idle(ctx);
+        break;
+      case EFR32_RFP_STATE_RXC_STOPPING_PENDING_RX:
+        /* Radio is disabled here */
+        assert(ctx->rx_cont);
+        if (ctx->next_rx_cont != ctx->rx_cont)
+          {
+            kroutine_exec(&ctx->rx_cont->base.kr);
+            ctx->rx_cont = ctx->next_rx_cont;
+          }
+        ctx->next_rx_cont = NULL;
+        efr32_rfp_idle(ctx);
+        break;
+      default:
+        abort();
+    }
+}
+
+static void efr32_rfp_read_packet(struct radio_efr32_rfp_ctx_s *ctx, bool_t locked)
+{
+  struct dev_rfpacket_rx_s *rx = ctx->rx;
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+
+  rx->timestamp = 0;
+  rx->snr = 0;
+  rx->err = 0;
+  rx->carrier = 0;
+ 
+  uint8_t *p = (uint8_t *)rx->buf;
+
+  /* Read packet */
+  for (uint16_t i = 0; i < rx->size; i++)
+    p[i] = cpu_mem_read_32(EFR32_BUFC_ADDR + EFR32_BUFC_READDATA_ADDR(1));
+
+  rx->rssi = cpu_mem_read_32(EFR32_BUFC_ADDR + EFR32_BUFC_READDATA_ADDR(1));
+
+  kroutine_exec(&rx->kr);
+
+  if (locked)
+    return efr32_rfp_read_done(ctx);
+  
+  LOCK_SPIN_IRQ(&pv->dev->lock);
+  efr32_rfp_read_done(ctx);
+  LOCK_RELEASE_IRQ(&pv->dev->lock);
+}
+
+static KROUTINE_EXEC(efr32_rfp_tx)
+{
+  struct radio_efr32_ctx_s *pv = radio_efr32_ctx_s_from_kr(kr);
+  struct radio_efr32_rfp_ctx_s *ctx = radio_efr32_rfp_ctx_s_from_pv(pv);
+
+  efr32_rfp_start_tx(ctx);
+}
+
+static KROUTINE_EXEC(efr32_rfp_rx)
+{
+  struct radio_efr32_ctx_s *pv = radio_efr32_ctx_s_from_kr(kr);
+  struct radio_efr32_rfp_ctx_s *ctx = radio_efr32_rfp_ctx_s_from_pv(pv);
+
+  efr32_rfp_read_packet(ctx, 0);
+}
+
+static void efr32_rfp_end_rq(struct radio_efr32_rfp_ctx_s *ctx, error_t err)
+{
+  struct dev_rfpacket_rq_s * rq = dev_rfpacket_rq_s_cast(dev_request_queue_head(&ctx->queue));
+
+  assert(rq && rq->type != DEV_RFPACKET_RQ_RX_CONT);
+
+  dev_request_queue_pop(&ctx->queue);
+  kroutine_exec(&rq->base.kr);
+
+  rq->err = err;
+
+  if (rq->err)
+    efr32_rfp_process_group(ctx, rq->err_group);
+
+  /* Timeout has occured before we fill RX fifo */
+  if (ctx->state == EFR32_RFP_STATE_RX_PENDING_RX)
+    return efr32_radio_set_state(ctx, EFR32_RFP_STATE_RX_DONE_PENDING_RX);
+
+  return efr32_rfp_idle(ctx);
+}
+
+static void efr32_rfp_rx_error(struct radio_efr32_rfp_ctx_s *ctx)
+{
+  /* Flush RX fifo */
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(1), EFR32_BUFC_CMD_CLEAR);
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(2), EFR32_BUFC_CMD_CLEAR);
+
+  switch (ctx->state)
+    {
+      case EFR32_RFP_STATE_RXC:
+        return efr32_rfp_idle(ctx);
+      case EFR32_RFP_STATE_RX:
+        return efr32_rfp_test_timeout(ctx);
+      case EFR32_RFP_STATE_TX_LBT:
+      case EFR32_RFP_STATE_IDLE:
+        return;
+      default:
+        abort();
+    }
+}
+static void efr32_rfp_rx_irq(struct radio_efr32_rfp_ctx_s *ctx, uint32_t irq)
+{
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+  struct dev_rfpacket_rq_s *rq = NULL;
+
+  uint32_t x = endian_le32(cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_STATUS_ADDR));
+  x = EFR32_RAC_STATUS_STATE_GET(x);  
+
+  if (irq != EFR32_FRC_IF_RXDONE)
+    return efr32_rfp_rx_error(ctx);
+  
+   switch (ctx->state)
+   {
+     case EFR32_RFP_STATE_TX_LBT:
+     case EFR32_RFP_STATE_IDLE:
+       return efr32_rfp_rx_error(ctx);
+     case EFR32_RFP_STATE_RXC:
+       rq = ctx->rx_cont;
+       break;
+     case EFR32_RFP_STATE_RX:
+       rq = dev_rfpacket_rq_s_cast(dev_request_queue_head(&ctx->queue));
+       break;
+     default:
+       abort();
+   }
+
+  assert(rq);
+
+  uint16_t size = cpu_mem_read_32(EFR32_BUFC_ADDR + EFR32_BUFC_READDATA_ADDR(1));
+
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(2), EFR32_BUFC_CMD_CLEAR);
+
+  uint32_t status = cpu_mem_read_32(EFR32_BUFC_ADDR + EFR32_BUFC_STATUS_ADDR(1));
+  status = EFR32_BUFC_STATUS_BYTES_GET(status);
+
+  assert(EFR32_BUFC_STATUS_BYTES_GET(status) >= size);
+
+  struct dev_rfpacket_rx_s * rx = rq->rx_alloc(rq, size);
+  
+  if (rx == NULL || rx->size != size)
+  /* Flush RX fifo */
+    {
+      cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(1), EFR32_BUFC_CMD_CLEAR);
+      cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(2), EFR32_BUFC_CMD_CLEAR);
+
+      switch (ctx->state)
+      {
+        case EFR32_RFP_STATE_RXC:
+          return efr32_rfp_idle(ctx);
+        case EFR32_RFP_STATE_RX:
+          return efr32_rfp_test_timeout(ctx);
+        default:
+          abort();
+      }
+    }
+
+  ctx->rx = rx;
+  rx->channel = rq->channel;
+  
+  if (size <= EFR32_RADIO_THRESHOLD)
+    return efr32_rfp_read_packet(ctx, 1);
+
+  switch (ctx->state)
+  {
+    case EFR32_RFP_STATE_RXC:
+      efr32_radio_set_state(ctx, EFR32_RFP_STATE_RXC_PENDING_RX);
+      break;
+    case EFR32_RFP_STATE_RX:
+      efr32_radio_set_state(ctx, EFR32_RFP_STATE_RX_PENDING_RX);
+      break;
+    default:
+      abort();
+  }
+
+  kroutine_init_deferred(&pv->kr, &efr32_rfp_rx);
+  kroutine_exec(&pv->kr);
+}
+
+static inline void efr32_rfp_tx_irq(struct radio_efr32_rfp_ctx_s *ctx, uint32_t irq)
+{
+  struct dev_rfpacket_rq_s *rq = dev_rfpacket_rq_s_cast(dev_request_queue_head(&ctx->queue));
+  assert(rq);
+
+  switch (ctx->state)
+  {
+    case EFR32_RFP_STATE_TX_LBT:
+    case EFR32_RFP_STATE_TX:
+      break;
+    default:
+      abort();
+  }
+
+  if (irq & EFR32_FRC_IF_TXDONE)
+  /* Packet sent */
+    {
+      /* Set timestamp */
+      rq->err = 0;
+      rq->tx_timestamp = 0;
+    }
+  else
+    /* Clear buffer */
+    cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(0), EFR32_BUFC_CMD_CLEAR);
+
+  return efr32_rfp_end_rq(ctx, 0);
+}
+
+static DEV_IRQ_SRC_PROCESS(efr32_radio_irq)
+{
+  struct device_s *dev = ep->base.dev;
+  struct radio_efr32_rfp_ctx_s *ctx = dev->drv_pv;
+
+  lock_spin(&dev->lock);
+
+  uint32_t irq = 0;
+
+  switch (ep - ctx->pv.irq_ep)
+  {
+    case 0:
+      irq = cpu_mem_read_32(EFR32_MODEM_ADDR + EFR32_MODEM_IF_ADDR);
+      irq &= cpu_mem_read_32(EFR32_MODEM_ADDR + EFR32_MODEM_IEN_ADDR);
+      cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_IFC_ADDR, irq);
+      efr32_radio_printk("modem irq: 0x%x\n", irq);
+      break;
+    case 1:
+    case 2:
+      irq = cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_IF_ADDR);
+      irq &= cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_IEN_ADDR);
+      efr32_radio_printk("Rac irq: 0x%x\n", irq);
+      break;
+    case 3:
+      irq = cpu_mem_read_32(EFR32_BUFC_ADDR + EFR32_BUFC_IF_ADDR);
+      irq &= cpu_mem_read_32(EFR32_BUFC_ADDR + EFR32_BUFC_IEN_ADDR);
+      efr32_radio_printk("bufc irq: 0x%x\n", irq);
+      break;
+    case 7:
+      efr32_rfp_timer_irq(dev);
+      break;
+    case 8:
+      irq = cpu_mem_read_32(EFR32_FRC_ADDR + EFR32_FRC_IF_ADDR);
+      irq &= cpu_mem_read_32(EFR32_FRC_ADDR + EFR32_FRC_IEN_ADDR);
+
+      if (irq & EFR32_TX_IRQ_FRC_MSK)
+        efr32_rfp_tx_irq(ctx, irq);
+      else if (irq & EFR32_RX_IRQ_FRC_MSK)
+        efr32_rfp_rx_irq(ctx, irq);
+
+      efr32_radio_printk("frc irq: 0x%x\n", irq);
+      /* Clear irqs */
+      cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_IFC_ADDR, irq);
+      break;
+
+    default:
+      efr32_radio_printk("irq: %d\n", ep - ctx->pv.irq_ep);
+      abort();
+      break;
+  }
+
+  lock_release(&dev->lock);
+}
+
+
+/* Transceiver is doing nothing */
+
+static void efr32_rfp_idle(struct radio_efr32_rfp_ctx_s *ctx)
+{
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+
+  /* Check RAC state */
+  uint32_t x = endian_le32(cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_STATUS_ADDR));
+  assert(EFR32_RAC_STATUS_STATE_GET(x) == EFR32_RAC_STATUS_STATE_OFF);
+
+  efr32_radio_set_state(ctx, EFR32_RFP_STATE_IDLE);
+
+  struct dev_rfpacket_rq_s *rq = dev_rfpacket_rq_s_cast(dev_request_queue_head(&ctx->queue));
+
+  if (!rq)
+    rq = ctx->rx_cont;
+
+  if (!rq)
+    return;
+
+  efr32_radio_printk("rq: %d\n", rq->type);
+
+  if (efr32_pkt_config(ctx, rq) || efr32_rf_config(ctx, rq))
+    {
+      /* Unsupported configuration */
+      if (rq->type != DEV_RFPACKET_RQ_RX_CONT)
+        return efr32_rfp_end_rq(ctx, -ENOTSUP);
+
+      /* Rx continuous */	
+      rq->err = -ENOTSUP;
+      kroutine_exec(&ctx->rx_cont->base.kr);
+      return;
+    }
+
+  rq->base.drvdata = NULL;
+  
+  switch (rq->type)
+  {
+    case DEV_RFPACKET_RQ_TX_FAIR:
+      efr32_radio_set_state(ctx, EFR32_RFP_STATE_TX_LBT);
+      break;
+    case DEV_RFPACKET_RQ_TX:
+      efr32_radio_set_state(ctx, EFR32_RFP_STATE_TX);
+      break;
+    case DEV_RFPACKET_RQ_RX_CONT:
+    case DEV_RFPACKET_RQ_RX:
+      return efr32_rfp_start_rx(ctx, rq);
+    default:
+      abort();
+  }
+
+  if (rq->tx_size > EFR32_RADIO_THRESHOLD)
+    {
+      kroutine_init_deferred(&pv->kr, &efr32_rfp_tx);
+      kroutine_exec(&pv->kr);
+      return;
+    }
+
+  return efr32_rfp_start_tx(ctx);
+}
+
+static DEV_RFPACKET_REQUEST(efr32_radio_request)
+{
+  struct device_s *dev = accessor->dev;
+  struct radio_efr32_rfp_ctx_s *ctx = dev->drv_pv;
+
+  LOCK_SPIN_IRQ(&dev->lock);
+
+  va_list vl;
+  va_start(vl, accessor);
+
+  while(1)
+  {
+    struct dev_rfpacket_rq_s *rq = va_arg(vl, struct dev_rfpacket_rq_s *);
+
+    if (rq == NULL)
+      break;
+
+    assert(rq != ctx->rx_cont);
+    assert(rq != ctx->next_rx_cont);
+
+    efr32_radio_printk("R %d %d\n", rq->type, ctx->state);
+
+    rq->err = 0;
+
+    if (rq->type == DEV_RFPACKET_RQ_RX_CONT)
+      {
+        rq->base.drvdata = NULL;
+        switch (ctx->state)
+        {
+          case EFR32_RFP_STATE_RXC_STOPPING_PENDING_RX:
+            if (ctx->next_rx_cont && ctx->next_rx_cont != ctx->rx_cont)
+              kroutine_exec(&ctx->next_rx_cont->base.kr);
+            ctx->next_rx_cont = rq;
+            break;
+          case EFR32_RFP_STATE_RXC_PENDING_RX:
+            assert(ctx->next_rx_cont == NULL);
+            assert(ctx->rx_cont);
+            efr32_rfp_disable(ctx);
+            efr32_radio_set_state(ctx, EFR32_RFP_STATE_RXC_STOPPING_PENDING_RX);
+            ctx->next_rx_cont = rq;
+            break;
+          case EFR32_RFP_STATE_RXC:
+            assert(ctx->next_rx_cont == NULL);
+            assert(ctx->rx_cont);
+            /* Replace the current RX continous */
+            efr32_rfp_disable(ctx);
+            kroutine_exec(&ctx->rx_cont->base.kr);
+          case EFR32_RFP_STATE_IDLE:
+            ctx->rx_cont = rq;
+            efr32_rfp_idle(ctx);
+            break;
+          default:
+            assert(ctx->next_rx_cont == NULL);
+            if (ctx->rx_cont)
+              kroutine_exec(&ctx->rx_cont->base.kr);
+            ctx->rx_cont = rq;
+            break;
+        }
+      }
+    else
+      {
+        bool_t empty = dev_request_queue_isempty(&ctx->queue);
+        dev_request_queue_pushback(&ctx->queue, dev_rfpacket_rq_s_base(rq));
+        rq->base.drvdata = ctx;
+
+        if (empty)
+          {
+            switch (ctx->state)
+            {
+              case EFR32_RFP_STATE_RXC_PENDING_RX:
+                /* A RX packet read is pending */
+                assert(rq->deadline == 0);
+                assert(ctx->rx_cont);
+                efr32_rfp_disable(ctx);
+                efr32_radio_set_state(ctx, EFR32_RFP_STATE_RXC_STOPPING_PENDING_RX);
+                ctx->next_rx_cont = ctx->rx_cont;
+                break;
+              case EFR32_RFP_STATE_RXC:
+                assert(rq->deadline == 0);
+                assert(ctx->next_rx_cont == NULL);
+                assert(ctx->rx_cont);
+                /* Pause the current RX continous */
+                efr32_rfp_disable(ctx);
+              case EFR32_RFP_STATE_IDLE:
+                efr32_rfp_idle(ctx);
+                break;
+              default:
+                break;
+            }
+          }
+      }
+  }
+
+  LOCK_RELEASE_IRQ(&dev->lock);
+}
+
+static DEV_RFPACKET_CANCEL(efr32_radio_cancel)
+{
+  struct device_s *dev = accessor->dev;
+  struct radio_efr32_rfp_ctx_s *ctx = dev->drv_pv;
+
+  error_t err = -EBUSY;
+
+  assert(rq);
+
+  LOCK_SPIN_IRQ(&dev->lock);
+
+  if (rq == ctx->rx_cont)
+    {
+      switch (ctx->state)
+      {
+        case EFR32_RFP_STATE_RXC_PENDING_RX:
+          assert(ctx->next_rx_cont == NULL);
+          assert(ctx->rx_cont);
+          efr32_rfp_disable(ctx);
+          efr32_radio_set_state(ctx, EFR32_RFP_STATE_RXC_STOPPING_PENDING_RX);
+          break;
+        case EFR32_RFP_STATE_RXC_STOPPING_PENDING_RX:
+          if (rq == ctx->next_rx_cont)
+            ctx->next_rx_cont = NULL;
+          break;
+        case EFR32_RFP_STATE_RXC:
+          assert(ctx->next_rx_cont == NULL);
+          assert(ctx->rx_cont);
+          efr32_rfp_disable(ctx);
+          efr32_radio_set_state(ctx, EFR32_RFP_STATE_IDLE);
+          ctx->rx_cont = NULL;
+          err = 0;
+          break;
+        default:
+          err = 0;
+          ctx->rx_cont = NULL;
+          if (rq == ctx->next_rx_cont)
+            ctx->next_rx_cont = NULL;
+          break;
+      }
+    }
+  else if(rq == ctx->next_rx_cont)
+    {
+      switch (ctx->state)
+      {
+        case EFR32_RFP_STATE_RXC_STOPPING_PENDING_RX:
+          ctx->next_rx_cont = NULL;
+          if (rq != ctx->rx_cont)
+            err = 0;
+        default:
+          break;
+      }
+    }
+  else if (rq->base.drvdata == ctx)
+    {
+      err = 0;
+      rq->base.drvdata = NULL;
+      dev_request_queue_remove(&ctx->queue, dev_rfpacket_rq_s_base(rq));
+    }
+
+  LOCK_RELEASE_IRQ(&dev->lock);
+
+  return err;
+}
+
+#define efr32_radio_use dev_use_generic
+#define efr32_radio_stats (dev_rfpacket_stats_t*)&dev_driver_notsup_fcn
+
+/**************************** TIMER PART ********************************/
+
+static DEV_TIMER_CANCEL(efr32_rfpacket_timer_cancel)
+{
+  struct device_s *dev = accessor->dev;
+  struct radio_efr32_rfp_ctx_s *ctx = dev->drv_pv;
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+
+  error_t err = -ETIMEDOUT;
+
+  LOCK_SPIN_IRQ(&dev->lock);
+
+  if (rq->rq.drvdata == ctx)
+    {
+      struct dev_timer_rq_s *rqnext = NULL;
+      bool_t first = (dev_request_pqueue_prev(&pv->pti.queue, dev_timer_rq_s_base(rq)) == NULL);
+
+      if (first)
+        rqnext = dev_timer_rq_s_cast(dev_request_pqueue_next(&pv->pti.queue, dev_timer_rq_s_base(rq)));
+
+      dev_timer_pqueue_remove(&pv->pti.queue, dev_timer_rq_s_base(rq));
+      rq->rq.drvdata = NULL;
+
+      if (first)
+        {
+          efr32_protimer_disable_compare(&pv->pti, EFR32_PROTIMER_CHANNEL);
+
+          if (rqnext != NULL)
+            {
+              dev_timer_value_t value = efr32_protimer_get_value(&pv->pti);
+              /* start next request, raise irq on race condition */
+              efr32_protimer_request_start(&pv->pti, value, rqnext->deadline, EFR32_PROTIMER_CHANNEL);
+            }
+        }
+
+      err = 0;
+    }
+
+  LOCK_RELEASE_IRQ(&dev->lock);
+
+  return err;
+}
+
+static DEV_TIMER_REQUEST(efr32_rfpacket_timer_request)
+{
+  struct device_s *dev = accessor->dev;
+
+  struct radio_efr32_rfp_ctx_s *ctx = dev->drv_pv;
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+  struct efr32_protimer_s *pti = &pv->pti;
+
+  error_t err = 0;
+
+  LOCK_SPIN_IRQ(&dev->lock);
+
+  if (rq->rev && rq->rev != pti->rev)
+    err = -EAGAIN;
+  else
+    {
+      /* Start timer if needed */
+      if (dev->start_count == 0)
+        efr32_protimer_start_counter(pti);
+
+      dev_timer_value_t value = efr32_protimer_get_value(pti);
+
+      if (rq->delay)
+        rq->deadline = value + rq->delay;
+      if (rq->deadline <= value)
+        err = -ETIMEDOUT;
+      else
+        {
+          dev->start_count |= 1;
+          dev_timer_pqueue_insert(&pti->queue, dev_timer_rq_s_base(rq));
+          rq->rq.drvdata = ctx;
+
+          /* start request, raise irq on race condition */
+          if (dev_request_pqueue_prev(&pti->queue, dev_timer_rq_s_base(rq)) == NULL)
+            efr32_protimer_request_start(pti, value, rq->deadline, EFR32_PROTIMER_CHANNEL);
+        }
+    }
+
+  LOCK_RELEASE_IRQ(&dev->lock);
+
+  return err;
+}
+
+static DEV_TIMER_GET_VALUE(efr32_rfpacket_timer_get_value)
+{
+  struct device_s *dev = accessor->dev;
+  struct radio_efr32_rfp_ctx_s *ctx = dev->drv_pv;
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+
+  LOCK_SPIN_IRQ(&dev->lock);
+
+  *value = efr32_protimer_get_value(&pv->pti);
+
+  LOCK_RELEASE_IRQ(&dev->lock);
+
+  return 0;
+}
+
+static DEV_TIMER_CONFIG(efr32_rfpacket_timer_config)
+{
+  struct device_s *dev = accessor->dev;
+  struct radio_efr32_rfp_ctx_s *ctx = dev->drv_pv;
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+
+  uint32_t r = 1;
+
+  error_t err = 0;
+
+  LOCK_SPIN_IRQ(&dev->lock);
+
+  cfg->freq = pv->freq;
+
+  if (res)
+    {
+      if (dev->start_count)
+        {
+          err = -EBUSY;
+          r = res;
+        }
+      else
+        {
+          /* Resolution can not be modified */
+          if (res != 1)
+            err = -ERANGE;
+          pv->pti.rev += 2;
+        }
+    }
+
+  if (cfg)
+    {
+      cfg->rev = pv->pti.rev;
+      cfg->res = r;
+      cfg->cap = pv->pti.cap;
+      cfg->max = 0xffffffffffffffffULL;
+    }
+
+  LOCK_RELEASE_IRQ(&dev->lock);
+
+  return err;
+}
+
+static void efr32_rfp_timer_irq(struct device_s *dev)
+{
+  struct radio_efr32_rfp_ctx_s *ctx = dev->drv_pv;
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+  struct efr32_protimer_s *pti = &pv->pti;
+
+  while (1)
+    {
+      uint32_t irq = endian_le32(cpu_mem_read_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IF_ADDR));
+      irq &= endian_le32(cpu_mem_read_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IEN_ADDR));
+
+      if (!irq)
+        break;
+
+      cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IFC_ADDR, endian_le32(irq));
+
+      uint32_t x = endian_le32(cpu_mem_read_32(EFR32_RAC_ADDR + EFR32_RAC_STATUS_ADDR));
+      x = EFR32_RAC_STATUS_STATE_GET(x);  
+
+      /* TX timeout */
+      if (irq & EFR32_PROTIMER_IF_LBTFAILURE)
+        {
+          /* Check RAC state */
+          if (x != EFR32_RAC_STATUS_STATE_OFF)
+            efr32_rfp_disable(ctx);
+          efr32_rfp_try_restart_tx(ctx);
+        }
+
+      /* Compare channel RX end interrupt */ 
+      if (irq & EFR32_PROTIMER_IF_CC(EFR32_PROTIMER_RX_STOP_CHANNEL))
+       {
+         /* RX timeout */
+         efr32_protimer_disable_compare(pti, EFR32_PROTIMER_RX_STOP_CHANNEL);
+         if (x != EFR32_RAC_STATUS_STATE_OFF)
+           efr32_rfp_disable(ctx);
+
+         efr32_rfp_end_rq(ctx, 0);
+       }
+
+      /* Timer class interrupts */
+      if (!(irq & (EFR32_PROTIMER_IF_CC(EFR32_PROTIMER_CHANNEL) | EFR32_PROTIMER_IF_WRAPCNTOF)))
+        break;
+
+#if EFR32_PROTIMER_HW_WIDTH < 64
+      /* Compare channel interrupt */ 
+      if (irq & EFR32_PROTIMER_IF_CC(EFR32_PROTIMER_CHANNEL))
+         efr32_protimer_disable_compare(pti, EFR32_PROTIMER_CHANNEL);
+
+      /* Update the software part of the counter */
+      if (irq & EFR32_PROTIMER_IF_WRAPCNTOF)
+        pti->swvalue++;
+#endif
+
+      /* CC channel irq */
+      while (1)
+        {
+          struct dev_timer_rq_s *rq;
+          rq = dev_timer_rq_s_cast(dev_request_pqueue_head(&pti->queue));
+          if (rq == NULL)
+            break;
+
+          dev_timer_value_t value = efr32_protimer_get_value(pti);
+
+          /* setup compare for first request */
+          if (rq->deadline > value)
+            if (!efr32_protimer_request_start(pti, value, rq->deadline, EFR32_PROTIMER_CHANNEL))
+              break;
+
+          dev_timer_pqueue_remove(&pti->queue, dev_timer_rq_s_base(rq));
+          efr32_protimer_disable_compare(pti, EFR32_PROTIMER_CHANNEL);
+          rq->rq.drvdata = NULL;
+
+          lock_release(&dev->lock);
+          kroutine_exec(&rq->rq.kr);
+          lock_spin(&dev->lock);
+        }
+    }
+}
+
+#ifdef CONFIG_DRIVER_EFR32_DEBUG
+static void efr32_rfp_cfg_prs_dbg(struct radio_efr32_rfp_ctx_s *ctx)
+{
+  uint32_t x;
+
+  /* Set PC9 to PC11 in output */
+  uint32_t a = 0x4000a008 + 2 * 0x30;
+  x = cpu_mem_read_32(a);
+  cpu_mem_write_32(a, x | (0x444 << 4));
+
+  /* Configure PRS channel 9/10/11 on PC9/10/11 */
+  x = EFR32_PRS_ROUTEPEN_CHPEN(9)  |
+      EFR32_PRS_ROUTEPEN_CHPEN(10) |
+      EFR32_PRS_ROUTEPEN_CHPEN(11);
+
+  cpu_mem_write_32(EFM32_PRS_ADDR + EFR32_PRS_ROUTEPEN_ADDR, x);
+
+  x = EFR32_PRS_ROUTELOC2_CH9LOC(14) |
+      EFR32_PRS_ROUTELOC2_CH10LOC(4) |
+      EFR32_PRS_ROUTELOC2_CH11LOC(4);
+
+  cpu_mem_write_32(EFM32_PRS_ADDR + EFR32_PRS_ROUTELOC2_ADDR, x);
+
+  /* PC9 */
+  x = EFR32_PRS_CH_CTRL_SOURCESEL(PROTIMERH);
+  EFR32_PRS_CH_CTRL_SIGSEL_SETVAL(x, 7); //PROTIMERCC1
+
+  cpu_mem_write_32(EFM32_PRS_ADDR + EFR32_PRS_CH_CTRL_ADDR(9), x);  
+
+  /* PC10 */
+  x = EFR32_PRS_CH_CTRL_SOURCESEL(PROTIMERH);
+  EFR32_PRS_CH_CTRL_SIGSEL_SETVAL(x, 2); //PROTIMERCC2
+
+  cpu_mem_write_32(EFM32_PRS_ADDR + EFR32_PRS_CH_CTRL_ADDR(10), x);  
+
+  /* PC11 */
+  x = EFR32_PRS_CH_CTRL_SOURCESEL(PROTIMERL);
+  EFR32_PRS_CH_CTRL_SIGSEL_SETVAL(x, 0); //PROTIMERPOF
+
+  cpu_mem_write_32(EFM32_PRS_ADDR + EFR32_PRS_CH_CTRL_ADDR(11), x);  
+}
+#endif
+
+static DEV_INIT(efr32_radio_init);
+static DEV_CLEANUP(efr32_radio_cleanup);
+
+DRIVER_DECLARE(efr32_radio_drv, 0, "EFR32 RFP radio", efr32_radio,
+    DRIVER_RFPACKET_METHODS(efr32_radio),
+    DRIVER_TIMER_METHODS(efr32_rfpacket_timer));
+
+DRIVER_REGISTER(efr32_radio_drv,
+    DEV_ENUM_FDTNAME_ENTRY("efr32:radio"));
+
+static DEV_INIT(efr32_radio_init)
+{
+  struct radio_efr32_rfp_ctx_s	*ctx;
+
+  /* allocate private driver data */
+  ctx = mem_alloc(sizeof(*ctx), (mem_scope_sys));
+
+  if (!ctx)
+    return -ENOMEM;
+
+  memset(ctx, 0, sizeof(*ctx));
+
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+
+  dev->drv_pv = ctx;
+  pv->dev = dev;
+
+
+  if (efr32_rfp_init(ctx))
+    goto err_mem;
+
+  uint32_t x = cpu_mem_read_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IEN_ADDR);
+
+  x |=  EFR32_PROTIMER_IF_CC(EFR32_PROTIMER_RX_STOP_CHANNEL) |
+        EFR32_PROTIMER_IF_LBTFAILURE;
+
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_IEN_ADDR, x);
+
+  /* Timeout counter 0 synchronized on PRECNTOF
+     Timeout counter 0 prescaler decremented on PRECNTOF */
+  x = cpu_mem_read_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CTRL_ADDR);
+  x |= EFR32_PROTIMER_CTRL_TOUT_SRC(0, PRECNTOF);
+  cpu_mem_write_32(EFR32_PROTIMER_ADDR + EFR32_PROTIMER_CTRL_ADDR, x);
+
+  pv->freq.num = EFR32_RADIO_HFXO_CLK;
+  pv->freq.denom = 1;
+
+  device_get_res_freq(dev, &pv->freq, 0);
+
+  assert(pv->freq.denom == 1);
+
+  /* Queues init */
+  dev_request_queue_init(&ctx->queue);
+  dev_request_pqueue_init(&pv->pti.queue);
+
+  /* Interrupt init */
+  device_irq_source_init(dev, pv->irq_ep, EFR32_RADIO_IRQ_COUNT,
+      &efr32_radio_irq);
+
+  if (device_irq_source_link(dev, pv->irq_ep, EFR32_RADIO_IRQ_COUNT, -1))
+    goto err_mem;
+
+  dev->start_count |= 1;
+  efr32_protimer_start_counter(&pv->pti);
+
+#ifdef CONFIG_DRIVER_EFR32_DEBUG
+  efr32_rfp_cfg_prs_dbg(ctx);
+  efr32_radio_debug_init(pv);
+#endif
+
+  return 0;
+
+err_mem:
+  mem_free(ctx);
+  return -1;
+}
+
+static DEV_CLEANUP(efr32_radio_cleanup)
+{
+  struct radio_efr32_rfp_ctx_s *ctx = dev->drv_pv;
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+
+  if (!dev_request_queue_isempty(&ctx->queue) || ctx->rx_cont || 
+       dev->start_count > 0)
+    return -EBUSY;
+
+  device_irq_source_unlink(dev, pv->irq_ep, EFR32_RADIO_IRQ_COUNT);
+
+  dev_request_pqueue_destroy(&pv->pti.queue);
+  dev_request_queue_destroy(&ctx->queue);
+
+  mem_free(ctx);
+
+  return 0;
+}
+
+static error_t efr32_rfp_init(struct radio_efr32_rfp_ctx_s *ctx)
+{
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_RXCTRL_ADDR, EFR32_FRC_RXCTRL_BUFRESTOREFRAMEERROR |
+                                                           EFR32_FRC_RXCTRL_BUFRESTORERXABORTED);
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_TRAILRXDATA_ADDR, EFR32_FRC_TRAILRXDATA_RSSI);
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_FCD_ADDR(0), EFR32_FRC_FCD_CALCCRC |
+                                                           EFR32_FRC_FCD_SKIPWHITE);
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_FCD_ADDR(1), EFR32_FRC_FCD_WORDS(255) |
+                                                           EFR32_FRC_FCD_INCLUDECRC |
+                                                           EFR32_FRC_FCD_CALCCRC |
+                                                           EFR32_FRC_FCD_SKIPWHITE);
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_FCD_ADDR(2), EFR32_FRC_FCD_BUFFER(1) |
+                                                           EFR32_FRC_FCD_CALCCRC |
+                                                           EFR32_FRC_FCD_SKIPWHITE);
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_FCD_ADDR(3), EFR32_FRC_FCD_WORDS(255) |
+                                                           EFR32_FRC_FCD_BUFFER(1) |
+                                                           EFR32_FRC_FCD_INCLUDECRC |
+                                                           EFR32_FRC_FCD_CALCCRC |
+                                                           EFR32_FRC_FCD_SKIPWHITE);
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_CTRL_ADDR, EFR32_SYNTH_CTRL_DITHERDSMINPUT |
+                                                           EFR32_SYNTH_CTRL_DITHERDSMOUTPUT(7) |
+                                                           EFR32_SYNTH_CTRL_DITHERDAC(3) |
+                                                           EFR32_SYNTH_CTRL_LOCKTHRESHOLD(3) |
+                                                           EFR32_SYNTH_CTRL_AUXLOCKTHRESHOLD(5) |
+                                                           EFR32_SYNTH_CTRL_PRSMUX0(DISABLED) |
+                                                           EFR32_SYNTH_CTRL_PRSMUX1(DISABLED) |
+                                                           EFR32_SYNTH_CTRL_DEMMODE);
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_CALCTRL_ADDR, EFR32_SYNTH_CALCTRL_NUMCYCLES(1) |
+                                                           EFR32_SYNTH_CALCTRL_CAPCALCYCLEWAIT(CYCLES1) |
+                                                           EFR32_SYNTH_CALCTRL_STARTUPTIMING(10) |
+                                                           EFR32_SYNTH_CALCTRL_AUXCALCYCLES(4) |
+                                                           EFR32_SYNTH_CALCTRL_AUXCALCYCLEWAIT(CYCLES64));
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_VCDACCTRL_ADDR, EFR32_SYNTH_VCDACCTRL_VCDACVAL(35));
+
+  /* Frequency 868 MHz */
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_FREQ_ADDR, EFR32_SYNTH_FREQ_FREQ(35553280));
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_IFFREQ_ADDR, EFR32_SYNTH_IFFREQ_IFFREQ(16384) |
+                                                               EFR32_SYNTH_IFFREQ_LOSIDE);
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_DIVCTRL_ADDR, EFR32_SYNTH_DIVCTRL_LODIVFREQCTRL(LODIV3) |
+                                                           EFR32_SYNTH_DIVCTRL_AUXLODIVFREQCTRL(LODIV1));
+
+  /* Channel spacing */
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_CHSP_ADDR, EFR32_SYNTH_CHSP_CHSP(4096));
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_VCOTUNING_ADDR, EFR32_SYNTH_VCOTUNING_VCOTUNING(125));
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_VCOGAIN_ADDR, EFR32_SYNTH_VCOGAIN_VCOGAIN(35));
+
+  cpu_mem_write_32(EFR32_SYNTH_ADDR + EFR32_SYNTH_CAPCALCYCLECNT_ADDR, EFR32_SYNTH_CAPCALCYCLECNT_CAPCALCYCLECNT(127));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_CTRL_ADDR, EFR32_RAC_CTRL_ACTIVEPOL |
+                                                         EFR32_RAC_CTRL_PAENPOL |
+                                                         EFR32_RAC_CTRL_LNAENPOL);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_LVDSCTRL_ADDR, EFR32_RAC_LVDSCTRL_LVDSCURR(3));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_LVDSIDLESEQ_ADDR, EFR32_RAC_LVDSIDLESEQ_LVDSIDLESEQ(188));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_HFXORETIMECTRL_ADDR, EFR32_RAC_HFXORETIMECTRL_LIMITH(4) |
+                                                           EFR32_RAC_HFXORETIMECTRL_LIMITL(5));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_WAITSNSH_ADDR, EFR32_RAC_WAITSNSH_WAITSNSH(1));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_PRESC_ADDR, EFR32_RAC_PRESC_STIMER(7));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_SYNTHENCTRL_ADDR, EFR32_RAC_SYNTHENCTRL_VCOEN |
+                                                                EFR32_RAC_SYNTHENCTRL_LODIVEN |
+                                                                EFR32_RAC_SYNTHENCTRL_CHPEN |
+                                                                EFR32_RAC_SYNTHENCTRL_LPFEN |
+                                                                EFR32_RAC_SYNTHENCTRL_SYNTHCLKEN |
+                                                                EFR32_RAC_SYNTHENCTRL_SYNTHSTARTREQ |
+                                                                EFR32_RAC_SYNTHENCTRL_CHPLDOEN |
+                                                                EFR32_RAC_SYNTHENCTRL_LODIVSYNCCLKEN |
+                                                                EFR32_RAC_SYNTHENCTRL_MMDLDOEN |
+                                                                EFR32_RAC_SYNTHENCTRL_VCOLDOEN |
+                                                                EFR32_RAC_SYNTHENCTRL_VCODIVEN);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_SYNTHREGCTRL_ADDR, EFR32_RAC_SYNTHREGCTRL_MMDLDOAMPCURR(3) |
+                                                           EFR32_RAC_SYNTHREGCTRL_MMDLDOVREFTRIM(3) |
+                                                           EFR32_RAC_SYNTHREGCTRL_VCOLDOAMPCURR(3) |
+                                                           EFR32_RAC_SYNTHREGCTRL_VCOLDOVREFTRIM(3) |
+                                                           EFR32_RAC_SYNTHREGCTRL_CHPLDOAMPCURR(3) |
+                                                           EFR32_RAC_SYNTHREGCTRL_CHPLDOVREFTRIM(3));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_VCOCTRL_ADDR, EFR32_RAC_VCOCTRL_VCOAMPLITUDE(10) |
+                                                            EFR32_RAC_VCOCTRL_VCODETAMPLITUDE(10) |
+                                                            EFR32_RAC_VCOCTRL_VCODETEN |
+                                                            EFR32_RAC_VCOCTRL_VCODETMODE |
+                                                            EFR32_RAC_VCOCTRL_VCOAREGCURR(1) |
+                                                            EFR32_RAC_VCOCTRL_VCOCREGCURR(2) |
+                                                            EFR32_RAC_VCOCTRL_VCODIVCURR(15));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_MMDCTRL_ADDR, EFR32_RAC_MMDCTRL_MMDDIVDCDC(123) |
+                                                            EFR32_RAC_MMDCTRL_MMDDIVRSDCDC(1) |
+                                                            EFR32_RAC_MMDCTRL_MMDDIVRSDIG(1) |
+                                                            EFR32_RAC_MMDCTRL_MMDENDCDC |
+                                                            EFR32_RAC_MMDCTRL_MMDENRSDCDC |
+                                                            EFR32_RAC_MMDCTRL_MMDENRSDIG);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_CHPCTRL_ADDR, EFR32_RAC_CHPCTRL_CHPBIAS(6) |
+                                                           EFR32_RAC_CHPCTRL_CHPCURR(5));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_CHPCAL_ADDR, EFR32_RAC_CHPCAL_PSRC(4) |
+                                                           EFR32_RAC_CHPCAL_NSRC(4));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_LPFCTRL_ADDR, EFR32_RAC_LPFCTRL_LPFINPUTCAP(3) |
+                                                           EFR32_RAC_LPFCTRL_LPFSWITCHINGEN |
+                                                           EFR32_RAC_LPFCTRL_LPFGNDSWITCHINGEN |
+                                                           EFR32_RAC_LPFCTRL_LPFBWTX(2));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_AUXCTRL_ADDR, EFR32_RAC_AUXCTRL_CHPCURR(3) |
+                                                           EFR32_RAC_AUXCTRL_RXAMP(16) |
+                                                           EFR32_RAC_AUXCTRL_LDOAMPCURR(4) |
+                                                           EFR32_RAC_AUXCTRL_LDOVREFTRIM(6) |
+                                                           EFR32_RAC_AUXCTRL_LPFRES(1));
+
+  /* Sub-G PA configuration */
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_SGRFENCTRL0_ADDR, EFR32_RAC_SGRFENCTRL0_LNAMIXBIASEN |
+                                                           EFR32_RAC_SGRFENCTRL0_LNAMIXLOBIASEN |
+                                                           EFR32_RAC_SGRFENCTRL0_LNAMIXRFBIASEN);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_SGLNAMIXCTRL_ADDR, EFR32_RAC_SGLNAMIXCTRL_CASCODEBIAS(3) |
+                                                           EFR32_RAC_SGLNAMIXCTRL_LOBIAS(3) |
+                                                           EFR32_RAC_SGLNAMIXCTRL_VREG(3) |
+                                                           EFR32_RAC_SGLNAMIXCTRL_RFBIAS(3) |
+                                                           EFR32_RAC_SGLNAMIXCTRL_SGREGAMPCURR(3));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_SGPACTRL0_ADDR, EFR32_RAC_SGPACTRL0_CASCODE(EN3SLICES) |
+                                                           EFR32_RAC_SGPACTRL0_SLICE(EN3SLICES) |
+                                                           EFR32_RAC_SGPACTRL0_STRIPE(8) |
+                                                           EFR32_RAC_SGPACTRL0_DACGLITCHCTRL);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_SGPAPKDCTRL_ADDR, EFR32_RAC_SGPAPKDCTRL_VTHSEL(23) |
+                                                           EFR32_RAC_SGPAPKDCTRL_CAPSEL(3) |
+                                                           EFR32_RAC_SGPAPKDCTRL_I2VCM(2) |
+                                                           EFR32_RAC_SGPAPKDCTRL_PKDBIASTH(4));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_SGPABIASCTRL0_ADDR, EFR32_RAC_SGPABIASCTRL0_LDOBIAS |
+                                                           EFR32_RAC_SGPABIASCTRL0_PABIAS(1) |
+                                                           EFR32_RAC_SGPABIASCTRL0_BUF0BIAS(1) |
+                                                           EFR32_RAC_SGPABIASCTRL0_BUF12BIAS(1) |
+                                                           EFR32_RAC_SGPABIASCTRL0_SGDACFILTBANDWIDTH(7));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_SGPABIASCTRL1_ADDR, EFR32_RAC_SGPABIASCTRL1_VLDO(3) |
+                                                           EFR32_RAC_SGPABIASCTRL1_VLDOFB(2) |
+                                                           EFR32_RAC_SGPABIASCTRL1_VCASCODEHV(5) |
+                                                           EFR32_RAC_SGPABIASCTRL1_VCASCODELV(4) |
+                                                           EFR32_RAC_SGPABIASCTRL1_SGVBATDETTHRESHOLD(2));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_RFBIASCTRL_ADDR, EFR32_RAC_RFBIASCTRL_LDOVREF(4) |
+                                                           EFR32_RAC_RFBIASCTRL_LDOAMPCURR(3));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_RFBIASCAL_ADDR, EFR32_RAC_RFBIASCAL_VREF(22) |
+                                                           EFR32_RAC_RFBIASCAL_BIAS(28) |
+                                                           EFR32_RAC_RFBIASCAL_TEMPCO(48));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_LNAMIXCTRL1_ADDR, EFR32_RAC_LNAMIXCTRL1_TRIMAUXPLLCLK(E0) |
+                                                           EFR32_RAC_LNAMIXCTRL1_TRIMVCASLDO |
+                                                           EFR32_RAC_LNAMIXCTRL1_TRIMVREGMIN(1));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_IFPGACTRL_ADDR, EFR32_RAC_IFPGACTRL_VLDO(3) |
+                                                           EFR32_RAC_IFPGACTRL_BANDSEL(SG) |
+                                                           EFR32_RAC_IFPGACTRL_CASCBIAS(7) |
+                                                           EFR32_RAC_IFPGACTRL_TRIMVCASLDO |
+                                                           EFR32_RAC_IFPGACTRL_TRIMVCM(3) |
+                                                           EFR32_RAC_IFPGACTRL_TRIMVREGMIN(1));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_IFPGACAL_ADDR, EFR32_RAC_IFPGACAL_IRAMP(2) |
+                                                           EFR32_RAC_IFPGACAL_IRPHASE(10) |
+                                                           EFR32_RAC_IFPGACAL_OFFSETI(64));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_IFFILTCTRL_ADDR, EFR32_RAC_IFFILTCTRL_CENTFREQ(7) |
+                                                           EFR32_RAC_IFFILTCTRL_VCM(2) |
+                                                           EFR32_RAC_IFFILTCTRL_VREG(4));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_IFADCCTRL_ADDR, EFR32_RAC_IFADCCTRL_REALMODE |
+                                                           EFR32_RAC_IFADCCTRL_VLDOSERIES(3) |
+                                                           EFR32_RAC_IFADCCTRL_VLDOSERIESCURR(3) |
+                                                           EFR32_RAC_IFADCCTRL_VLDOSHUNT(2) |
+                                                           EFR32_RAC_IFADCCTRL_VLDOCLKGEN(3) |
+                                                           EFR32_RAC_IFADCCTRL_VCM(E2) |
+                                                           EFR32_RAC_IFADCCTRL_OTA1CURRENT(2) |
+                                                           EFR32_RAC_IFADCCTRL_OTA2CURRENT(2) |
+                                                           EFR32_RAC_IFADCCTRL_OTA3CURRENT(2) |
+                                                           EFR32_RAC_IFADCCTRL_REGENCLKDELAY(3) |
+                                                           EFR32_RAC_IFADCCTRL_ENABLECLK |
+                                                           EFR32_RAC_IFADCCTRL_INVERTCLK);
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_RCTUNE_ADDR, EFR32_RAC_RCTUNE_IFADCRCTUNE(34) |
+                                                           EFR32_RAC_RCTUNE_IFFILT(34));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_APC_ADDR, EFR32_RAC_APC_AMPCONTROLLIMITSW(255));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_CHPCTRL1_ADDR, EFR32_RAC_CHPCTRL1_BYPREPLDORX |
+                                                           EFR32_RAC_CHPCTRL1_TRIMREPLDO(1));
+
+  cpu_mem_write_32(EFR32_RAC_ADDR + EFR32_RAC_MMDCTRL1_ADDR, EFR32_RAC_MMDCTRL1_BYPREPLDORX |
+                                                           EFR32_RAC_MMDCTRL1_TRIMREPLDO(1));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_FREQOFFEST_ADDR, EFR32_MODEM_FREQOFFEST_FREQOFFEST(9) |
+                                                           EFR32_MODEM_FREQOFFEST_CORRVAL(115) |
+                                                           EFR32_MODEM_FREQOFFEST_SOFTVAL(221));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_MIXCTRL_ADDR, EFR32_MODEM_MIXCTRL_MODE(NORMAL) |
+                                                           EFR32_MODEM_MIXCTRL_DIGIQSWAPEN);
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CTRL0_ADDR, EFR32_MODEM_CTRL0_MAPFSK(MAP0) |
+                                                           EFR32_MODEM_CTRL0_CODING(NRZ) |
+                                                           EFR32_MODEM_CTRL0_MODFORMAT(FSK2) |
+                                                           EFR32_MODEM_CTRL0_DSSSSHIFTS(NOSHIFT) |
+                                                           EFR32_MODEM_CTRL0_DSSSDOUBLE(DIS) |
+                                                           EFR32_MODEM_CTRL0_DIFFENCMODE(DIS) |
+                                                           EFR32_MODEM_CTRL0_SHAPING(EVENLENGTH) |
+                                                           EFR32_MODEM_CTRL0_DEMODRAWDATASEL(DIS) |
+                                                           EFR32_MODEM_CTRL0_FRAMEDETDEL(DEL0));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CTRL2_ADDR, EFR32_MODEM_CTRL2_SQITHRESH(200) |
+                                                           EFR32_MODEM_CTRL2_TXPINMODE(OFF) |
+                                                           EFR32_MODEM_CTRL2_DATAFILTER(LEN7) |
+                                                           EFR32_MODEM_CTRL2_RATESELMODE(NOCHANGE) |
+                                                           EFR32_MODEM_CTRL2_DMASEL(SOFT));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CTRL3_ADDR, EFR32_MODEM_CTRL3_PRSDINSEL(PRSCH0) |
+                                                           EFR32_MODEM_CTRL3_ANTDIVMODE(ANTENNA0) |
+                                                           EFR32_MODEM_CTRL3_TSAMPMODE(ON) |
+                                                           EFR32_MODEM_CTRL3_TSAMPDEL(3) |
+                                                           EFR32_MODEM_CTRL3_TSAMPLIM(8));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CTRL4_ADDR, EFR32_MODEM_CTRL4_ADCSATLEVEL(CONS64));
+
+  /* Baudrate 38400 bit/s */
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_TXBR_ADDR, EFR32_MODEM_TXBR_TXBRNUM(31875) |
+                                                             EFR32_MODEM_TXBR_TXBRDEN(255));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_RXBR_ADDR, EFR32_MODEM_RXBR_RXBRNUM(19) |
+                                                           EFR32_MODEM_RXBR_RXBRDEN(27) |
+                                                           EFR32_MODEM_RXBR_RXBRINT(3));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_CF_ADDR, EFR32_MODEM_CF_DEC0(DF3) |
+                                                           EFR32_MODEM_CF_DEC1(44) |
+                                                           EFR32_MODEM_CF_CFOSR(CF7) |
+                                                           EFR32_MODEM_CF_DEC1GAIN(ADD0));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_TIMING_ADDR, EFR32_MODEM_TIMING_TIMTHRESH(27) |
+                                                           EFR32_MODEM_TIMING_TIMINGBASES(7) |
+                                                           EFR32_MODEM_TIMING_OFFSUBNUM(13) |
+                                                           EFR32_MODEM_TIMING_OFFSUBDEN(8) |
+                                                           EFR32_MODEM_TIMING_FASTRESYNC(DIS));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_MODINDEX_ADDR, EFR32_MODEM_MODINDEX_MODINDEXM(20) |
+                                                           EFR32_MODEM_MODINDEX_MODINDEXE(27) |
+                                                           EFR32_MODEM_MODINDEX_FREQGAINE(3) |
+                                                           EFR32_MODEM_MODINDEX_FREQGAINM(7));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SHAPING0_ADDR, EFR32_MODEM_SHAPING0_COEFF0(4) |
+                                                           EFR32_MODEM_SHAPING0_COEFF1(10) |
+                                                           EFR32_MODEM_SHAPING0_COEFF2(20) |
+                                                           EFR32_MODEM_SHAPING0_COEFF3(34));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SHAPING1_ADDR, EFR32_MODEM_SHAPING1_COEFF4(50) |
+                                                           EFR32_MODEM_SHAPING1_COEFF5(65) |
+                                                           EFR32_MODEM_SHAPING1_COEFF6(74) |
+                                                           EFR32_MODEM_SHAPING1_COEFF7(79));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_RAMPCTRL_ADDR, EFR32_MODEM_RAMPCTRL_RAMPRATE2(6));
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_RAMPLEV_ADDR, EFR32_MODEM_RAMPLEV_RAMPLEV2(150));
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DCCOMP_ADDR, EFR32_MODEM_DCCOMP_DCESTIEN |
+                                                           EFR32_MODEM_DCCOMP_DCCOMPEN |
+                                                           EFR32_MODEM_DCCOMP_DCCOMPGEAR(3) |
+                                                           EFR32_MODEM_DCCOMP_DCLIMIT(FULLSCALE));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DCESTI_ADDR, EFR32_MODEM_DCESTI_DCCOMPESTIVALI(51) |
+                                                               EFR32_MODEM_DCESTI_DCCOMPESTIVALQ(32679));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_SRCCHF_ADDR, EFR32_MODEM_SRCCHF_SRCRATIO1(128) |
+                                                               EFR32_MODEM_SRCCHF_SRCRATIO2(1024));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DSATHD0_ADDR, EFR32_MODEM_DSATHD0_SPIKETHD(100) |
+                                                           EFR32_MODEM_DSATHD0_UNMODTHD(4) |
+                                                           EFR32_MODEM_DSATHD0_FDEVMINTHD(12) |
+                                                           EFR32_MODEM_DSATHD0_FDEVMAXTHD(120));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DSATHD1_ADDR, EFR32_MODEM_DSATHD1_POWABSTHD(5000) |
+                                                           EFR32_MODEM_DSATHD1_POWRELTHD(DISABLED) |
+                                                           EFR32_MODEM_DSATHD1_DSARSTCNT(2) |
+                                                           EFR32_MODEM_DSATHD1_RSSIJMPTHD(6) |
+                                                           EFR32_MODEM_DSATHD1_FREQLATDLY(1) |
+                                                           EFR32_MODEM_DSATHD1_PWRFLTBYP |
+                                                           EFR32_MODEM_DSATHD1_AMPFLTBYP |
+                                                           EFR32_MODEM_DSATHD1_PWRDETDIS);
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DSACTRL_ADDR, EFR32_MODEM_DSACTRL_DSAMODE(DISABLED) |
+                                                           EFR32_MODEM_DSACTRL_ARRTHD(7) |
+                                                           EFR32_MODEM_DSACTRL_ARRTOLERTHD0(2) |
+                                                           EFR32_MODEM_DSACTRL_ARRTOLERTHD1(4) |
+                                                           EFR32_MODEM_DSACTRL_FREQAVGSYM |
+                                                           EFR32_MODEM_DSACTRL_DSARSTON);
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_VITERBIDEMOD_ADDR, EFR32_MODEM_VITERBIDEMOD_VITERBIKSI1(64) |
+                                                           EFR32_MODEM_VITERBIDEMOD_VITERBIKSI2(48) |
+                                                           EFR32_MODEM_VITERBIDEMOD_VITERBIKSI3(32));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_VTCORRCFG0_ADDR, EFR32_MODEM_VTCORRCFG0_EXPECTPATT(349879) |
+                                                           EFR32_MODEM_VTCORRCFG0_EXPSYNCLEN(8) |
+                                                           EFR32_MODEM_VTCORRCFG0_BUFFHEAD(2));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_DIGMIXCTRL_ADDR, EFR32_MODEM_DIGMIXCTRL_DIGMIXFREQ(32768) |
+                                                           EFR32_MODEM_DIGMIXCTRL_DIGMIXMODE);
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_VTCORRCFG1_ADDR, EFR32_MODEM_VTCORRCFG1_CORRSHFTLEN(32) |
+                                                           EFR32_MODEM_VTCORRCFG1_VTFRQLIM(192));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_VTTRACK_ADDR, EFR32_MODEM_VTTRACK_FREQTRACKMODE(DISABLED) |
+                                                           EFR32_MODEM_VTTRACK_TIMTRACKTHD(2) |
+                                                           EFR32_MODEM_VTTRACK_TIMEACQUTHD(238) |
+                                                           EFR32_MODEM_VTTRACK_TIMEOUTMODE |
+                                                           EFR32_MODEM_VTTRACK_TIMGEAR(GEAR0));
+
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_BREST_ADDR, EFR32_MODEM_BREST_BRESTINT(7) |
+                                                           EFR32_MODEM_BREST_BRESTNUM(11));
+  cpu_mem_write_32(EFR32_MODEM_ADDR + EFR32_MODEM_POE_ADDR, EFR32_MODEM_POE_POEI(511));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_RSSI_ADDR, EFR32_AGC_RSSI_RSSIFRAC(3) |
+                                                           EFR32_AGC_RSSI_RSSIINT(149));
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_FRAMERSSI_ADDR, EFR32_AGC_FRAMERSSI_FRAMERSSIINT(128));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_CTRL1_ADDR, EFR32_AGC_CTRL1_RSSIPERIOD(3));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_CTRL2_ADDR, EFR32_AGC_CTRL2_HYST(3) |
+                                                           EFR32_AGC_CTRL2_FASTLOOPDEL(10) |
+                                                           EFR32_AGC_CTRL2_CFLOOPDEL(26) |
+                                                           EFR32_AGC_CTRL2_ADCRSTFASTLOOP(GAINREDUCTION) |
+                                                           EFR32_AGC_CTRL2_ADCRSTSTARTUP);
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_IFPEAKDET_ADDR, EFR32_AGC_IFPEAKDET_PKDTHRESH1(2) |
+                                                           EFR32_AGC_IFPEAKDET_PKDTHRESH2(8));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_RFPEAKDET_ADDR, EFR32_AGC_RFPEAKDET_RFPKDTHRESH1(5) |
+                                                           EFR32_AGC_RFPEAKDET_RFPKDTHRESH2(13));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_GAINRANGE_ADDR, EFR32_AGC_GAINRANGE_MAXGAIN(62) |
+                                                           EFR32_AGC_GAINRANGE_MINGAIN(112));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_GAININDEX_ADDR, EFR32_AGC_GAININDEX_NUMINDEXPGA(12) |
+                                                           EFR32_AGC_GAININDEX_NUMINDEXDEGEN(3) |
+                                                           EFR32_AGC_GAININDEX_NUMINDEXSLICES(6) |
+                                                           EFR32_AGC_GAININDEX_NUMINDEXATTEN(18));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_SLICECODE_ADDR, EFR32_AGC_SLICECODE_SLICECODEINDEX0(3) |
+                                                           EFR32_AGC_SLICECODE_SLICECODEINDEX1(4) |
+                                                           EFR32_AGC_SLICECODE_SLICECODEINDEX2(5) |
+                                                           EFR32_AGC_SLICECODE_SLICECODEINDEX3(6) |
+                                                           EFR32_AGC_SLICECODE_SLICECODEINDEX4(8) |
+                                                           EFR32_AGC_SLICECODE_SLICECODEINDEX5(10) |
+                                                           EFR32_AGC_SLICECODE_SLICECODEINDEX6(12));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_ATTENCODE1_ADDR, EFR32_AGC_ATTENCODE1_ATTENCODEINDEX1(1) |
+                                                           EFR32_AGC_ATTENCODE1_ATTENCODEINDEX2(2) |
+                                                           EFR32_AGC_ATTENCODE1_ATTENCODEINDEX3(3) |
+                                                           EFR32_AGC_ATTENCODE1_ATTENCODEINDEX4(4) |
+                                                           EFR32_AGC_ATTENCODE1_ATTENCODEINDEX5(5) |
+                                                           EFR32_AGC_ATTENCODE1_ATTENCODEINDEX6(6));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_ATTENCODE2_ADDR, EFR32_AGC_ATTENCODE2_ATTENCODEINDEX7(7) |
+                                                           EFR32_AGC_ATTENCODE2_ATTENCODEINDEX8(8) |
+                                                           EFR32_AGC_ATTENCODE2_ATTENCODEINDEX9(9) |
+                                                           EFR32_AGC_ATTENCODE2_ATTENCODEINDEX10(10) |
+                                                           EFR32_AGC_ATTENCODE2_ATTENCODEINDEX11(11) |
+                                                           EFR32_AGC_ATTENCODE2_ATTENCODEINDEX12(12));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_ATTENCODE3_ADDR, EFR32_AGC_ATTENCODE3_ATTENCODEINDEX13(13) |
+                                                           EFR32_AGC_ATTENCODE3_ATTENCODEINDEX14(14) |
+                                                           EFR32_AGC_ATTENCODE3_ATTENCODEINDEX15(15) |
+                                                           EFR32_AGC_ATTENCODE3_ATTENCODEINDEX16(16) |
+                                                           EFR32_AGC_ATTENCODE3_ATTENCODEINDEX17(17) |
+                                                           EFR32_AGC_ATTENCODE3_ATTENCODEINDEX18(18));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_GAINSTEPLIM_ADDR, EFR32_AGC_GAINSTEPLIM_FASTSTEPDOWN(5) |
+                                                           EFR32_AGC_GAINSTEPLIM_FASTSTEPUP(2) |
+                                                           EFR32_AGC_GAINSTEPLIM_CFLOOPSTEPMAX(8) |
+                                                           EFR32_AGC_GAINSTEPLIM_SLOWDECAYCNT(1) |
+                                                           EFR32_AGC_GAINSTEPLIM_ADCATTENMODE(DISABLE));
+
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_LOOPDEL_ADDR, EFR32_AGC_LOOPDEL_PKDWAIT(25) |
+                                                           EFR32_AGC_LOOPDEL_IFPGADEL(12) |
+                                                           EFR32_AGC_LOOPDEL_LNASLICESDEL(16));
+  cpu_mem_write_32(EFR32_AGC_ADDR + EFR32_AGC_MININDEX_ADDR, EFR32_AGC_MININDEX_INDEXMINSLICES(18) |
+                                                           EFR32_AGC_MININDEX_INDEXMINDEGEN(24) |
+                                                           EFR32_AGC_MININDEX_INDEXMINPGA(27));
+
+  struct radio_efr32_ctx_s *pv = &ctx->pv;
+
+  /* Sequencer code initialisaton */
+  efr32_radio_seq_init(pv, seqcode, 4 * seqcode_size);
+
+  /* Turn off radio */
+  efr32_rfp_disable(ctx);
+
+  /* Timer init */
+  efr32_protimer_init(&pv->pti);
+
+  uint32_t x = bit_ctz32(EFR32_RADIO_RFP_BUFFER_SIZE) - 6;
+
+  // TX/RX buffers initialisation 
+
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CTRL_ADDR(0), x);
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_ADDR_ADDR(0), (uint32_t)ctx->sg_buffer);
+
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CTRL_ADDR(1), x);
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_ADDR_ADDR(1), (uint32_t)ctx->sg_buffer);
+
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_ADDR_ADDR(2), (uint32_t)ctx->pv.rx_length_buffer);
+  cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CTRL_ADDR(2), 0);
+
+  /* Configure variable length mode */
+  x = EFR32_FRC_CTRL_RXFCDMODE(FCDMODE2) |
+      EFR32_FRC_CTRL_TXFCDMODE(FCDMODE2) |
+      EFR32_FRC_CTRL_BITORDER(MSB) |
+      EFR32_FRC_CTRL_BITSPERWORD(7);
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_CTRL_ADDR, x);
+
+  x = EFR32_FRC_DFLCTRL_DFLMODE(SINGLEBYTE) |
+      EFR32_FRC_DFLCTRL_MINLENGTH(1) |
+      EFR32_FRC_DFLCTRL_DFLBITS(8);
+
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_DFLCTRL_ADDR, x);
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_MAXLENGTH_ADDR, EFR32_RADIO_RFP_BUFFER_SIZE - 1);
+
+  /* Clear buffer */
+  for (uint8_t i = 0; i < 4; i++)
+    cpu_mem_write_32(EFR32_BUFC_ADDR + EFR32_BUFC_CMD_ADDR(i), EFR32_BUFC_CMD_CLEAR);
+
+  /* Enable irq */
+  x = cpu_mem_read_32(EFR32_FRC_ADDR + EFR32_FRC_IEN_ADDR);
+  x |= EFR32_TX_IRQ_FRC_MSK | EFR32_RX_IRQ_FRC_MSK;
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_IFC_ADDR, x); 
+  cpu_mem_write_32(EFR32_FRC_ADDR + EFR32_FRC_IEN_ADDR, x);
+
+  return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/drivers/radio/sequencer.seq	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,732 @@
+/*
+   This file is part of MutekH.
+
+   MutekH is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; version 2.1 of the
+   License.
+
+   MutekH is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with MutekH; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.
+
+   Copyright (c) 2017 Sebastien Cerdan <sebcerdan@gmail.com>
+
+*/
+
+.baseaddr 0x21000000
+
+entry_state_off:
+        /* 1 */
+        jmp              __entry_state_off           
+
+entry_state_rxwarm:
+        /* 2 */
+        jmp              __entry_rxwarm           
+
+entry_state_rxsearch:
+        /* 3 */
+        jmp              __entry_rxsearch           
+
+entry_state_rxframe:
+        /* 4 */
+        jmp              __entry_rxframe           
+
+entry_state_rxpd:
+        /* 5 */
+        jmp              __entry_rxpd_ovf           
+
+entry_state_rx2rx:
+        /* 6 */
+        jmp              __entry_rx2rx           
+
+entry_state_rxoverflow:
+        /* 5 */
+        jmp              __entry_rxpd_ovf           
+
+entry_state_rx2tx:
+        /* 7 */
+        jmp              __entry_rx2tx           
+
+entry_state_txwarm:
+        /* 8 */
+        jmp              __entry_txwarm           
+
+entry_state_tx:
+        /* 9 */
+        jmp              __entry_tx           
+
+entry_state_txpd:
+        /* a */
+        jmp              __entry_txpd           
+
+entry_state_tx2rx:
+        /* b */
+        jmp              __entry_tx2rx           
+
+entry_state_tx2tx:
+        /* c */
+        jmp              __entry_tx2tx           
+
+entry_state_shutdown:
+        /* d */
+        jmp              __entry_shutdown        
+
+#include "common.h"
+#include "debug.seq"
+
+#define RESET_SP()                                              \
+        cst32            r0, EFR32_SEQ_STACK_POINTER_ADDR;      \
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_R_ADDR(6)], r0
+
+__entry_state_off:        // function call from: entry_state_off
+        GPIO_LOG(1)
+        RESET_SP()
+        STACK_TEST(1)
+        call             _disable_radio
+        end                                  
+
+__entry_rxwarm:        // function call from: entry_state_rxwarm
+        GPIO_LOG(2)
+        RESET_SP()
+        STACK_TEST(2)
+	/* Test if buffer is empty before warming */
+        ld.rac           r0, [EFR32_RAC_ADDR + EFR32_RAC_IFPGACTRL_ADDR] 
+        andi.nowb        r0, EFR32_RAC_IFPGACTRL_BANDSEL(SG)            
+        jz               _rxwarmstart
+        cst32            r1, EFR32_BUFC_ADDR + EFR32_BUFC_STATUS_ADDR(1)      
+        ld               r0, [r1]          
+        andi.nowb        r0, 0xff            
+        /* Buffer is empty */ 
+        jz               _rxwarmstart
+        call 		 __stop_rx
+        cst8             r1,  EFR32_RAC_STATUS_STATE_OFF
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_FORCESTATE_ADDR], r1
+        end
+    _rxwarmstart:
+        call             _wait_before_op
+        call             _clear_hfxoretimectrl_en_bit 
+        cst32            r2, EFR32_SYNTH_ADDR + EFR32_SYNTH_CMD_ADDR       
+        bitband          [r2], EFR32_SYNTH_CMD_SYNTHSTOP_IDX, SET, 0    
+        /* Enable if */
+        bitband          [r2], EFR32_SYNTH_CMD_ENABLEIF_IDX, SET, 0  
+        /* Do not set synthenctrl.lpfbwsel bit */
+        cst32            r3, 0x0        
+        call             __cfg_synth 
+        /* Might need to configure DCDC here when used */
+        call             _rx_no_synth_cfg
+        /* Clear Sync Word detection bit */
+        cst32            r1, EFR32_MODEM_ADDR + EFR32_MODEM_IFC_ADDR
+        bitband          [r1], EFR32_MODEM_IF_RXFRAMEDET0_IDX, SET, 0
+        end                                  
+
+__entry_rxpd_ovf:        // function call from: entry_state_rxpd, entry_state_rxoverflow
+        // in {r1, sp, pc, sr0, sr1, sr3}
+        GPIO_LOG(5)
+        RESET_SP()
+        STACK_TEST(5)
+        /* Test buf1 overflow */
+        cst32            r4, EFR32_BUFC_ADDR + EFR32_BUFC_IF_ADDR    
+        ld               r2, [r4]            
+        cst32            r0, EFR32_BUFC_IF_OF(1)            
+        and              r2, r0             
+        /* No overflow */
+        jz               _no_ovf           
+        /* Clear buf1 ovf irq */
+        addi             r4, 8	  
+        st               [r4], r2            
+        cst32            r4, EFR32_FRC_ADDR + EFR32_FRC_IFS_ADDR    
+        bitband          [r4], EFR32_FRC_IF_RXABORTED_IDX, SET, 0  
+        jmp              _set_idle
+    _no_ovf:
+        ld.rac           r0, [EFR32_RAC_ADDR + EFR32_RAC_IFPGACTRL_ADDR] 
+        andi.nowb        r0, EFR32_RAC_IFPGACTRL_BANDSEL(SG)            
+        jnz              _set_idle
+        cst32            r1, 250
+        call             _schedule_next_op
+        jmp              _rxpd_end
+    _set_idle:
+        /* Stop Rx */
+        call 		 __stop_rx
+        cst8             r1,  EFR32_RAC_STATUS_STATE_OFF
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_FORCESTATE_ADDR], r1
+    _rxpd_end:
+        end                                  
+
+__entry_rx2rx:        // function call from: entry_state_rx2rx
+        // in {r1, sp, pc, sr0, sr1, sr3}
+        GPIO_LOG(6)
+        RESET_SP()
+        STACK_TEST(6)
+        call 		 __stop_rx
+        cst8             r1,  EFR32_RAC_STATUS_STATE_OFF
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_FORCESTATE_ADDR], r1
+        cst32            r0, EFR32_FRC_ADDR + EFR32_FRC_IFS_ADDR
+	/* Raise RX aborted error */
+        bitband          [r0], EFR32_FRC_IF_RXABORTED_IDX, SET, 0  
+        end                                  
+
+__entry_rx2tx:        // function call from: entry_state_rx2tx
+        // in {r1, sp, pc, sr0, sr1, sr2, sr3}
+        GPIO_LOG(7)
+        STACK_TEST(7)
+        RESET_SP()
+        sleep            316            /* Wait for 150 us */
+        end
+
+__entry_txwarm:        // function call from: entry_state_txwarm
+        // in {r1, sp, pc, sr0, sr1, sr2, sr3}
+        GPIO_LOG(8)
+        RESET_SP()
+        STACK_TEST(8)
+        call             _wait_before_op
+        call             _reset_tx
+        call             _clear_hfxoretimectrl_en_bit
+
+        /* Might Clear CMU HFXOCTRL1 SQBMODE here */
+
+        cst32            r2, EFR32_SYNTH_ADDR + EFR32_SYNTH_CMD_ADDR       
+        bitband          [r2], EFR32_SYNTH_CMD_SYNTHSTOP_IDX, SET, 0     
+        /* Disable if */
+        bitband          [r2], EFR32_SYNTH_CMD_DISABLEIF_IDX, SET, 0    
+
+        /* Set synthenctrl.lpfbwsel bit */
+        cst32            r3, EFR32_RAC_SYNTHENCTRL_LPFBWSEL
+        call             __cfg_synth 
+        call             __start_tx
+        end
+
+__entry_tx:        // function call from: entry_state_tx
+        // in {r1, sp, pc, sr0, sr1, sr3}
+        GPIO_LOG(9)
+        RESET_SP()
+        STACK_TEST(9)
+        end
+
+__entry_txpd:        // function call from: entry_state_txpd
+        // in {r1, sp, pc, sr0, sr1, sr3}
+        GPIO_LOG(0xa)
+        RESET_SP()
+        STACK_TEST(0xa)
+        cst32            r1, 180
+        call             _schedule_next_op
+        end
+
+__entry_tx2rx:        // function call from: entry_state_tx2rx
+        // in {r1, sp, pc, sr0, sr1, sr3}
+        GPIO_LOG(0xb)
+        RESET_SP()
+        STACK_TEST(0xb)
+        sleep            250            /* Wait for less than 150 us */
+        end
+
+
+__entry_tx2tx:        // function call from: entry_state_tx2tx
+        // in {r1, sp, pc, sr0, sr1, sr2, sr3}
+        GPIO_LOG(0xc)
+        RESET_SP()
+        STACK_TEST(0xC)
+        end
+
+__entry_shutdown:        // function call from: entry_state_shutdown
+        // in {r1, sp, pc, sr0, sr1, sr3}
+        GPIO_LOG(0xd)
+        RESET_SP()
+        STACK_TEST(0xd)
+        call             _disable_radio
+        end                                  
+
+__entry_rxsearch:        // function call from: entry_state_rxsearch
+        // in {r1, sp, pc, sr0, sr1, sr3}
+        STACK_TEST(3)
+        RESET_SP()
+        GPIO_LOG(3)
+        ld.rac           r0, [EFR32_RAC_ADDR + EFR32_RAC_IFPGACTRL_ADDR] 
+        andi.nowb        r0, EFR32_RAC_IFPGACTRL_BANDSEL(SG)            
+        jnz              _rxsearch_end
+        /* Wait at leat 50 us in BLE before ending RX */
+        sleep            0x200
+        cst32            r1, EFR32_MODEM_ADDR + EFR32_MODEM_IF_ADDR
+        ld               r0, [r1]          
+        ror              r0, 8
+        andi             r0, (EFR32_MODEM_IF_RXFRAMEDET0 >> 8)
+          jnz            _rxsearch_end
+        /* Stop RX */
+        GPIO_LOG(0xF)
+        call 		 __stop_rx
+        cst8             r1,  EFR32_RAC_STATUS_STATE_OFF
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_FORCESTATE_ADDR], r1
+        cst32            r0, EFR32_FRC_ADDR + EFR32_FRC_IFS_ADDR
+        bitband          [r0], EFR32_FRC_IF_RXABORTED_IDX, SET, 0  
+    _rxsearch_end:
+        end
+
+__entry_rxframe:        // function call from: entry_state_rxframe
+        // in {r1, sp, pc, sr0, sr1, sr3}
+        GPIO_LOG(4)
+        RESET_SP()
+        STACK_TEST(4)
+        call 		 __stop_rx
+        end
+
+__stop_rx:
+        cst8             r0,  EFR32_RAC_RXENSRCEN_ADDR    
+        bitband          [r0], 1, CLEAR, 1 
+	ret
+
+_disable_paramp:
+        cst8             r0, 0x00            
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_PAENCTRL_ADDR], r0  
+        cst32            r4, EFR32_MODEM_ADDR + EFR32_MODEM_RAMPCTRL_ADDR  
+        ld               r1, [r4]           
+        ror              r1, 8
+        ror              r1, 8
+        andi.nowb        r1, 0x80            
+        jnz              _wait_ramp_done_ret           
+        waitmask         EFR32_RAC_WAITMASK_RAMPDONE               
+    _wait_ramp_done_ret: 
+        ret                                  
+
+_disable_radio:
+        call             _disable_paramp
+        ld.rac           r0, [EFR32_RAC_ADDR + EFR32_RAC_IFPGACTRL_ADDR] 
+        cst32            r4, EFR32_RAC_SGRFENCTRL0_ADDR   
+        andi.nowb        r0, EFR32_RAC_IFPGACTRL_BANDSEL(SG)            
+        jnz              _reset_rf_ctrl
+        cst32            r4, EFR32_RAC_RFENCTRL0_ADDR
+
+    _reset_rf_ctrl:
+        mov              r3, r4              
+        addi             r3, 12	  
+        bitband          [r4], EFR32_RAC_RFENCTRL0_PAOUTEN_IDX, CLEAR, 1  
+        bitband          [r3], EFR32_RAC_PAPKDCTRL_PKDEN_IDX, CLEAR, 1   
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SYNTHENCTRL_ADDR], r0
+        cst32            r4, EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL0_ADDR
+        xor              r0, r0              
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SYNTHCTRL_ADDR], r0 
+        sleep            0x005               
+        bitband          [r4], EFR32_RAC_RFENCTRL0_STRIPESLICEDIS_IDX, SET, 1    
+        sleep            0x00a               
+        bitband          [r4], EFR32_RAC_RFENCTRL0_CASCODEDIS_IDX, SET, 1    
+        sleep            0x005               
+        bitband          [r4], EFR32_RAC_RFENCTRL0_PASTANDBY_IDX, CLEAR, 1  
+        cst8             r0, EFR32_RAC_CMD_ADDR
+        bitband          [r0], EFR32_RAC_CMD_PAENCLEAR_IDX, SET, 1    
+        ret                                 
+
+__cfg_synth:
+        cst8             r0, 0x00            
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SYNTHENCTRL_ADDR], r0
+
+        /* Set vcoamplitude = 0xe */
+        ld.rac           r0, [EFR32_RAC_ADDR + EFR32_RAC_VCOCTRL_ADDR]   
+        cst32            r1, 0xfffffff0      
+        and              r0, r1              
+        cst8             r1, 0x0e            
+        or               r0, r1              
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_VCOCTRL_ADDR], r0  
+
+        /* Set vcotunning = 0x80 */
+        cst8             r0, 0x80            
+        cst32            r1, EFR32_SYNTH_ADDR + EFR32_SYNTH_VCOTUNING_ADDR 
+        st               [r1], r0            
+
+        cst32            r0, (EFR32_RAC_SYNTHENCTRL_SYNTHCLKEN | EFR32_RAC_SYNTHENCTRL_SYNTHSTARTREQ | EFR32_RAC_SYNTHENCTRL_CHPLDOEN | EFR32_RAC_SYNTHENCTRL_LODIVSYNCCLKEN | EFR32_RAC_SYNTHENCTRL_MMDLDOEN | EFR32_RAC_SYNTHENCTRL_VCOLDOEN)
+
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SYNTHENCTRL_ADDR], r0
+
+        sleep            0x005               
+
+        cst32            r0, EFR32_SYNTH_ADDR + EFR32_SYNTH_VCDACCTRL_ADDR 
+        bitband          [r0], EFR32_SYNTH_VCDACCTRL_EN_IDX, SET, 0     
+
+        cst32            r0, (EFR32_RAC_SYNTHENCTRL_SYNTHCLKEN | EFR32_RAC_SYNTHENCTRL_SYNTHSTARTREQ | EFR32_RAC_SYNTHENCTRL_CHPLDOEN | EFR32_RAC_SYNTHENCTRL_LODIVSYNCCLKEN| EFR32_RAC_SYNTHENCTRL_MMDLDOEN | EFR32_RAC_SYNTHENCTRL_VCOLDOEN | EFR32_RAC_SYNTHENCTRL_LODIVSYNCCLKEN | EFR32_RAC_SYNTHENCTRL_VCOEN | EFR32_RAC_SYNTHENCTRL_VCOSTARTUP | EFR32_RAC_SYNTHENCTRL_LPFEN | EFR32_RAC_SYNTHENCTRL_LPFQUICKSTART | EFR32_RAC_SYNTHENCTRL_VCODIVEN)
+
+        or               r0, r3              
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SYNTHENCTRL_ADDR], r0
+
+        sleep            0x005               
+        waitmask         EFR32_RAC_WAITMASK_SYNTHRDY               
+        
+        /* Set CAPCALSTART bit and wait ready */
+        bitband          [r2], EFR32_SYNTH_CMD_CAPCALSTART_IDX, SET, 0     
+        waitmask         EFR32_RAC_WAITMASK_SYNTHRDY               
+
+        xori             r0, 0x18           
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SYNTHENCTRL_ADDR], r0
+
+        /* Set vcoamplitude = 0xa */
+        ld.rac           r0, [EFR32_RAC_ADDR + EFR32_RAC_VCOCTRL_ADDR]   
+        cst8             r1, 0x0a            
+        xor              r1, r0              
+        andi             r1, 0x0f            
+        xor              r0, r1              
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_VCOCTRL_ADDR], r0 
+
+        sleep            0x005              
+
+        /* Set SYNTHSTART bit */
+        bitband          [r2], EFR32_SYNTH_CMD_SYNTHSTART_IDX, SET, 0     
+        waitmask         EFR32_RAC_WAITMASK_SYNTHRDY               
+        sleep            0x00f
+        
+        /* Clear SYNTHENCTRL.VCOSTARTUP and SYNTHENCTRL.LPFQUICKSTART bits */
+        cst8             r0, EFR32_RAC_SYNTHENCTRL_ADDR            
+        bitband          [r0], EFR32_RAC_SYNTHENCTRL_LPFQUICKSTART_IDX, CLEAR, 1   
+        bitband          [r0], EFR32_RAC_SYNTHENCTRL_VCOSTARTUP_IDX, CLEAR, 1  
+
+        jmp              __wait_vco_stabilize
+
+__wait_vco_stabilize:
+
+        cst32            r0, EFR32_SYNTH_ADDR + EFR32_SYNTH_VCORANGE_ADDR
+        cst32            r1, (EFR32_SYNTH_VCORANGE_HIGHTHRESH(5) | EFR32_SYNTH_VCORANGE_LOWTHRESH(5) | EFR32_SYNTH_VCORANGE_SWITCHMODE | EFR32_SYNTH_VCORANGE_MODE(MANUAL))
+        st               [r0], r1           
+
+        /* Might need sleep here */
+//        sleep            0x200               
+//        sleep            0x200               
+        sleep            0x10               
+
+    __clear_synth_vco_irq:
+        /* Clear SYNTHIF bit 4 and 5 */
+        cst32            r0, EFR32_SYNTH_ADDR + EFR32_SYNTH_IFC_ADDR 
+        bitband          [r0], EFR32_SYNTH_IF_VCOLOW_IDX, SET, 0     
+        bitband          [r0], EFR32_SYNTH_IF_VCOHIGH_IDX, SET, 0    
+
+        sleep            0x096              
+
+        cst32            r0, EFR32_SYNTH_ADDR + EFR32_SYNTH_IF_ADDR   
+        ld               r1, [r0]            
+        andi             r1, 0x30            
+        jnz              __clear_synth_vco_irq           
+
+        cst32            r0, EFR32_SYNTH_ADDR + EFR32_SYNTH_VCORANGE_ADDR
+        cst32            r1, (EFR32_SYNTH_VCORANGE_SWITCHMODE | EFR32_SYNTH_VCORANGE_MODE(MANUAL))
+        st               [r0], r1            
+        cst8             r1, EFR32_SYNTH_VCORANGE_MODE(AUTO)
+        st               [r0], r1          
+        ret
+
+_clear_hfxoretimectrl_en_bit:
+        /* Clear RAC hfxoretimectrl en bit */        
+        cst8             r0, EFR32_RAC_HFXORETIMECTRL_ADDR            
+        bitband          [r0], EFR32_RAC_HFXORETIMECTRL_EN, CLEAR, 1  
+     __wait_hfxoretime_clksel_null:
+        ld.rac           r1, [EFR32_RAC_ADDR + EFR32_RAC_HFXORETIMESTATUS_ADDR]
+        andi.nowb        r1, 0x01            
+        jnz              __wait_hfxoretime_clksel_null
+        bitband          [r0], EFR32_RAC_HFXORETIMECTRL_RESET_IDX, CLEAR, 1  
+        /* MMD ctrl */
+        cst8             r3, EFR32_RAC_MMDCTRL_ADDR            
+        bitband          [r3], EFR32_RAC_MMDCTRL_MMDENRSDIG_IDX, SET, 1    
+        bitband          [r3], EFR32_RAC_MMDCTRL_MMDENDCDC_IDX, CLEAR, 1  
+        bitband          [r3], EFR32_RAC_MMDCTRL_MMDENRSDCDC_IDX, CLEAR, 1  
+        ret
+
+_reset_tx:
+        /* Disable IF ADC clock */
+        cst32            r0, EFR32_RAC_IFADCCTRL_ADDR            
+        bitband          [r0], 29, CLEAR, 1 
+
+        /* Disable strip slice and cascode */
+        cst32            r0, 0x3000000       
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SGRFENCTRL0_ADDR], r0
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL0_ADDR], r0
+
+        /* Keep DEMEN bit */
+        ld.rac           r1, [EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL_ADDR]  
+        cst32            r0, 0x1000            
+        and              r1, r0              
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL_ADDR], r1 
+
+        /* Set lnaenclear bit */
+        cst8             r0, EFR32_RAC_CMD_ADDR    
+        bitband          [r0], EFR32_RAC_CMD_LNAENCLEAR_IDX, SET, 1  
+
+        ret
+
+__start_tx:
+
+        /* Set RAC PA en bit */
+        cst8             r0, EFR32_RAC_CMD_ADDR    
+        bitband          [r0], EFR32_RAC_CMD_PAENSET_IDX, SET, 1    
+
+        // Disable PA VHigh; PA VLow; PA BatHigh
+        cst8             r0, EFR32_RAC_IEN_ADDR            
+        bitband          [r0], EFR32_RAC_IF_PAVLOW_IDX, CLEAR, 1  
+        bitband          [r0], EFR32_RAC_IF_PAVHIGH_IDX, CLEAR, 1  
+        bitband          [r0], EFR32_RAC_IF_PABATHIGH_IDX, CLEAR, 1  
+        // Set PA CTuneSel
+        cst32            r0, EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL_ADDR    
+        bitband          [r0], EFR32_RAC_RFENCTRL_PACTUNESEL_IDX, SET, 1    
+
+        cst32            r0, 0x5c00c0c4      
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_PACTRL0_ADDR], r0   
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SGPACTRL0_ADDR], r0 
+        ld.rac           r0, [EFR32_RAC_ADDR + EFR32_RAC_IFPGACTRL_ADDR] 
+        andi.nowb        r0, EFR32_RAC_IFPGACTRL_BANDSEL(SG)            
+        jz               _txconfig_2p4          
+
+    _txconfig_sg:
+        cst32            r2, EFR32_RAC_SGRFENCTRL0_PASTANDBY         
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SGRFENCTRL0_ADDR], r2
+        sleep            0x023               
+        cst32            r2, (EFR32_RAC_SGRFENCTRL0_PASTANDBY | EFR32_RAC_SGRFENCTRL0_PAEN | EFR32_RAC_SGRFENCTRL0_TRSW)
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SGRFENCTRL0_ADDR], r2
+        cst32            r4, EFR32_RAC_SGRFENCTRL0_ADDR
+        cst32            r2, EFR32_RAC_SGPACTRL0_ADDR
+        jmp              _txconfig_done
+
+    _txconfig_2p4:
+        ld.rac           r1, [EFR32_RAC_ADDR + EFR32_RAC_LNAMIXCTRL1_ADDR]
+        cst32            r0, 0xffffff9f      
+        and              r0, r1              
+        xori             r0, 0x60            
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_LNAMIXCTRL1_ADDR], r0
+
+        cst8             r0, EFR32_RAC_RFENCTRL0_ADDR            
+        bitband          [r0], EFR32_RAC_RFENCTRL0_PASTANDBY_IDX, SET, 1    
+        sleep            0x019               
+        cst32            r1, EFR32_RAC_RFENCTRL_ADDR            
+        bitband          [r1], EFR32_RAC_RFENCTRL_ENLDOPGALNA_IDX, SET, 1    
+        bitband          [r0], EFR32_RAC_RFENCTRL0_TRSW_IDX, SET, 1    
+        bitband          [r0], EFR32_RAC_RFENCTRL0_PAEN_IDX, SET, 1   
+        cst32            r4, EFR32_RAC_RFENCTRL0_ADDR
+        cst32            r2, EFR32_RAC_PACTRL0_ADDR
+
+     _txconfig_done:
+        /* Enable Cascode and stripeslice */
+        bitband          [r4], EFR32_RAC_RFENCTRL0_CASCODEDIS_IDX, CLEAR, 1  
+        sleep            0x005               
+
+        bitband          [r4], EFR32_RAC_RFENCTRL0_STRIPESLICEDIS_IDX, CLEAR, 1  
+        sleep            0x00f               
+
+        /* Set lodivtxen */
+        cst8             r3, 0x04            
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SYNTHCTRL_ADDR], r3 
+        sleep            0x005               
+
+        bitband          [r4], EFR32_RAC_RFENCTRL0_PAOUTEN_IDX, SET, 1   // PAOUT EN 
+        sleep            0x005   
+
+        cst32            r0, EFR32_RAC_PAENCTRL_ADDR            
+        bitband          [r0], EFR32_RAC_PAENCTRL_PARAMP_IDX, SET, 1 
+        waitmask         EFR32_RAC_WAITMASK_RAMPDONE 
+        ret
+
+__startdccal:
+        cst32            r0, EFR32_AGC_ADDR + EFR32_AGC_MANGAIN_ADDR     
+        ld               r1, [r0]            
+        push             r1                  
+        cst32            r1, 0x40001800      
+        st               [r0], r1           
+
+        /* AGC_MANUALCTRL */
+        addi             r0, 68	  
+        ld               r1, [r0]            
+        push             r1                 
+
+        /* AGC_CTRL0 */
+        addi             r0, -88	  // 0xffffffa8
+        ld               r1, [r0]            
+        push             r1                 
+        st               [r0], r1           
+
+        ld.rac           r1, [EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL_ADDR]  
+        push             r1                  
+        cst8             r0, EFR32_RAC_RFENCTRL_ADDR            
+        bitband          [r0], EFR32_RAC_RFENCTRL_PKDEN_IDX, CLEAR, 1  
+
+        /* IFPGACTRL */
+        addi             r0, 68	
+        bitband          [r0], EFR32_RAC_IFPGACTRL_ENOFFD_IDX, SET, 1    
+
+        /* SGRFENCTRL0 */
+        addi             r0, -40
+        bitband          [r0], EFR32_RAC_SGRFENCTRL0_TRSW_IDX, SET, 1   
+
+        /* RFENCTRL0 */
+        addi             r0, -24	
+        bitband          [r0], EFR32_RAC_RFENCTRL0_TRSW_IDX, SET, 1   
+
+        ld.rac           r2, [EFR32_RAC_ADDR + EFR32_RAC_IFPGACAL_ADDR]  
+        cst32            r4, 0x8080ffff      
+        and              r2, r4             
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_IFPGACAL_ADDR], r2  
+
+        cst8             r4, 0x01            
+        ror              r4, 2               
+        mov              r3, r4              
+        ror              r3, 8               
+
+    __rx_cal_loop:  
+        cst32            r0, EFR32_AGC_ADDR + EFR32_AGC_MANUALCTRL_ADDR  
+        cst8             r1, 0x03            
+        st               [r0], r1            
+
+        mov              r0, r0              
+        mov              r0, r0              
+
+        cst8             r1, 0x01            
+        st               [r0], r1            
+
+        mov              r0, r0              
+        mov              r0, r0              
+        mov              r0, r0              
+        mov              r0, r0              
+
+        /* AGC STATUS 1 */
+        addi             r0, -104	  // 0xffffff98
+        ld               r1, [r0]            
+        ror              r1, 8               
+        cst8             r0, 0x01            
+        ror              r0, 2               
+        and.nowb         r2, r0              
+        jz               _210007ce           
+        xori             r1, 0x04            
+
+    _210007ce:
+        andi.nowb        r1, 0x04            
+        jnz              _210007d4           
+        xor              r2, r4              
+
+    _210007d4: 
+        ror              r0, 8               
+        and.nowb         r2, r0              
+        jz               _210007dc           
+        xori             r1, 0x08            
+
+    _210007dc:
+        andi.nowb        r1, 0x08            
+        jnz              _210007e2           
+        xor              r2, r3              
+
+    _210007e2: 
+        ror              r0, 5               
+        and.nowb         r3, r0              
+        jnz              __rx_cal_done           
+        ror              r3, 1               
+        ror              r4, 1               
+        or               r2, r3              
+        or               r2, r4              
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_IFPGACAL_ADDR], r2  
+        ja               __rx_cal_loop           
+
+    __rx_cal_done:
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_IFPGACAL_ADDR], r2  
+        cst32            r0, EFR32_RAC_SGRFENCTRL0_ADDR
+        bitband          [r0], EFR32_RAC_SGRFENCTRL0_TRSW_IDX, CLEAR, 1  
+        cst32            r0, EFR32_RAC_RFENCTRL0_ADDR
+        bitband          [r0], EFR32_RAC_RFENCTRL0_TRSW_IDX, CLEAR, 1  
+        addi             r0, 64	 
+        bitband          [r0], EFR32_RAC_IFPGACTRL_ENOFFD_IDX, CLEAR, 1  
+        pop              r1                  
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL_ADDR], r1  
+        pop              r1                  
+        cst32            r0, EFR32_AGC_ADDR + EFR32_AGC_CTRL0_ADDR       
+        st               [r0], r1            
+        pop              r1                  
+        addi             r0, 88	  // 0x00000058
+        st               [r0], r1            
+        pop              r1                  
+        addi             r0, -68	  // 0xffffffbc
+        st               [r0], r1            
+        ret                                 
+
+_rx_no_synth_cfg:
+        /* Lna en set bit */ 
+        cst8             r0, EFR32_RAC_CMD_ADDR            
+        bitband          [r0], EFR32_RAC_CMD_LNAENSET_IDX, SET, 1    
+
+        cst8             r0, 0x0e            
+        ld.rac           r1, [EFR32_RAC_ADDR + EFR32_RAC_IFPGACTRL_ADDR] 
+        andi.nowb        r1, EFR32_RAC_IFPGACTRL_BANDSEL(SG)            
+        jnz              __sg_rx_cfg          
+
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL0_ADDR], r0 
+        sleep            0x014              
+        cst32            r0, 0xf             
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL0_ADDR], r0
+        jmp              _rx_cfg_done
+
+    __sg_rx_cfg:
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_SGRFENCTRL0_ADDR], r0
+        sleep            0x014               
+        cst32            r0, 0x1             
+        cst32            r1, EFM32_EMU_ADDR + EFR32_EMU_SGLNAMIXCTRL_ADDR
+        st               [r1], r0            
+
+    _rx_cfg_done:
+        cst32            r0, 0x1f8077        
+        ld.rac           r2, [EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL_ADDR]  
+        or               r2, r0              
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL_ADDR], r2  
+
+        /* Clear pactunesel and sgpactunesel bits */
+        cst32            r0, 0xfcffffff      
+        and              r2, r0             
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL_ADDR], r2  
+
+        sleep            0x014              
+
+        cst32            r0, 0x1fe077        
+        or               r2, r0              
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_RFENCTRL_ADDR], r2  
+
+        cst32            r0, EFR32_RAC_ADDR + EFR32_RAC_IFADCCTRL_ADDR           
+        bitband          [r0], EFR32_RAC_IFADCCTRL_ENABLECLK_IDX, SET, 1    
+        cst8             r0, EFR32_RAC_CMD_ADDR            
+        bitband          [r0], EFR32_RAC_IFADCCTRL_INVERTCLK_IDX, SET, 1   
+
+        call             __startdccal
+
+        /* Clear ifadccapreset bit */
+        cst8             r0, EFR32_RAC_RFENCTRL_ADDR
+        bitband          [r0], EFR32_RAC_RFENCTRL_IFADCCAPRESET_IDX, CLEAR, 1  
+
+        sleep            0x00a               
+        ret
+
+_schedule_next_op:
+        ld.rac           r0, [EFR32_RAC_ADDR + EFR32_RAC_STIMER_ADDR]  
+        addc             r0, r1              
+        cst32            r1, 0xffff          
+        and              r0, r1             
+        rol              r0, 1
+        xori             r0, 1
+        cst32            r1, EFR32_SEQ_DEADLINE_ADDR      
+        st               [r1], r0
+        ret
+
+_wait_before_op:
+        /* Get next op date */
+        cst32            r1, EFR32_SEQ_DEADLINE_ADDR      
+        ld               r1, [r1]
+        andi.nowb        r1, 1
+          jz             _wait_done
+        ror              r1, 1  
+        /* Get current stimer value */
+        ld.rac           r0, [EFR32_RAC_ADDR + EFR32_RAC_STIMER_ADDR] 
+        neg              r0, r0
+        addc             r0, r1              
+          jpos           _wait           
+        cst32            r1, 0x10000
+        addc             r0, r1              
+  _wait:
+        st.rac           [EFR32_RAC_ADDR + EFR32_RAC_STIMERCOMP_ADDR], r0
+        waitmask         EFR32_RAC_WAITMASK_STCMP              
+        xor              r0, r0
+        cst32            r1, EFR32_SEQ_DEADLINE_ADDR     
+        st               [r1], r0
+  _wait_done:
+        ret
+
+	
--- a/arch/efm32/drivers/usart/usart_char.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/usart/usart_char.c	Tue Apr 17 16:02:59 2018 +0200
@@ -32,6 +32,7 @@
 #include <device/irq.h>
 #include <device/class/char.h>
 #include <device/class/iomux.h>
+#include <device/class/uart.h>
 #include <device/clock.h>
 
 #include <arch/efm32/usart.h>
@@ -70,8 +71,8 @@
   struct dev_irq_src_s           irq_ep[2];
 #endif
 
+  struct dev_uart_config_s      cfg;
 #ifdef CONFIG_DEVICE_CLOCK_VARFREQ
-  uint32_t                      bauds;
   uint32_t                      clkdiv;
 #endif
   struct dev_freq_s             freq;
@@ -79,10 +80,10 @@
   struct dev_clock_sink_ep_s    clk_ep;
 });
 
-static uint32_t efm32_usart_char_bauds(struct device_s *dev, uint32_t bauds)
+static uint32_t efm32_usart_char_bauds(struct device_s *dev)
 {
   struct efm32_usart_context_s	*pv = dev->drv_pv;
-  return (256 * pv->freq.num) / (4 * bauds * pv->freq.denom) - 256;
+  return (256 * pv->freq.num) / (4 * pv->cfg.baudrate * pv->freq.denom) - 256;
 }
 
 static void efm32_usart_try_read(struct device_s *dev)
@@ -350,7 +351,7 @@
       struct device_s *dev = sink->dev;
       struct efm32_usart_context_s *pv = dev->drv_pv;
       pv->freq = chg->freq;
-      pv->clkdiv = endian_le32(efm32_usart_char_bauds(dev, pv->bauds));
+      pv->clkdiv = endian_le32(efm32_usart_char_bauds(dev));
       return 0;
     }
 #endif
@@ -493,12 +494,14 @@
                                EFM32_USART_FRAME_STOPBITS(ONE)));
 
   /* set baud rate */
+  if (device_get_res_uart(dev, &pv->cfg))
+    pv->cfg.baudrate = CONFIG_DRIVER_EFM32_USART_RATE;
+
 #ifdef CONFIG_DEVICE_CLOCK_VARFREQ
-  pv->bauds = CONFIG_DRIVER_EFM32_USART_RATE;
   pv->clkdiv = 0;
 #endif
   cpu_mem_write_32(pv->addr + EFM32_USART_CLKDIV_ADDR,
-                   endian_le32(efm32_usart_char_bauds(dev, CONFIG_DRIVER_EFM32_USART_RATE)));
+                   endian_le32(efm32_usart_char_bauds(dev)));
 
   /* enable the uart */
   cpu_mem_write_32(pv->addr + EFM32_USART_CMD_ADDR,
@@ -555,6 +558,7 @@
   dev_request_queue_destroy(&pv->read_q);
   dev_request_queue_destroy(&pv->write_q);
 
+  device_iomux_cleanup(dev);
   mem_free(pv);
 
   return 0;
--- a/arch/efm32/drivers/usart/usart_printk.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/usart/usart_printk.c	Tue Apr 17 16:02:59 2018 +0200
@@ -121,10 +121,6 @@
 
 #define USART_CLOCK            38400000
 
-  cpu_mem_write_32(b + EFM32_CMU_OSCENCMD_ADDR, EFM32_CMU_OSCENCMD_HFRCOEN);
-  while (!(cpu_mem_read_32(b + EFM32_CMU_STATUS_ADDR) & EFM32_CMU_STATUS_HFRCORDY))
-    ;
-  cpu_mem_write_32(b + EFM32_CMU_HFCLKSEL_ADDR, EFM32_CMU_HFCLKSEL_HF(HFRCO));
   /* Enable clock for HF peripherals */
   x = cpu_mem_read_32(b + EFM32_CMU_CTRL_ADDR);
   cpu_mem_write_32(b + EFM32_CMU_CTRL_ADDR, x | EFM32_CMU_CTRL_HFPERCLKEN);
@@ -134,6 +130,7 @@
   /* Enable clock for GPIO */
   x = cpu_mem_read_32(b + EFM32_CMU_HFBUSCLKEN0_ADDR);
   cpu_mem_write_32(b + EFM32_CMU_HFBUSCLKEN0_ADDR, x | EFM32_CMU_HFBUSCLKEN0_GPIO);
+
 #elif CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFM
 
 #define USART_CLOCK            14000000
--- a/arch/efm32/drivers/usart/usart_spi.c	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/drivers/usart/usart_spi.c	Tue Apr 17 16:02:59 2018 +0200
@@ -66,9 +66,9 @@
   struct dev_clock_sink_ep_s     clk_ep;
 
 #if defined(CONFIG_DRIVER_EFM32_DMA) || defined(CONFIG_DRIVER_EFR32_DMA)
-  DEV_DMA_RQ_TYPE(1)             dma_rd_rq; 
-  struct dev_dma_rq_s            dma_wr_rq;
-  struct dev_dma_desc_s          dma_wr_desc;
+  struct dev_dma_rq_s            dma_rd_rq;
+  struct dev_dma_desc_s          dma_rd_desc;
+  DEV_DMA_RQ_TYPE(1)             dma_wr_rq; 
   struct device_dma_s            dma;
   struct device_s                *spi;
 #endif
@@ -313,21 +313,38 @@
   return 0;
 }
 
+static enum dev_dma_inc_e efm32_usart_spi_get_dma_inc(uint_fast8_t width)
+{
+  switch (width)
+    {
+    case 4:
+      return DEV_DMA_INC_4_UNITS; 
+    case 2:
+      return DEV_DMA_INC_2_UNITS; 
+    case 1:
+      return DEV_DMA_INC_1_UNITS; 
+    default:
+      return DEV_DMA_INC_0_UNIT; 
+    }
+}
+
 static void efm32_usart_spi_start_dma(struct efm32_usart_spi_context_s *pv)
 {
   pv->dma_use = 1;
 
-  struct dev_dma_desc_s * desc = &pv->dma_wr_desc;
+  struct dev_dma_desc_s * desc = pv->dma_wr_rq.desc;
+  struct dev_spi_ctrl_transfer_s *tr = pv->tr;
 
   /* TX */
-  desc->src.mem.addr = (uintptr_t)pv->tr->data.out;
-  desc->src.mem.size = pv->tr->data.count - 1;
-
-  desc = pv->dma_rd_rq.desc;
+  desc->src.mem.addr = (uintptr_t)tr->data.out;
+  desc->src.mem.inc = efm32_usart_spi_get_dma_inc(tr->data.out_width);
+  desc->src.mem.size = tr->data.count - 1;
 
   /* RX */
-  desc->dst.mem.addr = (uintptr_t)pv->tr->data.in;
-  desc->src.mem.size = pv->tr->data.count - 1;
+  desc = &pv->dma_rd_desc;
+  desc->dst.mem.addr = (uintptr_t)tr->data.in;
+  desc->dst.mem.inc = efm32_usart_spi_get_dma_inc(tr->data.in_width);
+  desc->src.mem.size = tr->data.count - 1;
   
   /* Start DMA request */ 
   DEVICE_OP(&pv->dma, request, &pv->dma_rd_rq, &pv->dma_wr_rq, NULL);
@@ -344,14 +361,14 @@
 
   LOCK_SPIN_IRQ(&dev->lock);
 
+  tr->err = 0;
+
   if (pv->tr != NULL)
     tr->err = -EBUSY;
   else if (tr->cs_op != DEV_SPI_CS_NOP_NOP)
     tr->err = -ENOTSUP;
-  else
+  else if (tr->data.count > 0)
     {
-      assert(tr->data.count > 0);
-      tr->err = 0;
       pv->tr = tr;
       dev->start_count |= 1;
 
@@ -365,25 +382,7 @@
       cpu_mem_write_32(pv->addr + EFM32_USART_ROUTELOC0_ADDR, endian_le32(pv->route));
       cpu_mem_write_32(pv->addr + EFM32_USART_ROUTEPEN_ADDR, endian_le32(pv->enable));
 #elif CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFM
-
-  #if 0
-      if (tr->data.out == tr->data.in)
-        {
-          pv->route &= ~EFM32_USART_ROUTE_TXPEN;
-          if (device_iomux_setup(dev, "<mosi", NULL, NULL, NULL))
-            abort();
-        }
-      else
-        {
-        pv->route |= EFM32_USART_ROUTE_TXPEN;
-          if (device_iomux_setup(dev, ">mosi", NULL, NULL, NULL))
-            abort();
-        }
-  #endif
-
-       pv->route |= EFM32_USART_ROUTE_TXPEN;
       cpu_mem_write_32(pv->addr + EFM32_USART_ROUTE_ADDR, endian_le32(pv->route));
-      
 #else
 # error
 #endif
@@ -575,15 +574,14 @@
       device_get_param_dev_accessor(dev, "dma", &pv->dma.base, DRIVER_CLASS_DMA))
     goto err_irq;
 
-  struct dev_dma_rq_s *rq = &pv->dma_rd_rq.rq;
+  /* READ */
+  struct dev_dma_rq_s *rq = &pv->dma_rd_rq;
   struct dev_dma_desc_s *desc = rq->desc;
 
   desc->src.reg.addr = pv->addr + EFM32_USART_RXDATA_ADDR;
   desc->src.reg.width = 0;
   desc->src.reg.burst = 1;
-  desc->dst.mem.inc = DEV_DMA_INC_1_UNITS;
 
-  /* READ */
   rq->dev_link.src = read_link;
   rq->type = DEV_DMA_REG_MEM;
   rq->desc_count_m1 = 0;
@@ -593,12 +591,11 @@
   rq->cache_ptr = NULL;
 
   /* WRITE */
-  rq = &pv->dma_wr_rq;
-  desc = &pv->dma_wr_desc;
+  rq = &pv->dma_wr_rq.rq;
+  desc = pv->dma_wr_rq.desc;
 
   desc->dst.reg.addr = pv->addr + EFM32_USART_TXDATA_ADDR;
   desc->dst.reg.burst = EFM32_USART_FIFO_SIZE;
-  desc->src.mem.inc = DEV_DMA_INC_1_UNITS;
   desc->src.mem.width = 0;
 
   rq->dev_link.dst = write_link;
@@ -649,6 +646,7 @@
   dev_spi_context_cleanup(&pv->spi_ctrl_ctx);
 #endif
 
+  device_iomux_cleanup(dev);
   mem_free(pv);
 
   return 0;
--- a/arch/efm32/efm32_stk.build	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/efm32_stk.build	Tue Apr 17 16:02:59 2018 +0200
@@ -88,3 +88,23 @@
 #  CONFIG_MUTEK_PRINTK_ADDR 0x4004a000
   CONFIG_DRIVER_EFM32_LEUART_PRINTK_PIN 2
   CONFIG_DRIVER_EFM32_LEUART_PRINTK_LOC 2
+
+%section ezr32-stk6200a
+  %inherit ezr32-stk620xa
+  CONFIG_DRIVER_RFPACKET_SI446X_CHIPPART 0x604400 
+
+%section ezr32-stk6202a
+  %inherit ezr32-stk620xa
+  CONFIG_DRIVER_RFPACKET_SI446X_CHIPPART 0x614400
+
+%section ezr32-stk620xa
+  %inherit efm32-lg330-f256-bga
+
+  CONFIG_EFM32_BOARD stk620xa
+  CONFIG_EFM32_BOARD_INIT
+  CONFIG_DRIVER_RFPACKET_SI446X
+  CONFIG_MUTEK_CONSOLE_DEVICE_PATHS "usart2"
+
+  CONFIG_MUTEK_PRINTK_ADDR 0x4000c800
+  CONFIG_DRIVER_EFM32_USART_PRINTK_PIN 19
+  CONFIG_DRIVER_EFM32_USART_PRINTK_LOC 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/flash.S	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,226 @@
+/*
+    This file is part of MutekH.
+    
+    MutekH is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation; version 2.1 of the
+    License.
+    
+    MutekH is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+    
+    You should have received a copy of the GNU Lesser General Public
+    License along with MutekH; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA.
+
+    Copyright Alexandre Becoulet <alexandre.becoulet@free.fr> (c) 2014
+*/
+
+#include <hexo/asm.h>
+#include <arch/efm32/msc.h>
+
+.syntax unified
+
+.macro LOAD_WORD dst addr tmp
+#if CONFIG_CPU_ARM32M_ARCH_VERSION >= 7
+	ldr	\dst,     [\addr]
+#else
+        ldrb    \dst,     [\addr]
+        ldrb    \tmp,     [\addr, #1]
+        lsls    \tmp,     #8
+        orrs    \dst,     \tmp
+        ldrb    \tmp,     [\addr, #2]
+        lsls    \tmp,     #16
+        orrs    \dst,     \tmp
+        ldrb    \tmp,     [\addr, #3]
+        lsls    \tmp,     #24
+        orrs    \dst,     \tmp
+#endif
+.endm
+
+/*
+  This function erases a page of flash. The msc_addr parameter
+  must point to the Memory System Controller registers.
+
+  The size of the page is device dependent. The return value
+  contains the error bits of the MSC status register.
+*/
+
+FUNC_START(.text, flash_page_erase)
+
+	push	{r4, r5, r6, r7, lr}
+
+	ldr	r3,	= EFM32_MSC_ADDR
+
+	/* copy code to stack */
+	movs	r4,	4f - 3f
+	ldr	r5,	= 3f
+	sub	sp,	4f - 3f
+	mov	r7,	sp
+1:
+	subs	r4,	#4
+	ldr	r6,	[r5, r4]
+	str	r6,	[r7, r4]
+	bne	1b
+
+	/* disable irqs */
+	mrs	r6,	primask
+	cpsid	i
+
+	/* unlock and enable flash write feature */
+	ldr	r5,	= EFM32_MSC_LOCK_LOCKKEY_UNLOCK
+	str	r5,	[r3, #EFM32_MSC_LOCK_ADDR]
+
+	movs	r5,	#EFM32_MSC_WRITECTRL_WREN
+	str	r5,	[r3, #EFM32_MSC_WRITECTRL_ADDR]
+
+	/* barrier and jump to code on stack */
+	dsb
+	isb
+
+	adds	r7,	#1
+	blx	r7
+
+	/* lock access to flash write registers */
+	movs	r5,	#0
+	str	r5,	[r3, #EFM32_MSC_WRITECTRL_ADDR]
+	str	r5,	[r3, #EFM32_MSC_LOCK_ADDR]
+
+	/* return MSC status error bits */
+	ldr	r0,	[r3, #EFM32_MSC_STATUS_ADDR]
+	movs	r1,	#(EFM32_MSC_STATUS_LOCKED | EFM32_MSC_STATUS_INVADDR)
+	ands	r0,	r1
+
+	/* restore irqs and return */
+	msr	primask,	r6
+
+	add	sp,     4f - 3f
+	pop	{r4, r5, r6, r7, pc}
+
+	.align	2
+3:
+	/* set address */
+	str	r0,	[r3, #EFM32_MSC_ADDRB_ADDR]
+	movs	r5,	#EFM32_MSC_WRITECMD_LADDRIM
+	str	r5,	[r3, #EFM32_MSC_WRITECMD_ADDR]
+
+	/* erase page */
+	movs	r5,	#EFM32_MSC_WRITECMD_ERASEPAGE
+	str	r5,	[r3, #EFM32_MSC_WRITECMD_ADDR]
+
+1:
+	/* wait for completion */
+	ldr	r5,	[r3, #EFM32_MSC_STATUS_ADDR]
+	lsrs	r5,	#(EFM32_MSC_STATUS_BUSY_SHIFT+1)
+	bcs	1b
+
+	bx	lr
+	.align	2
+4:
+FUNC_END(flash_page_erase)
+
+/*
+  This function writes data to a page of flash. The msc_addr
+  parameter must point to the Memory System Controller
+  registers. The write operation can not span across multiple pages.
+
+  The return value indicates if the new data in flash is different
+  from the passed data buffer.
+*/
+
+FUNC_START(.text, flash_page_write)
+
+	push	{r4, r5, r6, r7, lr}
+
+	ldr	r3,	= EFM32_MSC_ADDR
+        lsrs    r2,     #2
+
+	/* copy code to stack */
+	movs	r4,	5f - 3f
+	ldr	r5,	= 3f
+	sub	sp,	5f - 3f
+	mov	r7,	sp
+1:
+	subs	r4,	#4
+	ldr	r6,	[r5, r4]
+	str	r6,	[r7, r4]
+	bne	1b
+
+	/* disable irqs */
+	mrs	r6,	primask
+	cpsid	i
+
+	/* unlock and enable flash write feature */
+	ldr	r5,	= EFM32_MSC_LOCK_LOCKKEY_UNLOCK
+	str	r5,	[r3, #EFM32_MSC_LOCK_ADDR]
+
+	movs	r5,	#EFM32_MSC_WRITECTRL_WREN
+	str	r5,	[r3, #EFM32_MSC_WRITECTRL_ADDR]
+
+	/* barrier and jump to code on stack */
+	dsb
+	isb
+
+	adds	r7,	#1
+	blx	r7
+
+	/* lock access to flash write registers */
+	movs	r5,	#0
+	str	r5,	[r3, #EFM32_MSC_WRITECTRL_ADDR]
+	str	r5,	[r3, #EFM32_MSC_LOCK_ADDR]
+
+	/* restore irqs and return */
+	msr	primask,	r6
+
+	add	sp,     5f - 3f
+	pop	{r4, r5, r6, r7, pc}
+
+	.align	2
+3:
+	/* set address */
+	str	r0,	[r3, #EFM32_MSC_ADDRB_ADDR]
+	movs	r5,	#EFM32_MSC_WRITECMD_LADDRIM
+	str	r5,	[r3, #EFM32_MSC_WRITECMD_ADDR]
+2:
+	/* set data */
+        LOAD_WORD r4,   r1,     r5
+	str	r4,	[r3, #EFM32_MSC_WDATA_ADDR]
+
+	/* write once */
+	movs	r5,	#EFM32_MSC_WRITECMD_WRITEONCE
+	str	r5,	[r3, #EFM32_MSC_WRITECMD_ADDR]
+
+1:
+	/* wait for completion */
+	ldr	r5,	[r3, #EFM32_MSC_STATUS_ADDR]
+	lsrs	r5,	#(EFM32_MSC_STATUS_BUSY_SHIFT+1)
+	bcs	1b
+
+	/* readback and test */
+        LOAD_WORD r7,   r0,     r5
+        mvns    r4,     r4
+        ands    r7,     r4
+        bne     4f
+
+	/* repeat */
+	adds	r1,	#4
+	adds	r0,	#4
+	subs	r2,	#1
+#if CONFIG_EFM32_FAMILY == EFM32_FAMILY_GECKO
+	bne	3b
+#else
+	bne	2b
+#endif
+
+        movs    r0, #0
+	bx	lr
+4:
+        movs    r0, #1
+	bx	lr
+
+	.align	2
+5:
+FUNC_END(flash_page_write)
--- a/arch/efm32/include/arch/efm32/efm/leopard/clock.h	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/include/arch/efm32/efm/leopard/clock.h	Tue Apr 17 16:02:59 2018 +0200
@@ -85,7 +85,7 @@
 # define EFM32_CLOCK_UART1 EFM32_CLOCK_UART1
 #endif
 
-#ifdef CONFIG_DRIVER_EFM32_I2C
+#if defined(CONFIG_DRIVER_EFM32_I2C) || defined(CONFIG_DRIVER_EFM32_I2C_SLAVE)
   EFM32_CLOCK_I2C0,
 # define EFM32_CLOCK_I2C0 EFM32_CLOCK_I2C0
   EFM32_CLOCK_I2C1,
--- a/arch/efm32/include/arch/efm32/efm/timer.h	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/include/arch/efm32/efm/timer.h	Tue Apr 17 16:02:59 2018 +0200
@@ -322,12 +322,7 @@
     #define EFM32_TIMER_CC_CTRL_INSEL_PIN              0x00000000
     #define EFM32_TIMER_CC_CTRL_INSEL_PRS              0x00000001
 /** Enable digital filter. @multiple */
-  #define EFM32_TIMER_CC_CTRL_FILT(v)                ((EFM32_TIMER_CC_CTRL_FILT_##v) << 21)
-  #define EFM32_TIMER_CC_CTRL_FILT_SET(x, v)         do { (x) = (((x) & ~0x200000) | ((EFM32_TIMER_CC_CTRL_FILT_##v) << 21)); } while(0)
-  #define EFM32_TIMER_CC_CTRL_FILT_SETVAL(x, v)      do { (x) = (((x) & ~0x200000) | ((v) << 21)); } while(0)
-  #define EFM32_TIMER_CC_CTRL_FILT_GET(x)            (((x) >> 21) & 0x1)
-    #define EFM32_TIMER_CC_CTRL_FILT_DISBALED          0x00000000
-    #define EFM32_TIMER_CC_CTRL_FILT_ENABLED           0x00000001
+  #define EFM32_TIMER_CC_CTRL_FILT                 0x00200000
 /** These bits control which edges the edge detector triggers on. The output is
    used for input capture and external clock input. @multiple */
   #define EFM32_TIMER_CC_CTRL_ICEDGE(v)              ((EFM32_TIMER_CC_CTRL_ICEDGE_##v) << 24)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/include/arch/efm32/efr/agc.h	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,8 @@
+
+#include "../chips.h"
+
+#if CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12
+# include "xg12/agc.h"
+#else
+# error not supported
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/include/arch/efm32/efr/bufc.h	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,8 @@
+
+#include "../chips.h"
+
+#if CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12
+# include "xg12/bufc.h"
+#else
+# error not supported
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/include/arch/efm32/efr/crc.h	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,8 @@
+
+#include "../chips.h"
+
+#if CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12
+# include "xg12/crc.h"
+#else
+# error not supported
+#endif
--- a/arch/efm32/include/arch/efm32/efr/devaddr.h	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/include/arch/efm32/efr/devaddr.h	Tue Apr 17 16:02:59 2018 +0200
@@ -2,10 +2,21 @@
 #ifndef EFM32_DEVADDR_H_
 #define EFM32_DEVADDR_H_
 
-#define EFM32_RMU_ADDR 0x400e5000
-#define EFM32_EMU_ADDR 0x400e3000
-#define EFM32_CMU_ADDR 0x400e4000
-#define EFM32_GPIO_ADDR 0x4000a000
+#define EFM32_RMU_ADDR 	     0x400e5000
+#define EFM32_EMU_ADDR       0x400e3000
+#define EFM32_CMU_ADDR       0x400e4000
+#define EFM32_GPIO_ADDR      0x4000a000
+#define EFM32_PRS_ADDR       0x400e6000
+
+#define EFR32_FRC_ADDR       0x40080000
+#define EFR32_BUFC_ADDR      0x40081000
+#define EFR32_CRC_ADDR       0x40082000
+#define EFR32_SYNTH_ADDR     0x40083000
+#define EFR32_RAC_ADDR       0x40084000
+#define EFR32_PROTIMER_ADDR  0x40085000
+#define EFR32_MODEM_ADDR     0x40086000
+#define EFR32_AGC_ADDR       0x40087000
+#define EFR32_RFSENSE_ADDR   0x40088000
 
 #endif
 
--- a/arch/efm32/include/arch/efm32/efr/dma_source.h	Wed Feb 07 15:11:17 2018 +0100
+++ b/arch/efm32/include/arch/efm32/efr/dma_source.h	Tue Apr 17 16:02:59 2018 +0200
@@ -7,6 +7,7 @@
 #define EFM32_DMA_SOURCE_USART0   12
 #define EFM32_DMA_SOURCE_USART1   13
 #define EFM32_DMA_SOURCE_USART2   14
+#define EFM32_DMA_SOURCE_USART3   15
 #define EFM32_DMA_SOURCE_LEUART0  16
 #define EFM32_DMA_SOURCE_I2C0     20
 #define EFM32_DMA_SOURCE_TIMER0   24
@@ -34,6 +35,10 @@
 #define EFM32_DMA_SIGNAL_USART2TXBL         1
 #define EFM32_DMA_SIGNAL_USART2TXEMPTY      2
 
+#define EFM32_DMA_SIGNAL_USART3RXDATAV      0
+#define EFM32_DMA_SIGNAL_USART3TXBL         1
+#define EFM32_DMA_SIGNAL_USART3TXEMPTY      2
+
 #define EFM32_DMA_SIGNAL_LEUART0RXDATAV     0
 #define EFM32_DMA_SIGNAL_LEUART0TXBL        1
 #define EFM32_DMA_SIGNAL_LEUART0TXEMPTY     2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/include/arch/efm32/efr/frc.h	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,8 @@
+
+#include "../chips.h"
+
+#if CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12
+# include "xg12/frc.h"
+#else
+# error not supported
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/include/arch/efm32/efr/i2c.h	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,628 @@
+/***************************************
+* Auto generated by BFGen, do not edit *
+***************************************/
+
+/*
+   bfgen -o cdefs cdefs_use_reg_mask=1 cdefs_use_field_setval=1                \
+     cdefs_use_field_shift=1 cdefs_use_field_shifted_mask=1                    \
+     cdefs_sfx_field_shifter=_SHIFT_VAL
+*/
+
+#ifndef _EFM32_I2C_BFGEN_DEFS_
+#define _EFM32_I2C_BFGEN_DEFS_
+
+#define EFM32_I2C_CTRL_ADDR                          0x00000000
+#define EFM32_I2C_CTRL_MASK                          0x0007b3ff
+/** Use this bit to enable or disable the I2C module. @multiple */
+  #define EFM32_I2C_CTRL_EN                        0x00000001
+  #define EFM32_I2C_CTRL_EN_SHIFT                  0
+/** Set this bit to allow the device to be selected as an I2C slave. @multiple */
+  #define EFM32_I2C_CTRL_SLAVE                     0x00000002
+  #define EFM32_I2C_CTRL_SLAVE_SHIFT               1
+  #define EFM32_I2C_CTRL_SLAVE_SHIFT_VAL(v)        ((EFM32_I2C_CTRL_SLAVE_##v) << 1)
+  #define EFM32_I2C_CTRL_SLAVE_SET(x, v)           do { (x) = (((x) & ~0x2) | ((EFM32_I2C_CTRL_SLAVE_##v) << 1)); } while(0)
+  #define EFM32_I2C_CTRL_SLAVE_SETVAL(x, v)        do { (x) = (((x) & ~0x2) | ((v) << 1)); } while(0)
+  #define EFM32_I2C_CTRL_SLAVE_GET(x)              (((x) >> 1) & 0x1)
+    #define EFM32_I2C_CTRL_SLAVE_NOT_SLAVE           0x00000000
+    #define EFM32_I2C_CTRL_SLAVE_SLAVE               0x00000001
+/** Set to enable automatic acknowledges. @multiple */
+  #define EFM32_I2C_CTRL_AUTOACK                   0x00000004
+  #define EFM32_I2C_CTRL_AUTOACK_SHIFT             2
+/** Write to 1 to make a master transmitter send a STOP when no more data is
+   available for transmission. @multiple */
+  #define EFM32_I2C_CTRL_AUTOSE                    0x00000008
+  #define EFM32_I2C_CTRL_AUTOSE_SHIFT              3
+  #define EFM32_I2C_CTRL_AUTOSE_SHIFT_VAL(v)       ((EFM32_I2C_CTRL_AUTOSE_##v) << 3)
+  #define EFM32_I2C_CTRL_AUTOSE_SET(x, v)          do { (x) = (((x) & ~0x8) | ((EFM32_I2C_CTRL_AUTOSE_##v) << 3)); } while(0)
+  #define EFM32_I2C_CTRL_AUTOSE_SETVAL(x, v)       do { (x) = (((x) & ~0x8) | ((v) << 3)); } while(0)
+  #define EFM32_I2C_CTRL_AUTOSE_GET(x)             (((x) >> 3) & 0x1)
+    #define EFM32_I2C_CTRL_AUTOSE_MANUAL             0x00000000
+    #define EFM32_I2C_CTRL_AUTOSE_AUTOMATIC          0x00000001
+/** Write to 1 to make a master transmitter send a STOP when a NACK is received
+   from a slave. @multiple */
+  #define EFM32_I2C_CTRL_AUTOSN                    0x00000010
+  #define EFM32_I2C_CTRL_AUTOSN_SHIFT              4
+  #define EFM32_I2C_CTRL_AUTOSN_SHIFT_VAL(v)       ((EFM32_I2C_CTRL_AUTOSN_##v) << 4)
+  #define EFM32_I2C_CTRL_AUTOSN_SET(x, v)          do { (x) = (((x) & ~0x10) | ((EFM32_I2C_CTRL_AUTOSN_##v) << 4)); } while(0)
+  #define EFM32_I2C_CTRL_AUTOSN_SETVAL(x, v)       do { (x) = (((x) & ~0x10) | ((v) << 4)); } while(0)
+  #define EFM32_I2C_CTRL_AUTOSN_GET(x)             (((x) >> 4) & 0x1)
+    #define EFM32_I2C_CTRL_AUTOSN_NO_AUTOMATOC       0x00000000
+    #define EFM32_I2C_CTRL_AUTOSN_AUTOMATIC          0x00000001
+/** A master or slave will not release the bus upon losing arbitration. @multiple
+   */
+  #define EFM32_I2C_CTRL_ARBDIS                    0x00000020
+  #define EFM32_I2C_CTRL_ARBDIS_SHIFT              5
+  #define EFM32_I2C_CTRL_ARBDIS_SHIFT_VAL(v)       ((EFM32_I2C_CTRL_ARBDIS_##v) << 5)
+  #define EFM32_I2C_CTRL_ARBDIS_SET(x, v)          do { (x) = (((x) & ~0x20) | ((EFM32_I2C_CTRL_ARBDIS_##v) << 5)); } while(0)
+  #define EFM32_I2C_CTRL_ARBDIS_SETVAL(x, v)       do { (x) = (((x) & ~0x20) | ((v) << 5)); } while(0)
+  #define EFM32_I2C_CTRL_ARBDIS_GET(x)             (((x) >> 5) & 0x1)
+    #define EFM32_I2C_CTRL_ARBDIS_RELEASED           0x00000000
+    #define EFM32_I2C_CTRL_ARBDIS_PROCEED            0x00000001
+/** Set to enable address match on general call in addition to the programmed
+   slave address. @multiple */
+  #define EFM32_I2C_CTRL_GCAMEN                    0x00000040
+  #define EFM32_I2C_CTRL_GCAMEN_SHIFT              6
+  #define EFM32_I2C_CTRL_GCAMEN_SHIFT_VAL(v)       ((EFM32_I2C_CTRL_GCAMEN_##v) << 6)
+  #define EFM32_I2C_CTRL_GCAMEN_SET(x, v)          do { (x) = (((x) & ~0x40) | ((EFM32_I2C_CTRL_GCAMEN_##v) << 6)); } while(0)
+  #define EFM32_I2C_CTRL_GCAMEN_SETVAL(x, v)       do { (x) = (((x) & ~0x40) | ((v) << 6)); } while(0)
+  #define EFM32_I2C_CTRL_GCAMEN_GET(x)             (((x) >> 6) & 0x1)
+    #define EFM32_I2C_CTRL_GCAMEN_IDLE_LOW           0x00000000
+    #define EFM32_I2C_CTRL_GCAMEN_IDLE_HIGH          0x00000001
+/** Determines the interrupt and status level of the transmit buffer @multiple */
+  #define EFM32_I2C_CTRL_TXBIL                     0x00000080
+  #define EFM32_I2C_CTRL_TXBIL_SHIFT               7
+  #define EFM32_I2C_CTRL_TXBIL_SHIFT_VAL(v)        ((EFM32_I2C_CTRL_TXBIL_##v) << 7)
+  #define EFM32_I2C_CTRL_TXBIL_SET(x, v)           do { (x) = (((x) & ~0x80) | ((EFM32_I2C_CTRL_TXBIL_##v) << 7)); } while(0)
+  #define EFM32_I2C_CTRL_TXBIL_SETVAL(x, v)        do { (x) = (((x) & ~0x80) | ((v) << 7)); } while(0)
+  #define EFM32_I2C_CTRL_TXBIL_GET(x)              (((x) >> 7) & 0x1)
+    #define EFM32_I2C_CTRL_TXBIL_EMPTY               0x00000000
+    #define EFM32_I2C_CTRL_TXBIL_HALFFULL            0x00000001
+/** Determines the ratio between the low and high parts of the clock signal
+   generated on SCL as master. @multiple */
+  #define EFM32_I2C_CTRL_CLHR                      0x00000300
+  #define EFM32_I2C_CTRL_CLHR_SHIFT                8
+  #define EFM32_I2C_CTRL_CLHR_SHIFT_VAL(v)         ((EFM32_I2C_CTRL_CLHR_##v) << 8)
+  #define EFM32_I2C_CTRL_CLHR_SET(x, v)            do { (x) = (((x) & ~0x300) | ((EFM32_I2C_CTRL_CLHR_##v) << 8)); } while(0)
+  #define EFM32_I2C_CTRL_CLHR_SETVAL(x, v)         do { (x) = (((x) & ~0x300) | ((v) << 8)); } while(0)
+  #define EFM32_I2C_CTRL_CLHR_GET(x)               (((x) >> 8) & 0x3)
+    #define EFM32_I2C_CTRL_CLHR_STANDARD             0x00000000
+    #define EFM32_I2C_CTRL_CLHR_ASYMMETRIC           0x00000001
+    #define EFM32_I2C_CTRL_CLHR_FAST                 0x00000002
+/** Use to generate a timeout when SCL has been high for a given amount time
+   between a START and STOP condition. When in a bus transaction, i.e. the BUSY
+   flag is set, a timer is started whenever SCL goes high. When the timer reaches
+   the value defined by BITO, it sets the BITO interrupt flag. The BITO interrupt
+   flag will then be set periodically as long as SCL remains high. The bus idle
+   timeout is active as long as BUSY is set. It is thus stopped automatically on
+   a timeout if GIBITO is set. It is also stopped a STOP condition is detected
+   and when the ABORT command is issued. The timeout is activated whenever the
+   bus goes BUSY, i.e. a START condition is detected. @multiple */
+  #define EFM32_I2C_CTRL_BITO                      0x00003000
+  #define EFM32_I2C_CTRL_BITO_SHIFT                12
+  #define EFM32_I2C_CTRL_BITO_SHIFT_VAL(v)         ((EFM32_I2C_CTRL_BITO_##v) << 12)
+  #define EFM32_I2C_CTRL_BITO_SET(x, v)            do { (x) = (((x) & ~0x3000) | ((EFM32_I2C_CTRL_BITO_##v) << 12)); } while(0)
+  #define EFM32_I2C_CTRL_BITO_SETVAL(x, v)         do { (x) = (((x) & ~0x3000) | ((v) << 12)); } while(0)
+  #define EFM32_I2C_CTRL_BITO_GET(x)               (((x) >> 12) & 0x3)
+    #define EFM32_I2C_CTRL_BITO_OFF                  0x00000000
+    #define EFM32_I2C_CTRL_BITO_40PCC                0x00000001
+    #define EFM32_I2C_CTRL_BITO_80PCC                0x00000002
+    #define EFM32_I2C_CTRL_BITO_160PCC               0x00000003
+/** When set, the bus automatically goes idle on a bus idle timeout, allowing new
+   transfers to be initiated. @multiple */
+  #define EFM32_I2C_CTRL_GIBITO                    0x00008000
+  #define EFM32_I2C_CTRL_GIBITO_SHIFT              15
+  #define EFM32_I2C_CTRL_GIBITO_SHIFT_VAL(v)       ((EFM32_I2C_CTRL_GIBITO_##v) << 15)
+  #define EFM32_I2C_CTRL_GIBITO_SET(x, v)          do { (x) = (((x) & ~0x8000) | ((EFM32_I2C_CTRL_GIBITO_##v) << 15)); } while(0)
+  #define EFM32_I2C_CTRL_GIBITO_SETVAL(x, v)       do { (x) = (((x) & ~0x8000) | ((v) << 15)); } while(0)
+  #define EFM32_I2C_CTRL_GIBITO_GET(x)             (((x) >> 15) & 0x1)
+    #define EFM32_I2C_CTRL_GIBITO_NO_ACTION          0x00000000
+    #define EFM32_I2C_CTRL_GIBITO_NEW_TRANSFER       0x00000001
+/** Use to generate a timeout when CLK has been low for the given amount of time.
+   Wraps around and continues counting when the timeout is reached. @multiple */
+  #define EFM32_I2C_CTRL_CLTO                      0x00070000
+  #define EFM32_I2C_CTRL_CLTO_SHIFT                16
+  #define EFM32_I2C_CTRL_CLTO_SHIFT_VAL(v)         ((EFM32_I2C_CTRL_CLTO_##v) << 16)
+  #define EFM32_I2C_CTRL_CLTO_SET(x, v)            do { (x) = (((x) & ~0x70000) | ((EFM32_I2C_CTRL_CLTO_##v) << 16)); } while(0)
+  #define EFM32_I2C_CTRL_CLTO_SETVAL(x, v)         do { (x) = (((x) & ~0x70000) | ((v) << 16)); } while(0)
+  #define EFM32_I2C_CTRL_CLTO_GET(x)               (((x) >> 16) & 0x7)
+    #define EFM32_I2C_CTRL_CLTO_OFF                  0x00000000
+    #define EFM32_I2C_CTRL_CLTO_40PCC                0x00000001
+    #define EFM32_I2C_CTRL_CLTO_80PCC                0x00000002
+    #define EFM32_I2C_CTRL_CLTO_160PCC               0x00000003
+    #define EFM32_I2C_CTRL_CLTO_320PCC               0x00000004
+    #define EFM32_I2C_CTRL_CLTO_1024PCC              0x00000005
+
+#define EFM32_I2C_CMD_ADDR                           0x00000004
+#define EFM32_I2C_CMD_MASK                           0x000000ff
+/** Set to send start condition as soon as possible. If a transmission is ongoing
+   and not owned, the start condition will be sent as soon as the bus is idle. If
+   the current transmission is owned by this module, a repeated start condition
+   will be sent. Use in combination with a STOP command to automatically send a
+   STOP, then a START when the bus becomes idle. @multiple */
+  #define EFM32_I2C_CMD_START                      0x00000001
+  #define EFM32_I2C_CMD_START_SHIFT                0
+/** Set to send stop condition as soon as possible. @multiple */
+  #define EFM32_I2C_CMD_STOP                       0x00000002
+  #define EFM32_I2C_CMD_STOP_SHIFT                 1
+/** Set to transmit an ACK the next time an acknowledge is required. @multiple */
+  #define EFM32_I2C_CMD_ACK                        0x00000004
+  #define EFM32_I2C_CMD_ACK_SHIFT                  2
+/** Set to transmit a NACK the next time an acknowledge is required. @multiple */
+  #define EFM32_I2C_CMD_NACK                       0x00000008
+  #define EFM32_I2C_CMD_NACK_SHIFT                 3
+/** Set to continue transmission after a NACK has been received. @multiple */
+  #define EFM32_I2C_CMD_CONT                       0x00000010
+  #define EFM32_I2C_CMD_CONT_SHIFT                 4
+/** Abort the current transmission making the bus go idle. When used in
+   combination with STOP, a STOP condition is sent as soon as possible before
+   aborting the transmission. The stop condition is subject to clock
+   synchronization. @multiple */
+  #define EFM32_I2C_CMD_ABORT                      0x00000020
+  #define EFM32_I2C_CMD_ABORT_SHIFT                5
+/** Set to clear transmit buffer and shift register. Will not abort ongoing
+   transfer. @multiple */
+  #define EFM32_I2C_CMD_CLEARTX                    0x00000040
+  #define EFM32_I2C_CMD_CLEARTX_SHIFT              6
+/** Set to clear pending commands. @multiple */
+  #define EFM32_I2C_CMD_CLEARPC                    0x00000080
+  #define EFM32_I2C_CMD_CLEARPC_SHIFT              7
+
+#define EFM32_I2C_STATE_ADDR                         0x00000008
+#define EFM32_I2C_STATE_MASK                         0x000000ff
+/** Set when the bus is busy. Whether the I2C module is in control of the bus or
+   not has no effect on the value of this bit. When the MCU comes out of reset,
+   the state of the bus is not known, and thus BUSY is set. Use the ABORT command
+   or a bus idle timeout to force the I2C module out of the BUSY state. @multiple
+   */
+  #define EFM32_I2C_STATE_BUSY                     0x00000001
+  #define EFM32_I2C_STATE_BUSY_SHIFT               0
+/** Set when operating as an I2C master. When cleared, the system may be
+   operating as an I2C slave. @multiple */
+  #define EFM32_I2C_STATE_MASTER                   0x00000002
+  #define EFM32_I2C_STATE_MASTER_SHIFT             1
+/** Set when operating as a master transmitter or a slave transmitter. When
+   cleared, the system may be operating as a master receiver, a slave receiver or
+   the current mode is not known. @multiple */
+  #define EFM32_I2C_STATE_TRANSMITTER              0x00000004
+  #define EFM32_I2C_STATE_TRANSMITTER_SHIFT        2
+/** Set if a NACK was received and STATE is ADDRACK or DATAACK. @multiple */
+  #define EFM32_I2C_STATE_NACKED                   0x00000008
+  #define EFM32_I2C_STATE_NACKED_SHIFT             3
+/** Set if the bus is currently being held by this I2C module. @multiple */
+  #define EFM32_I2C_STATE_BUSHOLD                  0x00000010
+  #define EFM32_I2C_STATE_BUSHOLD_SHIFT            4
+/** The state of any current transmission. Cleared if the I2C module is idle.
+   @multiple */
+  #define EFM32_I2C_STATE_STATE                    0x000000e0
+  #define EFM32_I2C_STATE_STATE_SHIFT              5
+  #define EFM32_I2C_STATE_STATE_SHIFT_VAL(v)       ((EFM32_I2C_STATE_STATE_##v) << 5)
+  #define EFM32_I2C_STATE_STATE_SET(x, v)          do { (x) = (((x) & ~0xe0) | ((EFM32_I2C_STATE_STATE_##v) << 5)); } while(0)
+  #define EFM32_I2C_STATE_STATE_SETVAL(x, v)       do { (x) = (((x) & ~0xe0) | ((v) << 5)); } while(0)
+  #define EFM32_I2C_STATE_STATE_GET(x)             (((x) >> 5) & 0x7)
+    #define EFM32_I2C_STATE_STATE_IDLE               0x00000000
+    #define EFM32_I2C_STATE_STATE_WAIT               0x00000001
+    #define EFM32_I2C_STATE_STATE_START              0x00000002
+    #define EFM32_I2C_STATE_STATE_ADDR               0x00000003
+    #define EFM32_I2C_STATE_STATE_ADDRACK            0x00000004
+    #define EFM32_I2C_STATE_STATE_DATA               0x00000005
+    #define EFM32_I2C_STATE_STATE_DATAACK            0x00000006
+
+#define EFM32_I2C_STATUS_ADDR                        0x0000000c
+#define EFM32_I2C_STATUS_MASK                        0x000003ff
+/** A start condition is pending and will be transmitted as soon as possible.
+   @multiple */
+  #define EFM32_I2C_STATUS_PSTART                  0x00000001
+  #define EFM32_I2C_STATUS_PSTART_SHIFT            0
+/** A stop condition is pending and will be transmitted as soon as possible.
+   @multiple */
+  #define EFM32_I2C_STATUS_PSTOP                   0x00000002
+  #define EFM32_I2C_STATUS_PSTOP_SHIFT             1
+/** An acknowledge is pending and will be transmitted as soon as possible. a
+   slave receiver or the current mode is not known. @multiple */
+  #define EFM32_I2C_STATUS_PACK                    0x00000004
+  #define EFM32_I2C_STATUS_PACK_SHIFT              2
+/** A not-acknowledge is pending and will be transmitted as soon as possible.
+   @multiple */
+  #define EFM32_I2C_STATUS_PNACK                   0x00000008
+  #define EFM32_I2C_STATUS_PNACK_SHIFT             3
+/** A continue is pending and will be transmitted as soon as possible. @multiple
+   */
+  #define EFM32_I2C_STATUS_PCONT                   0x00000010
+  #define EFM32_I2C_STATUS_PCONT_SHIFT             4
+/** An abort is pending and will be transmitted as soon as possible. @multiple */
+  #define EFM32_I2C_STATUS_PABORT                  0x00000020
+  #define EFM32_I2C_STATUS_PABORT_SHIFT            5
+/** Set when a transmission has completed and no more data is available in the
+   transmit buffer. Cleared when a new transmission starts. @multiple */
+  #define EFM32_I2C_STATUS_TXC                     0x00000040
+  #define EFM32_I2C_STATUS_TXC_SHIFT               6
+/** Indicates the level of the transmit buffer. Set when the transmit buffer is
+   empty, and cleared when it is full. @multiple */
+  #define EFM32_I2C_STATUS_TXBL                    0x00000080
+  #define EFM32_I2C_STATUS_TXBL_SHIFT              7
+/** Set when data is available in the receive buffer. Cleared when the receive
+   buffer is empty. @multiple */
+  #define EFM32_I2C_STATUS_RXDATAV                 0x00000100
+  #define EFM32_I2C_STATUS_RXDATAV_SHIFT           8
+/** Set when the receive buffer is full. Cleared when the receive buffer is no
+   longer full. When this bit is set, there is still room for one more frame in
+   the receive shift register. @multiple */
+  #define EFM32_I2C_STATUS_RXFULL                  0x00000200
+  #define EFM32_I2C_STATUS_RXFULL_SHIFT            9
+
+#define EFM32_I2C_CLKDIV_ADDR                        0x00000010
+#define EFM32_I2C_CLKDIV_MASK                        0x000001ff
+/** Specifies the clock divider for the I2C. Note that DIV must be 1 or higher
+   when slave is enabled. @multiple */
+  #define EFM32_I2C_CLKDIV_VAL                     0x000001ff
+  #define EFM32_I2C_CLKDIV_VAL_SHIFT               0
+  #define EFM32_I2C_CLKDIV_VAL_SHIFT_VAL(v)        ((v) << 0)
+  #define EFM32_I2C_CLKDIV_VAL_SET(x, v)           do { (x) = (((x) & ~0x1ff) | ((v) << 0)); } while(0)
+  #define EFM32_I2C_CLKDIV_VAL_GET(x)              (((x) >> 0) & 0x1ff)
+
+#define EFM32_I2C_SADDR_ADDR                         0x00000014
+#define EFM32_I2C_SADDR_MASK                         0x000000fe
+/** Specifies the slave address of the device. @multiple */
+  #define EFM32_I2C_SADDR_VAL                      0x000000fe
+  #define EFM32_I2C_SADDR_VAL_SHIFT                1
+  #define EFM32_I2C_SADDR_VAL_SHIFT_VAL(v)         ((v) << 1)
+  #define EFM32_I2C_SADDR_VAL_SET(x, v)            do { (x) = (((x) & ~0xfe) | ((v) << 1)); } while(0)
+  #define EFM32_I2C_SADDR_VAL_GET(x)               (((x) >> 1) & 0x7f)
+
+#define EFM32_I2C_SADDRMASK_ADDR                     0x00000018
+#define EFM32_I2C_SADDRMASK_MASK                     0x000000fe
+/** Specifies the significant bits of the slave address. Setting the mask to 0x00
+   will match all addresses, while setting it to 0x7F will only match the exact
+   address specified by ADDR. @multiple */
+  #define EFM32_I2C_SADDRMASK_VAL                  0x000000fe
+  #define EFM32_I2C_SADDRMASK_VAL_SHIFT            1
+  #define EFM32_I2C_SADDRMASK_VAL_SHIFT_VAL(v)     ((v) << 1)
+  #define EFM32_I2C_SADDRMASK_VAL_SET(x, v)        do { (x) = (((x) & ~0xfe) | ((v) << 1)); } while(0)
+  #define EFM32_I2C_SADDRMASK_VAL_GET(x)           (((x) >> 1) & 0x7f)
+
+#define EFM32_I2C_RXDATA_ADDR                        0x0000001c
+#define EFM32_I2C_RXDATA_MASK                        0x000000ff
+/** Use this register to read from the receive buffer. Buffer is emptied on read
+   access. @multiple */
+  #define EFM32_I2C_RXDATA_VAL                     0x000000ff
+  #define EFM32_I2C_RXDATA_VAL_SHIFT               0
+  #define EFM32_I2C_RXDATA_VAL_SHIFT_VAL(v)        ((v) << 0)
+  #define EFM32_I2C_RXDATA_VAL_SET(x, v)           do { (x) = (((x) & ~0xff) | ((v) << 0)); } while(0)
+  #define EFM32_I2C_RXDATA_VAL_GET(x)              (((x) >> 0) & 0xff)
+
+#define EFM32_I2C_RXDOUBLE_ADDR                      0x00000020
+#define EFM32_I2C_RXDOUBLE_MASK                      0x0000ffff
+/** First byte read from buffer. Buffer is emptied on read access @multiple */
+  #define EFM32_I2C_RXDOUBLE_RXDATA0               0x000000ff
+  #define EFM32_I2C_RXDOUBLE_RXDATA0_SHIFT         0
+  #define EFM32_I2C_RXDOUBLE_RXDATA0_SHIFT_VAL(v)  ((v) << 0)
+  #define EFM32_I2C_RXDOUBLE_RXDATA0_SET(x, v)     do { (x) = (((x) & ~0xff) | ((v) << 0)); } while(0)
+  #define EFM32_I2C_RXDOUBLE_RXDATA0_GET(x)        (((x) >> 0) & 0xff)
+/** Second byte read from buffer. Buffer is emptied on read access @multiple */
+  #define EFM32_I2C_RXDOUBLE_RXDATA1               0x0000ff00
+  #define EFM32_I2C_RXDOUBLE_RXDATA1_SHIFT         8
+  #define EFM32_I2C_RXDOUBLE_RXDATA1_SHIFT_VAL(v)  ((v) << 8)
+  #define EFM32_I2C_RXDOUBLE_RXDATA1_SET(x, v)     do { (x) = (((x) & ~0xff00) | ((v) << 8)); } while(0)
+  #define EFM32_I2C_RXDOUBLE_RXDATA1_GET(x)        (((x) >> 8) & 0xff)
+
+#define EFM32_I2C_RXDATAP_ADDR                       0x00000024
+#define EFM32_I2C_RXDATAP_MASK                       0x000000ff
+/** Use this register to read from the receive buffer. Buffer is not emptied on
+   read access. @multiple */
+  #define EFM32_I2C_RXDATAP_VAL                    0x000000ff
+  #define EFM32_I2C_RXDATAP_VAL_SHIFT              0
+  #define EFM32_I2C_RXDATAP_VAL_SHIFT_VAL(v)       ((v) << 0)
+  #define EFM32_I2C_RXDATAP_VAL_SET(x, v)          do { (x) = (((x) & ~0xff) | ((v) << 0)); } while(0)
+  #define EFM32_I2C_RXDATAP_VAL_GET(x)             (((x) >> 0) & 0xff)
+
+#define EFM32_I2C_RXDOUBLEP_ADDR                     0x00000028
+#define EFM32_I2C_RXDOUBLEP_MASK                     0x0000ffff
+/** First byte read from buffer. Buffer is not emptied on read access @multiple
+   */
+  #define EFM32_I2C_RXDOUBLEP_RXDATAP0             0x000000ff
+  #define EFM32_I2C_RXDOUBLEP_RXDATAP0_SHIFT       0
+  #define EFM32_I2C_RXDOUBLEP_RXDATAP0_SHIFT_VAL(v) ((v) << 0)
+  #define EFM32_I2C_RXDOUBLEP_RXDATAP0_SET(x, v)   do { (x) = (((x) & ~0xff) | ((v) << 0)); } while(0)
+  #define EFM32_I2C_RXDOUBLEP_RXDATAP0_GET(x)      (((x) >> 0) & 0xff)
+/** Second byte read from buffer. Buffer is not emptied on read access @multiple
+   */
+  #define EFM32_I2C_RXDOUBLEP_RXDATAP1             0x0000ff00
+  #define EFM32_I2C_RXDOUBLEP_RXDATAP1_SHIFT       8
+  #define EFM32_I2C_RXDOUBLEP_RXDATAP1_SHIFT_VAL(v) ((v) << 8)
+  #define EFM32_I2C_RXDOUBLEP_RXDATAP1_SET(x, v)   do { (x) = (((x) & ~0xff00) | ((v) << 8)); } while(0)
+  #define EFM32_I2C_RXDOUBLEP_RXDATAP1_GET(x)      (((x) >> 8) & 0xff)
+
+#define EFM32_I2C_TXDATA_ADDR                        0x0000002c
+#define EFM32_I2C_TXDATA_MASK                        0x000000ff
+/** Use this register to write a byte to the transmit buffer. @multiple */
+  #define EFM32_I2C_TXDATA_VAL                     0x000000ff
+  #define EFM32_I2C_TXDATA_VAL_SHIFT               0
+  #define EFM32_I2C_TXDATA_VAL_SHIFT_VAL(v)        ((v) << 0)
+  #define EFM32_I2C_TXDATA_VAL_SET(x, v)           do { (x) = (((x) & ~0xff) | ((v) << 0)); } while(0)
+  #define EFM32_I2C_TXDATA_VAL_GET(x)              (((x) >> 0) & 0xff)
+
+#define EFM32_I2C_TXDOUBLE_ADDR                      0x00000030
+#define EFM32_I2C_TXDOUBLE_MASK                      0x0000ffff
+/** First byte to write to buffer @multiple */
+  #define EFM32_I2C_TXDOUBLE_TXDATA0               0x000000ff
+  #define EFM32_I2C_TXDOUBLE_TXDATA0_SHIFT         0
+  #define EFM32_I2C_TXDOUBLE_TXDATA0_SHIFT_VAL(v)  ((v) << 0)
+  #define EFM32_I2C_TXDOUBLE_TXDATA0_SET(x, v)     do { (x) = (((x) & ~0xff) | ((v) << 0)); } while(0)
+  #define EFM32_I2C_TXDOUBLE_TXDATA0_GET(x)        (((x) >> 0) & 0xff)
+/** Second byte to write to buffer @multiple */
+  #define EFM32_I2C_TXDOUBLE_TXDATA1               0x0000ff00
+  #define EFM32_I2C_TXDOUBLE_TXDATA1_SHIFT         8
+  #define EFM32_I2C_TXDOUBLE_TXDATA1_SHIFT_VAL(v)  ((v) << 8)
+  #define EFM32_I2C_TXDOUBLE_TXDATA1_SET(x, v)     do { (x) = (((x) & ~0xff00) | ((v) << 8)); } while(0)
+  #define EFM32_I2C_TXDOUBLE_TXDATA1_GET(x)        (((x) >> 8) & 0xff)
+
+#define EFM32_I2C_IF_ADDR                            0x00000034
+#define EFM32_I2C_IF_MASK                            0x0007ffff
+/** Set when a start condition is successfully transmitted. @multiple */
+  #define EFM32_I2C_IF_START                       0x00000001
+  #define EFM32_I2C_IF_START_SHIFT                 0
+/** Set when a repeated start condition is detected. @multiple */
+  #define EFM32_I2C_IF_RSTART                      0x00000002
+  #define EFM32_I2C_IF_RSTART_SHIFT                1
+/** Set when incoming address is accepted, i.e. own address or general call
+   address is received. @multiple */
+  #define EFM32_I2C_IF_ADDRA                       0x00000004
+  #define EFM32_I2C_IF_ADDRA_SHIFT                 2
+/** Set when the transmit shift register becomes empty and there is no more data
+   in the transmit buffer. @multiple */
+  #define EFM32_I2C_IF_TXC                         0x00000008
+  #define EFM32_I2C_IF_TXC_SHIFT                   3
+/** Set when the transmit buffer becomes empty. Cleared automatically when new
+   data is written to the transmit buffer. @multiple */
+  #define EFM32_I2C_IF_TXBL                        0x00000010
+  #define EFM32_I2C_IF_TXBL_SHIFT                  4
+/** Set when data is available in the receive buffer. Cleared automatically when
+   the receive buffer is read. @multiple */
+  #define EFM32_I2C_IF_RXDATAV                     0x00000020
+  #define EFM32_I2C_IF_RXDATAV_SHIFT               5
+/** Set when an ACK has been received. @multiple */
+  #define EFM32_I2C_IF_ACK                         0x00000040
+  #define EFM32_I2C_IF_ACK_SHIFT                   6
+/** Set when a NACK has been received. @multiple */
+  #define EFM32_I2C_IF_NACK                        0x00000080
+  #define EFM32_I2C_IF_NACK_SHIFT                  7
+/** Set when a STOP condition has been successfully transmitted. If arbitration
+   is lost during the transmission of the STOP condition, then the MSTOP
+   interrupt flag is not set. @multiple */
+  #define EFM32_I2C_IF_MSTOP                       0x00000100
+  #define EFM32_I2C_IF_MSTOP_SHIFT                 8
+/** Set when arbitration is lost. @multiple */
+  #define EFM32_I2C_IF_ARBLOST                     0x00000200
+  #define EFM32_I2C_IF_ARBLOST_SHIFT               9
+/** Set when a bus error is detected. The bus error is resolved automatically,
+   but the current transfer is aborted. @multiple */
+  #define EFM32_I2C_IF_BUSERR                      0x00000400
+  #define EFM32_I2C_IF_BUSERR_SHIFT                10
+/** Set when the bus becomes held by the I2C module. @multiple */
+  #define EFM32_I2C_IF_BUSHOLD                     0x00000800
+  #define EFM32_I2C_IF_BUSHOLD_SHIFT               11
+/** Set when data is written to the transmit buffer while the transmit buffer is
+   full. @multiple */
+  #define EFM32_I2C_IF_TXOF                        0x00001000
+  #define EFM32_I2C_IF_TXOF_SHIFT                  12
+/** Set when data is read from the receive buffer through the I2Cn_RXDATA
+   register while the receive buffer is empty. @multiple */
+  #define EFM32_I2C_IF_RXUF                        0x00002000
+  #define EFM32_I2C_IF_RXUF_SHIFT                  13
+/** Set on each bus idle timeout. The timeout value can be set in the BITO bit
+   field in the I2Cn_CTRL register. @multiple */
+  #define EFM32_I2C_IF_BITO                        0x00004000
+  #define EFM32_I2C_IF_BITO_SHIFT                  14
+/** Set on each clock low timeout. The timeout value can be set in CLTO bit field
+   in the I2Cn_CTRL register. @multiple */
+  #define EFM32_I2C_IF_CLTO                        0x00008000
+  #define EFM32_I2C_IF_CLTO_SHIFT                  15
+/** Set when a STOP condition has been received. Will be set regardless of the
+   EFM32 being involved in the transaction or not. @multiple */
+  #define EFM32_I2C_IF_SSTOP                       0x00010000
+  #define EFM32_I2C_IF_SSTOP_SHIFT                 16
+/** Set when the receive buffer becomes full @multiple */
+  #define EFM32_I2C_IF_RXFULL                      0x00020000
+  #define EFM32_I2C_IF_RXFULL_SHIFT                17
+/** Set when the clock is pulled low before a START or a STOP condition could be
+   transmitted @multiple */
+  #define EFM32_I2C_IF_CLERR                       0x00040000
+  #define EFM32_I2C_IF_CLERR_SHIFT                 18
+
+#define EFM32_I2C_IFS_ADDR                           0x00000038
+#define EFM32_I2C_IFS_MASK                           0x0007ffcf
+/** Write to 1 to set the START interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_START                      0x00000001
+  #define EFM32_I2C_IFS_START_SHIFT                0
+/** Write to 1 to set the RSTART interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_RSTART                     0x00000002
+  #define EFM32_I2C_IFS_RSTART_SHIFT               1
+/** Write to 1 to set the ADDR interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_ADDRA                      0x00000004
+  #define EFM32_I2C_IFS_ADDRA_SHIFT                2
+/** Write to 1 to set the TXC interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_TXC                        0x00000008
+  #define EFM32_I2C_IFS_TXC_SHIFT                  3
+/** Write to 1 to set the ACK interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_ACK                        0x00000040
+  #define EFM32_I2C_IFS_ACK_SHIFT                  6
+/** Write to 1 to set the NACK interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_NACK                       0x00000080
+  #define EFM32_I2C_IFS_NACK_SHIFT                 7
+/** Write to 1 to set the MSTOP interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_MSTOP                      0x00000100
+  #define EFM32_I2C_IFS_MSTOP_SHIFT                8
+/** Write to 1 to set the ARBLOST interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_ARBLOST                    0x00000200
+  #define EFM32_I2C_IFS_ARBLOST_SHIFT              9
+/** Write to 1 to set the BUSERR interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_BUSERR                     0x00000400
+  #define EFM32_I2C_IFS_BUSERR_SHIFT               10
+/** Write to 1 to set the BUSHOLD interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_BUSHOLD                    0x00000800
+  #define EFM32_I2C_IFS_BUSHOLD_SHIFT              11
+/** Write to 1 to set the TXOF interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_TXOF                       0x00001000
+  #define EFM32_I2C_IFS_TXOF_SHIFT                 12
+/** Write to 1 to set the RXUF interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_RXUF                       0x00002000
+  #define EFM32_I2C_IFS_RXUF_SHIFT                 13
+/** Write to 1 to set the BITO interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_BITO                       0x00004000
+  #define EFM32_I2C_IFS_BITO_SHIFT                 14
+/** Write to 1 to set the CLTO interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_CLTO                       0x00008000
+  #define EFM32_I2C_IFS_CLTO_SHIFT                 15
+/** Write to 1 to set the SSTOP interrupt flag. @multiple */
+  #define EFM32_I2C_IFS_SSTOP                      0x00010000
+  #define EFM32_I2C_IFS_SSTOP_SHIFT                16
+/** Write 1 to set the RXFULL interrupt flag @multiple */
+  #define EFM32_I2C_IFS_RXFULL                     0x00020000
+  #define EFM32_I2C_IFS_RXFULL_SHIFT               17
+/** Write 1 to set the CLERR interrupt flag @multiple */
+  #define EFM32_I2C_IFS_CLERR                      0x00040000
+  #define EFM32_I2C_IFS_CLERR_SHIFT                18
+
+#define EFM32_I2C_IFC_ADDR                           0x0000003c
+#define EFM32_I2C_IFC_MASK                           0x0007ffcf
+/** Write to 1 to clear the START interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_START                      0x00000001
+  #define EFM32_I2C_IFC_START_SHIFT                0
+/** Write to 1 to clear the RSTART interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_RSTART                     0x00000002
+  #define EFM32_I2C_IFC_RSTART_SHIFT               1
+/** Write to 1 to clear the ADDR interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_ADDRA                      0x00000004
+  #define EFM32_I2C_IFC_ADDRA_SHIFT                2
+/** Write to 1 to clear the TXC interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_TXC                        0x00000008
+  #define EFM32_I2C_IFC_TXC_SHIFT                  3
+/** Write to 1 to clear the ACK interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_ACK                        0x00000040
+  #define EFM32_I2C_IFC_ACK_SHIFT                  6
+/** Write to 1 to clear the NACK interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_NACK                       0x00000080
+  #define EFM32_I2C_IFC_NACK_SHIFT                 7
+/** Write to 1 to clear the MSTOP interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_MSTOP                      0x00000100
+  #define EFM32_I2C_IFC_MSTOP_SHIFT                8
+/** Write to 1 to clear the ARBLOST interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_ARBLOST                    0x00000200
+  #define EFM32_I2C_IFC_ARBLOST_SHIFT              9
+/** Write to 1 to clear the BUSERR interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_BUSERR                     0x00000400
+  #define EFM32_I2C_IFC_BUSERR_SHIFT               10
+/** Write to 1 to clear the BUSHOLD interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_BUSHOLD                    0x00000800
+  #define EFM32_I2C_IFC_BUSHOLD_SHIFT              11
+/** Write to 1 to clear the TXOF interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_TXOF                       0x00001000
+  #define EFM32_I2C_IFC_TXOF_SHIFT                 12
+/** Write to 1 to clear the RXUF interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_RXUF                       0x00002000
+  #define EFM32_I2C_IFC_RXUF_SHIFT                 13
+/** Write to 1 to clear the BITO interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_BITO                       0x00004000
+  #define EFM32_I2C_IFC_BITO_SHIFT                 14
+/** Write to 1 to clear the CLTO interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_CLTO                       0x00008000
+  #define EFM32_I2C_IFC_CLTO_SHIFT                 15
+/** Write to 1 to clear the SSTOP interrupt flag. @multiple */
+  #define EFM32_I2C_IFC_SSTOP                      0x00010000
+  #define EFM32_I2C_IFC_SSTOP_SHIFT                16
+/** Write 1 to clear the RXFULL interrupt flag @multiple */
+  #define EFM32_I2C_IFC_RXFULL                     0x00020000
+  #define EFM32_I2C_IFC_RXFULL_SHIFT               17
+/** Write 1 to clear the CLERR interrupt flag @multiple */
+  #define EFM32_I2C_IFC_CLERR                      0x00040000
+  #define EFM32_I2C_IFC_CLERR_SHIFT                18
+
+#define EFM32_I2C_IEN_ADDR                           0x00000040
+#define EFM32_I2C_IEN_MASK                           0x0007ffff
+/** Enable interrupt on transmitted or received START condition. @multiple */
+  #define EFM32_I2C_IEN_START                      0x00000001
+  #define EFM32_I2C_IEN_START_SHIFT                0
+/** Enable interrupt on transmitted or received repeated START condition.
+   @multiple */
+  #define EFM32_I2C_IEN_RSTART                     0x00000002
+  #define EFM32_I2C_IEN_RSTART_SHIFT               1
+/** Enable interrupt on recognized address. @multiple */
+  #define EFM32_I2C_IEN_ADDRA                      0x00000004
+  #define EFM32_I2C_IEN_ADDRA_SHIFT                2
+/** Enable interrupt on transfer completed. @multiple */
+  #define EFM32_I2C_IEN_TXC                        0x00000008
+  #define EFM32_I2C_IEN_TXC_SHIFT                  3
+/** Enable interrupt on transmit buffer level. @multiple */
+  #define EFM32_I2C_IEN_TXBL                       0x00000010
+  #define EFM32_I2C_IEN_TXBL_SHIFT                 4
+/** Enable interrupt on receive buffer full. @multiple */
+  #define EFM32_I2C_IEN_RXDATAV                    0x00000020
+  #define EFM32_I2C_IEN_RXDATAV_SHIFT              5
+/** Enable interrupt on acknowledge received. @multiple */
+  #define EFM32_I2C_IEN_ACK                        0x00000040
+  #define EFM32_I2C_IEN_ACK_SHIFT                  6
+/** Enable interrupt when not-acknowledge is received. @multiple */
+  #define EFM32_I2C_IEN_NACK                       0x00000080
+  #define EFM32_I2C_IEN_NACK_SHIFT                 7
+/** Enable interrupt on MSTOP. @multiple */
+  #define EFM32_I2C_IEN_MSTOP                      0x00000100
+  #define EFM32_I2C_IEN_MSTOP_SHIFT                8
+/** Enable interrupt on loss of arbitration. @multiple */
+  #define EFM32_I2C_IEN_ARBLOST                    0x00000200
+  #define EFM32_I2C_IEN_ARBLOST_SHIFT              9
+/** Enable interrupt on bus error. @multiple */
+  #define EFM32_I2C_IEN_BUSERR                     0x00000400
+  #define EFM32_I2C_IEN_BUSERR_SHIFT               10
+/** Enable interrupt on bus-held. @multiple */
+  #define EFM32_I2C_IEN_BUSHOLD                    0x00000800
+  #define EFM32_I2C_IEN_BUSHOLD_SHIFT              11
+/** Enable interrupt on transmit buffer overflow. @multiple */
+  #define EFM32_I2C_IEN_TXOF                       0x00001000
+  #define EFM32_I2C_IEN_TXOF_SHIFT                 12
+/** Enable interrupt on receive buffer underflow. @multiple */
+  #define EFM32_I2C_IEN_RXUF                       0x00002000
+  #define EFM32_I2C_IEN_RXUF_SHIFT                 13
+/** Enable interrupt on bus idle timeout. @multiple */
+  #define EFM32_I2C_IEN_BITO                       0x00004000
+  #define EFM32_I2C_IEN_BITO_SHIFT                 14
+/** Enable interrupt on clock low timeout. @multiple */
+  #define EFM32_I2C_IEN_CLTO                       0x00008000
+  #define EFM32_I2C_IEN_CLTO_SHIFT                 15
+/** Enable interrupt on SSTOP. @multiple */
+  #define EFM32_I2C_IEN_SSTOP                      0x00010000
+  #define EFM32_I2C_IEN_SSTOP_SHIFT                16
+/** Enable/disable the RXFULL interrupt @multiple */
+  #define EFM32_I2C_IEN_RXFULL                     0x00020000
+  #define EFM32_I2C_IEN_RXFULL_SHIFT               17
+/** Enable/disable the CLERR interrupt @multiple */
+  #define EFM32_I2C_IEN_CLERR                      0x00040000
+  #define EFM32_I2C_IEN_CLERR_SHIFT                18
+
+/** I/O Routing Pin Enable Register @multiple */
+#define EFM32_I2C_ROUTEPEN_ADDR                      0x00000044
+#define EFM32_I2C_ROUTEPEN_MASK                      0x00000003
+/** When set, the SDA pin of the I2C is enabled @multiple */
+  #define EFM32_I2C_ROUTEPEN_SDAPEN                0x00000001
+  #define EFM32_I2C_ROUTEPEN_SDAPEN_SHIFT          0
+/** When set, the SCL pin of the I2C is enabled @multiple */
+  #define EFM32_I2C_ROUTEPEN_SCLPEN                0x00000002
+  #define EFM32_I2C_ROUTEPEN_SCLPEN_SHIFT          1
+
+/** I/O Routing Location Register @multiple */
+#define EFM32_I2C_ROUTELOC0_ADDR                     0x00000048
+#define EFM32_I2C_ROUTELOC0_MASK                     0x00003f3f
+/** Decides the location of the I2C SDA pin @multiple */
+  #define EFM32_I2C_ROUTELOC0_SDALOC               0x0000003f
+  #define EFM32_I2C_ROUTELOC0_SDALOC_SHIFT         0
+  #define EFM32_I2C_ROUTELOC0_SDALOC_SHIFT_VAL(v)  ((v) << 0)
+  #define EFM32_I2C_ROUTELOC0_SDALOC_SET(x, v)     do { (x) = (((x) & ~0x3f) | ((v) << 0)); } while(0)
+  #define EFM32_I2C_ROUTELOC0_SDALOC_GET(x)        (((x) >> 0) & 0x3f)
+/** Decides the location of the I2C SCL pin @multiple */
+  #define EFM32_I2C_ROUTELOC0_SCLLOC               0x00003f00
+  #define EFM32_I2C_ROUTELOC0_SCLLOC_SHIFT         8
+  #define EFM32_I2C_ROUTELOC0_SCLLOC_SHIFT_VAL(v)  ((v) << 8)
+  #define EFM32_I2C_ROUTELOC0_SCLLOC_SET(x, v)     do { (x) = (((x) & ~0x3f00) | ((v) << 8)); } while(0)
+  #define EFM32_I2C_ROUTELOC0_SCLLOC_GET(x)        (((x) >> 8) & 0x3f)
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/include/arch/efm32/efr/modem.h	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,8 @@
+
+#include "../chips.h"
+
+#if CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12
+# include "xg12/modem.h"
+#else
+# error not supported
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/include/arch/efm32/efr/protimer.h	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,8 @@
+
+#include "../chips.h"
+
+#if CONFIG_EFM32_ARCHREV == EFM32_ARCHREV_EFR_XG12
+# include "xg12/protimer.h"
+#else
+# error not supported
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/efm32/include/arch/efm32/efr/prs.h	Tue Apr 17 16:02:59 2018 +0200
@@ -0,0 +1,375 @@
+/***************************************
+* Auto generated by BFGen, do not edit *
+***************************************/
+
+/*
+   bfgen -o cdefs cdefs_use_reg_mask=1 cdefs_use_field_setval=1                \
+     cdefs_use_field_set=1
+*/
+
+#ifndef _EFR32_PRS_BFGEN_DEFS_
+#define _EFR32_PRS_BFGEN_DEFS_
+
+#define EFR32_PRS_SWPULSE_ADDR                       0x00000000
+#define EFR32_PRS_SWPULSE_MASK                       0x00000fff
+  #define EFR32_PRS_SWPULSE_CH0PULSE               0x00000001
+  #define EFR32_PRS_SWPULSE_CH0PULSE_SET(x, v)     do { (x) = (((x) & ~0x1) | ((v) << 0)); } while(0)
+  #define EFR32_PRS_SWPULSE_CH1PULSE               0x00000002
+  #define EFR32_PRS_SWPULSE_CH1PULSE_SET(x, v)     do { (x) = (((x) & ~0x2) | ((v) << 1)); } while(0)
+  #define EFR32_PRS_SWPULSE_CH2PULSE               0x00000004
+  #define EFR32_PRS_SWPULSE_CH2PULSE_SET(x, v)     do { (x) = (((x) & ~0x4) | ((v) << 2)); } while(0)
+  #define EFR32_PRS_SWPULSE_CH3PULSE               0x00000008
+  #define EFR32_PRS_SWPULSE_CH3PULSE_SET(x, v)     do { (x) = (((x) & ~0x8) | ((v) << 3)); } while(0)
+  #define EFR32_PRS_SWPULSE_CH4PULSE               0x00000010
+  #define EFR32_PRS_SWPULSE_CH4PULSE_SET(x, v)     do { (x) = (((x) & ~0x10) | ((v) << 4)); } while(0)
+  #define EFR32_PRS_SWPULSE_CH5PULSE               0x00000020
+  #define EFR32_PRS_SWPULSE_CH5PULSE_SET(x, v)     do { (x) = (((x) & ~0x20) | ((v) << 5)); } while(0)
+  #define EFR32_PRS_SWPULSE_CH6PULSE               0x00000040
+  #define EFR32_PRS_SWPULSE_CH6PULSE_SET(x, v)     do { (x) = (((x) & ~0x40) | ((v) << 6)); } while(0)
+  #define EFR32_PRS_SWPULSE_CH7PULSE               0x00000080
+  #define EFR32_PRS_SWPULSE_CH7PULSE_SET(x, v)     do { (x) = (((x) & ~0x80) | ((v) << 7)); } while(0)
+  #define EFR32_PRS_SWPULSE_CH8PULSE               0x00000100
+  #define EFR32_PRS_SWPULSE_CH8PULSE_SET(x, v)     do { (x) = (((x) & ~0x100) | ((v) << 8)); } while(0)
+  #define EFR32_PRS_SWPULSE_CH9PULSE               0x00000200
+  #define EFR32_PRS_SWPULSE_CH9PULSE_SET(x, v)     do { (x) = (((x) & ~0x200) | ((v) << 9)); } while(0)
+  #define EFR32_PRS_SWPULSE_CH10PULSE              0x00000400
+  #define EFR32_PRS_SWPULSE_CH10PULSE_SET(x, v)    do { (x) = (((x) & ~0x400) | ((v) << 10)); } while(0)
+  #define EFR32_PRS_SWPULSE_CH11PULSE              0x00000800
+  #define EFR32_PRS_SWPULSE_CH11PULSE_SET(x, v)    do { (x) = (((x) & ~0x800) | ((v) << 11)); } while(0)
+
+#define EFR32_PRS_SWLEVEL_ADDR                       0x00000004
+#define EFR32_PRS_SWLEVEL_MASK                       0x00000fff
+  #define EFR32_PRS_SWLEVEL_CH0LEVEL               0x00000001
+  #define EFR32_PRS_SWLEVEL_CH0LEVEL_SET(x, v)     do { (x) = (((x) & ~0x1) | ((v) << 0)); } while(0)
+  #define EFR32_PRS_SWLEVEL_CH1LEVEL               0x00000002
+  #define EFR32_PRS_SWLEVEL_CH1LEVEL_SET(x, v)     do { (x) = (((x) & ~0x2) | ((v) << 1)); } while(0)
+  #define EFR32_PRS_SWLEVEL_CH2LEVEL               0x00000004
+  #define EFR32_PRS_SWLEVEL_CH2LEVEL_SET(x, v)     do { (x) = (((x) & ~0x4) | ((v) << 2)); } while(0)
+  #define EFR32_PRS_SWLEVEL_CH3LEVEL               0x00000008
+  #define EFR32_PRS_SWLEVEL_CH3LEVEL_SET(x, v)     do { (x) = (((x) & ~0x8) | ((v) << 3)); } while(0)
+  #define EFR32_PRS_SWLEVEL_CH4LEVEL               0x00000010
+  #define EFR32_PRS_SWLEVEL_CH4LEVEL_SET(x, v)     do { (x) = (((x) & ~0x10) | ((v) << 4)); } while(0)
+  #define EFR32_PRS_SWLEVEL_CH5LEVEL               0x00000020
+  #define EFR32_PRS_SWLEVEL_CH5LEVEL_SET(x, v)     do { (x) = (((x) & ~0x20) | ((v) << 5)); } while(0)
+  #define EFR32_PRS_SWLEVEL_CH6LEVEL               0x00000040
+  #define EFR32_PRS_SWLEVEL_CH6LEVEL_SET(x, v)     do { (x) = (((x) & ~0x40) | ((v) << 6)); } while(0)
+  #define EFR32_PRS_SWLEVEL_CH7LEVEL               0x00000080
+  #define EFR32_PRS_SWLEVEL_CH7LEVEL_SET(x, v)     do { (x) = (((x) & ~0x80) | ((v) << 7)); } while(0)
+  #define EFR32_PRS_SWLEVEL_CH8LEVEL               0x00000100
+  #define EFR32_PRS_SWLEVEL_CH8LEVEL_SET(x, v)     do { (x) = (((x) & ~0x100) | ((v) << 8)); } while(0)
+  #define EFR32_PRS_SWLEVEL_CH9LEVEL               0x00000200
+  #define EFR32_PRS_SWLEVEL_CH9LEVEL_SET(x, v)     do { (x) = (((x) & ~0x200) | ((v) << 9)); } while(0)
+  #define EFR32_PRS_SWLEVEL_CH10LEVEL              0x00000400
+  #define EFR32_PRS_SWLEVEL_CH10LEVEL_SET(x, v)    do { (x) = (((x) & ~0x400) | ((v) << 10)); } while(0)
+  #define EFR32_PRS_SWLEVEL_CH11LEVEL              0x00000800
+  #define EFR32_PRS_SWLEVEL_CH11LEVEL_SET(x, v)    do { (x) = (((x) & ~0x800) | ((v) << 11)); } while(0)
+
+#define EFR32_PRS_ROUTEPEN_ADDR                      0x00000008
+#define EFR32_PRS_ROUTEPEN_MASK                      0x00000fff
+  #define EFR32_PRS_ROUTEPEN_CHPEN_COUNT           12
+  #define EFR32_PRS_ROUTEPEN_CHPEN(fidx)           (0x00000001 << ((fidx)))
+  #define EFR32_PRS_ROUTEPEN_CHPEN_SET(fidx, x, v) do { (x) = (((x) & ~(0x1 << ((fidx)))) | ((v) << ((fidx) + 0))); } while(0)
+
+#define EFR32_PRS_ROUTELOC0_ADDR                     0x00000010
+#define EFR32_PRS_ROUTELOC0_MASK                     0x3f3f3f3f
+  #define EFR32_PRS_ROUTELOC0_CH0LOC(v)            ((v) << 0)
+  #define EFR32_PRS_ROUTELOC0_CH0LOC_SET(x, v)     do { (x) = (((x) & ~0x3f) | ((v) << 0)); } while(0)
+  #define EFR32_PRS_ROUTELOC0_CH0LOC_GET(x)        (((x) >> 0) & 0x3f)
+  #define EFR32_PRS_ROUTELOC0_CH1LOC(v)            ((v) << 8)
+  #define EFR32_PRS_ROUTELOC0_CH1LOC_SET(x, v)     do { (x) = (((x) & ~0x3f00) | ((v) << 8)); } while(0)
+  #define EFR32_PRS_ROUTELOC0_CH1LOC_GET(x)        (((x) >> 8) & 0x3f)
+  #define EFR32_PRS_ROUTELOC0_CH2LOC(v)            ((v) << 16)
+  #define EFR32_PRS_ROUTELOC0_CH2LOC_SET(x, v)     do { (x) = (((x) & ~0x3f0000) | ((v) << 16)); } while(0)
+  #define EFR32_PRS_ROUTELOC0_CH2LOC_GET(x)        (((x) >> 16) & 0x3f)
+  #define EFR32_PRS_ROUTELOC0_CH3LOC(v)            ((v) << 24)
+  #define EFR32_PRS_ROUTELOC0_CH3LOC_SET(x, v)     do { (x) = (((x) & ~0x3f000000) | ((v) << 24)); } while(0)
+  #define EFR32_PRS_ROUTELOC0_CH3LOC_GET(x)        (((x) >> 24) & 0x3f)
+
+#define EFR32_PRS_ROUTELOC1_ADDR                     0x00000014
+#define EFR32_PRS_ROUTELOC1_MASK                     0x3f3f3f3f
+  #define EFR32_PRS_ROUTELOC1_CH4LOC(v)            ((v) << 0)
+  #define EFR32_PRS_ROUTELOC1_CH4LOC_SET(x, v)     do { (x) = (((x) & ~0x3f) | ((v) << 0)); } while(0)
+  #define EFR32_PRS_ROUTELOC1_CH4LOC_GET(x)        (((x) >> 0) & 0x3f)
+  #define EFR32_PRS_ROUTELOC1_CH5LOC(v)            ((v) << 8)
+  #define EFR32_PRS_ROUTELOC1_CH5LOC_SET(x, v)     do { (x) = (((x) & ~0x3f00) | ((v) << 8)); } while(0)
+  #define EFR32_PRS_ROUTELOC1_CH5LOC_GET(x)        (((x) >> 8) & 0x3f)
+  #define EFR32_PRS_ROUTELOC1_CH6LOC(v)            ((v) << 16)
+  #define EFR32_PRS_ROUTELOC1_CH6LOC_SET(x, v)     do { (x) = (((x) & ~0x3f0000) | ((v) << 16)); } while(0)
+  #define EFR32_PRS_ROUTELOC1_CH6LOC_GET(x)        (((x) >> 16) & 0x3f)
+  #define EFR32_PRS_ROUTELOC1_CH7LOC(v)            ((v) << 24)
+  #define EFR32_PRS_ROUTELOC1_CH7LOC_SET(x, v)     do { (x) = (((x) & ~0x3f000000) | ((v) << 24)); } while(0)
+  #define EFR32_PRS_ROUTELOC1_CH7LOC_GET(x)        (((x) >> 24) & 0x3f)
+
+#define EFR32_PRS_ROUTELOC2_ADDR                     0x00000018
+#define EFR32_PRS_ROUTELOC2_MASK                     0x3f3f3f3f
+  #define EFR32_PRS_ROUTELOC2_CH8LOC(v)            ((v) << 0)
+  #define EFR32_PRS_ROUTELOC2_CH8LOC_SET(x, v)     do { (x) = (((x) & ~0x3f) | ((v) << 0)); } while(0)
+  #define EFR32_PRS_ROUTELOC2_CH8LOC_GET(x)        (((x) >> 0) & 0x3f)
+  #define EFR32_PRS_ROUTELOC2_CH9LOC(v)            ((v) << 8)
+  #define EFR32_PRS_ROUTELOC2_CH9LOC_SET(x, v)     do { (x) = (((x) & ~0x3f00) | ((v) << 8)); } while(0)
+  #define EFR32_PRS_ROUTELOC2_CH9LOC_GET(x)        (((x) >> 8) & 0x3f)
+  #define EFR32_PRS_ROUTELOC2_CH10LOC(v)           ((v) << 16)
+  #define EFR32_PRS_ROUTELOC2_CH10LOC_SET(x, v)    do { (x) = (((x) & ~0x3f0000) | ((v) << 16)); } while(0)
+  #define EFR32_PRS_ROUTELOC2_CH10LOC_GET(x)       (((x) >> 16) & 0x3f)
+  #define EFR32_PRS_ROUTELOC2_CH11LOC(v)           ((v) << 24)
+  #define EFR32_PRS_ROUTELOC2_CH11LOC_SET(x, v)    do { (x) = (((x) & ~0x3f000000) | ((v) << 24)); } while(0)
+  #define EFR32_PRS_ROUTELOC2_CH11LOC_GET(x)       (((x) >> 24) & 0x3f)
+
+#define EFR32_PRS_CTRL_ADDR                          0x00000030
+#define EFR32_PRS_CTRL_MASK                          0x0000001f
+  #define EFR32_PRS_CTRL_SEVONPRS                  0x00000001
+  #define EFR32_PRS_CTRL_SEVONPRS_SET(x, v)        do { (x) = (((x) & ~0x1) | ((v) << 0)); } while(0)
+  #define EFR32_PRS_CTRL_SEVONPRSSEL(v)            ((EFR32_PRS_CTRL_SEVONPRSSEL_##v) << 1)
+  #define EFR32_PRS_CTRL_SEVONPRSSEL_SET(x, v)     do { (x) = (((x) & ~0x1e) | ((EFR32_PRS_CTRL_SEVONPRSSEL_##v) << 1)); } whil