diff --git a/boards/airfy-beacon/include/periph_conf.h b/boards/airfy-beacon/include/periph_conf.h
index bc7d1a009053d3c334621dcd0c74f6e444244ca0..4aac804ea10b46f65d13bed9d12cd0c8f301a550 100644
--- a/boards/airfy-beacon/include/periph_conf.h
+++ b/boards/airfy-beacon/include/periph_conf.h
@@ -1,9 +1,9 @@
 /*
  * Copyright (C) 2014 Christian Mehlis <mehlis@inf.fu-berlin.de>
  *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
  */
 
 /**
@@ -83,15 +83,16 @@ static const timer_conf_t timer_config[] = {
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           (1U)
-#define SPI_0_EN            1
-#define SPI_IRQ_PRIO        1
-
-/* SPI_0 device configuration */
-#define SPI_0_DEV           NRF_SPI0
-#define SPI_0_PIN_MOSI      13
-#define SPI_0_PIN_MISO      14
-#define SPI_0_PIN_SCK       15
+static const spi_conf_t spi_config[] = {
+    {
+        .dev  = NRF_SPI0,
+        .sclk = 15,
+        .mosi = 13,
+        .miso = 14
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/arduino-due/include/periph_conf.h b/boards/arduino-due/include/periph_conf.h
index d6e603c75d812ac07b822cfe2afd6ed2a8cafaec..fe187f43965b10949ec0c46ecea553516bad7887 100644
--- a/boards/arduino-due/include/periph_conf.h
+++ b/boards/arduino-due/include/periph_conf.h
@@ -88,27 +88,18 @@ static const uart_conf_t uart_config[] = {
 * @name SPI configuration
 * @{
 */
-#define SPI_NUMOF           (1U)
-#define SPI_0_EN            1
-
-/* SPI 0 device config */
-#define SPI_0_DEV           SPI0
-#define SPI_0_CLKEN()       (PMC->PMC_PCER0 |= (1 << ID_SPI0));
-#define SPI_0_CLKDIS()      (PMC->PMC_PCER0 &= ~(1 << ID_SPI0));
-#define SPI_0_IRQ           SPI0_IRQn
-#define SPI_0_IRQ_HANDLER   isr_spi0
-#define SPI_0_IRQ_PRIO      1
-
-/* SPI 0 pin configuration */
-#define SPI_0_MISO_PIN      PIO_PA25A_SPI0_MISO
-#define SPI_0_MOSI_PIN      PIO_PA26A_SPI0_MOSI
-#define SPI_0_SCK_PIN       PIO_PA27A_SPI0_SPCK
-#define SPI_0_MISO_PORT     PIOA
-#define SPI_0_MOSI_PORT     PIOA
-#define SPI_0_SCK_PORT      PIOA
-#define SPI_0_MISO_PORT_CLKEN()  (PMC->PMC_PCER0 |= (1 << ID_PIOA));
-#define SPI_0_MOSI_PORT_CLKEN()  (PMC->PMC_PCER0 |= (1 << ID_PIOA));
-#define SPI_0_SCK_PORT_CLKEN()   (PMC->PMC_PCER0 |= (1 << ID_PIOA));
+static const spi_conf_t spi_config[] = {
+    {
+        .dev   = SPI0,
+        .id    = ID_SPI0,
+        .clk   = GPIO_PIN(PA, 27),
+        .mosi  = GPIO_PIN(PA, 26),
+        .miso  = GPIO_PIN(PA, 25),
+        .mux   = GPIO_MUX_A
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/arduino-due/include/sdcard_spi_params.h b/boards/arduino-due/include/sdcard_spi_params.h
new file mode 100644
index 0000000000000000000000000000000000000000..0cd2a1e4c19ff3e5ac34021a29366e5c19ee9791
--- /dev/null
+++ b/boards/arduino-due/include/sdcard_spi_params.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
+ *               2017 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     boards_arduino-due
+ * @{
+ *
+ * @file
+ * @brief       SD card configuration for the Arduino due
+ *
+ * @author      Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ */
+
+#ifndef SDCARD_SPI_PARAMS_H
+#define SDCARD_SPI_PARAMS_H
+
+#include "board.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Set default configuration parameters for the sdcard_spi driver
+ * @{
+ */
+#ifndef SDCARD_SPI_PARAM_SPI
+#define SDCARD_SPI_PARAM_SPI         (SPI_DEV(0))
+#endif
+#ifndef SDCARD_SPI_PARAM_CS
+#define SDCARD_SPI_PARAM_CS          (GPIO_PIN(PA, 29))
+#endif
+#ifndef SDCARD_SPI_PARAM_CLK
+#define SDCARD_SPI_PARAM_CLK         (GPIO_PIN(PA, 27))
+#endif
+#ifndef SDCARD_SPI_PARAM_MOSI
+#define SDCARD_SPI_PARAM_MOSI        (GPIO_PIN(PA, 26))
+#endif
+#ifndef SDCARD_SPI_PARAM_MISO
+#define SDCARD_SPI_PARAM_MISO        (GPIO_PIN(PA, 25))
+#endif
+#ifndef SDCARD_SPI_PARAM_POWER
+#define SDCARD_SPI_PARAM_POWER       (GPIO_UNDEF)
+#endif
+#ifndef SDCARD_SPI_PARAM_POWER_AH
+/** treated as 'don't care' if SDCARD_SPI_PARAM_POWER is GPIO_UNDEF */
+#define SDCARD_SPI_PARAM_POWER_AH    (true)
+#endif
+/** @} */
+
+/**
+ * @brief   sdcard_spi configuration
+ */
+static const  sdcard_spi_params_t sdcard_spi_params[] = {
+    {
+        .spi_dev        = SDCARD_SPI_PARAM_SPI,
+        .cs             = SDCARD_SPI_PARAM_CS,
+        .clk            = SDCARD_SPI_PARAM_CLK,
+        .mosi           = SDCARD_SPI_PARAM_MOSI,
+        .miso           = SDCARD_SPI_PARAM_MISO,
+        .power          = SDCARD_SPI_PARAM_POWER,
+        .power_act_high = SDCARD_SPI_PARAM_POWER_AH
+    },
+};
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SDCARD_SPI_PARAMS_H */
+/** @} */
diff --git a/boards/arduino-due/include/w5100_params.h b/boards/arduino-due/include/w5100_params.h
index 131bed8ec8251222f87839669546c412ccc39408..7eefa13bade2736e7e78b8a081fa9cfa977c25b9 100644
--- a/boards/arduino-due/include/w5100_params.h
+++ b/boards/arduino-due/include/w5100_params.h
@@ -28,10 +28,10 @@ extern "C" {
  * @{
  */
 #ifndef W5100_PARAM_SPI
-#define W5100_PARAM_SPI         (SPI_0)
+#define W5100_PARAM_SPI         (SPI_DEV(0))
 #endif
-#ifndef W5100_PARAM_SPI_SPEED
-#define W5100_PARAM_SPI_SPEED   (SPI_SPEED_5MHZ)
+#ifndef W5100_PARAM_SPI_CLK
+#define W5100_PARAM_SPI_CLK     (SPI_CLK_5MHZ)
 #endif
 #ifndef W5100_PARAM_CS
 #define W5100_PARAM_CS          (GPIO_PIN(2, 29))
@@ -46,10 +46,10 @@ extern "C" {
  */
 static const  w5100_params_t w5100_params[] = {
     {
-        .spi       = W5100_PARAM_SPI,
-        .spi_speed = W5100_PARAM_SPI_SPEED,
-        .cs        = W5100_PARAM_CS,
-        .evt       = W5100_PARAM_EVT
+        .spi = W5100_PARAM_SPI,
+        .clk = W5100_PARAM_SPI_CLK,
+        .cs  = W5100_PARAM_CS,
+        .evt = W5100_PARAM_EVT
     },
 };
 /** @} */
diff --git a/boards/arduino-zero/include/periph_conf.h b/boards/arduino-zero/include/periph_conf.h
index 177882619bf62bd43da423e3b11ef84aaf442715..4b17f99498efc14319bc2fdafd800a3f4e4e8f0c 100644
--- a/boards/arduino-zero/include/periph_conf.h
+++ b/boards/arduino-zero/include/periph_conf.h
@@ -183,23 +183,21 @@ static const pwm_conf_t pwm_config[] = {
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF          (1)
-#define SPI_0_EN           1
-
-/*      SPI0             */
-#define SPI_0_DEV          SERCOM4->SPI
-#define SPI_IRQ_0          SERCOM4_IRQn
-#define SPI_0_GCLK_ID      SERCOM4_GCLK_ID_CORE
-/* SPI 0 pin configuration */
-#define SPI_0_SCLK         GPIO_PIN(PB, 11)
-#define SPI_0_SCLK_MUX     GPIO_MUX_D
-#define SPI_0_MISO         GPIO_PIN(PA, 12)
-#define SPI_0_MISO_MUX     GPIO_MUX_D
-#define SPI_0_MISO_PAD     SPI_PAD_MISO_0
-#define SPI_0_MOSI         GPIO_PIN(PB, 10)
-#define SPI_0_MOSI_MUX     GPIO_MUX_D
-#define SPI_0_MOSI_PAD     SPI_PAD_MOSI_2_SCK_3
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = &SERCOM4->SPI,
+        .miso_pin = GPIO_PIN(PA, 12),
+        .mosi_pin = GPIO_PIN(PB, 10),
+        .clk_pin  = GPIO_PIN(PB, 11),
+        .miso_mux = GPIO_MUX_D,
+        .mosi_mux = GPIO_MUX_D,
+        .clk_mux  = GPIO_MUX_D,
+        .miso_pad = SPI_PAD_MISO_0,
+        .mosi_pad = SPI_PAD_MOSI_2_SCK_3
+    }
+};
 
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/cc2538dk/include/periph_conf.h b/boards/cc2538dk/include/periph_conf.h
index 55222f9dfa733aed15db7866d26112d6e183503e..575a8a653ffa9557fbd5c71521ff273fef78d0a2 100644
--- a/boards/cc2538dk/include/periph_conf.h
+++ b/boards/cc2538dk/include/periph_conf.h
@@ -58,7 +58,6 @@ static const timer_conf_t timer_config[] = {
 #define TIMER_IRQ_PRIO      1
 /** @} */
 
-
 /**
  * @name UART configuration
  * @{
@@ -112,22 +111,36 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = {
 };
 /** @} */
 
+/**
+ * @brief   Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz)
+ *
+ * Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where
+ * 1 < CPSR < 255 and
+ * 0 < SCR  < 256
+ */
+static const spi_clk_conf_t spi_clk_config[] = {
+    { .cpsr = 10, .scr = 31 },  /* 100khz */
+    { .cpsr =  2, .scr = 39 },  /* 400khz */
+    { .cpsr =  2, .scr = 15 },  /* 1MHz */
+    { .cpsr =  2, .scr =  2 },  /* ~4.5MHz */
+    { .cpsr =  2, .scr =  1 }   /* ~10.7MHz */
+};
+
 /**
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           1
-#define SPI_0_EN            1
-
-static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
+static const spi_conf_t spi_config[] = {
     {
         .dev      = SSI0,
         .mosi_pin = GPIO_PA4,
         .miso_pin = GPIO_PA5,
         .sck_pin  = GPIO_PA2,
-        .cs_pin   = GPIO_PD0,
-    },
+        .cs_pin   = GPIO_PD0
+    }
 };
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/fox/include/board.h b/boards/fox/include/board.h
index 24316d18efba52294198035929d93245dcad396b..d87e492d07cbbb1c8264fef368edbdf5a2b972d6 100644
--- a/boards/fox/include/board.h
+++ b/boards/fox/include/board.h
@@ -43,8 +43,8 @@ extern "C" {
  *
  * {spi bus, spi speed, cs pin, int pin, reset pin, sleep pin}
  */
-#define AT86RF2XX_PARAMS_BOARD      {.spi = SPI_0, \
-                                     .spi_speed = SPI_SPEED_5MHZ, \
+#define AT86RF2XX_PARAMS_BOARD      {.spi = SPI_DEV(0), \
+                                     .spi_clk = SPI_CLK_5MHZ, \
                                      .cs_pin = GPIO_PIN(PORT_A, 1), \
                                      .int_pin = GPIO_PIN(PORT_C, 2), \
                                      .sleep_pin = GPIO_PIN(PORT_A, 0), \
diff --git a/boards/fox/include/periph_conf.h b/boards/fox/include/periph_conf.h
index 13565ad619398ecbc2ab5759071a1b9928a546ed..ffe99f22e2d69c806a61899202116b4e91784b8b 100644
--- a/boards/fox/include/periph_conf.h
+++ b/boards/fox/include/periph_conf.h
@@ -115,21 +115,42 @@ static const uart_conf_t uart_config[] = {
 /** @} */
 
 /**
- * @brief SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF           (1U)
-#define SPI_0_EN            1
-
-/* SPI 0 device configuration */
-#define SPI_0_DEV           SPI2
-#define SPI_0_CLKEN()       (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_0_CLKDIS()      (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_0_BUS_DIV       0   /* 1 -> SPI runs with full CPU clock, 0 -> half CPU clock */
-/* SPI 0 pin configuration */
-#define SPI_0_CLK_PIN       GPIO_PIN(PORT_B,13)
-#define SPI_0_MOSI_PIN      GPIO_PIN(PORT_B,15)
-#define SPI_0_MISO_PIN      GPIO_PIN(PORT_B,14)
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 36000000Hz */
+        7,  /* -> 140625Hz */
+        6,  /* -> 281250Hz */
+        4,  /* -> 1125000Hz */
+        2,  /* -> 4500000Hz */
+        1   /* -> 9000000Hz */
+    },
+    {       /* for APB2 @ 72000000Hz */
+        7,  /* -> 281250Hz */
+        7,  /* -> 281250Hz */
+        5,  /* -> 1125000Hz */
+        3,  /* -> 4500000Hz */
+        2   /* -> 9000000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI2,
+        .mosi_pin = GPIO_PIN(PORT_B, 15),
+        .miso_pin = GPIO_PIN(PORT_B, 14),
+        .sclk_pin = GPIO_PIN(PORT_B, 13),
+        .cs_pin   = GPIO_UNDEF,
+        .rccmask  = RCC_APB1ENR_SPI2EN,
+        .apbbus   = APB1
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/frdm-k64f/include/periph_conf.h b/boards/frdm-k64f/include/periph_conf.h
index 4af0e403b1cdb6d05b1c1af4ba23a1ed1e66988d..9abbbb2f1f2237501461e4b155780a9d82b5ded8 100644
--- a/boards/frdm-k64f/include/periph_conf.h
+++ b/boards/frdm-k64f/include/periph_conf.h
@@ -147,35 +147,67 @@ static const pwm_conf_t pwm_config[] = {
 
 
 /**
-* @name SPI configuration
+ * @name   SPI configuration
+ *
+ * Clock configuration values based on the configured 30Mhz module clock.
+ *
+ * Auto-generated by:
+ * cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c
+ *
 * @{
 */
-#define SPI_NUMOF                    (1U)
-#define SPI_0_EN                     1
-#define SPI_IRQ_PRIO                 1
-#define KINETIS_SPI_USE_HW_CS        1
-
-/* SPI 0 device config */
-#define SPI_0_DEV                    SPI0
-#define SPI_0_INDEX                  0
-#define SPI_0_CTAS                   0
-#define SPI_0_CLKEN()                (SIM->SCGC6 |= (SIM_SCGC6_SPI0_MASK))
-#define SPI_0_CLKDIS()               (SIM->SCGC6 &= ~(SIM_SCGC6_SPI0_MASK))
-#define SPI_0_IRQ                    SPI0_IRQn
-#define SPI_0_IRQ_HANDLER            isr_spi0
-#define SPI_0_FREQ                   CLOCK_CORECLOCK
-
-/* SPI 0 pin configuration */
-#define SPI_0_PORT                   PORTD
-#define SPI_0_PORT_CLKEN()           (SIM->SCGC5 |= (SIM_SCGC5_PORTD_MASK))
-#define SPI_0_AF                     2
-
-#define SPI_0_PCS0_PIN               0
-#define SPI_0_SCK_PIN                1
-#define SPI_0_SOUT_PIN               2
-#define SPI_0_SIN_PIN                3
-
-#define SPI_0_PCS0_ACTIVE_LOW        1
+static const uint32_t spi_clk_config[] = {
+    (
+        SPI_CTAR_PBR(2) | SPI_CTAR_BR(6) |          /* -> 93750Hz */
+        SPI_CTAR_PCSSCK(2) | SPI_CTAR_CSSCK(5) |
+        SPI_CTAR_PASC(2) | SPI_CTAR_ASC(5) |
+        SPI_CTAR_PDT(2) | SPI_CTAR_DT(5)
+    ),
+    (
+        SPI_CTAR_PBR(2) | SPI_CTAR_BR(4) |          /* -> 375000Hz */
+        SPI_CTAR_PCSSCK(2) | SPI_CTAR_CSSCK(3) |
+        SPI_CTAR_PASC(2) | SPI_CTAR_ASC(3) |
+        SPI_CTAR_PDT(2) | SPI_CTAR_DT(3)
+    ),
+    (
+        SPI_CTAR_PBR(2) | SPI_CTAR_BR(2) |          /* -> 1000000Hz */
+        SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(4) |
+        SPI_CTAR_PASC(0) | SPI_CTAR_ASC(4) |
+        SPI_CTAR_PDT(0) | SPI_CTAR_DT(4)
+    ),
+    (
+        SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) |          /* -> 5000000Hz */
+        SPI_CTAR_PCSSCK(1) | SPI_CTAR_CSSCK(0) |
+        SPI_CTAR_PASC(1) | SPI_CTAR_ASC(0) |
+        SPI_CTAR_PDT(1) | SPI_CTAR_DT(0)
+    ),
+    (
+        SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) |          /* -> 7500000Hz */
+        SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(1) |
+        SPI_CTAR_PASC(0) | SPI_CTAR_ASC(1) |
+        SPI_CTAR_PDT(0) | SPI_CTAR_DT(1)
+    )
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI0,
+        .pin_miso = GPIO_PIN(PORT_D, 3),
+        .pin_mosi = GPIO_PIN(PORT_D, 2),
+        .pin_clk  = GPIO_PIN(PORT_D, 1),
+        .pin_cs   = {
+            GPIO_PIN(PORT_D, 0),
+            GPIO_UNDEF,
+            GPIO_UNDEF,
+            GPIO_UNDEF,
+            GPIO_UNDEF
+        },
+        .pcr      = GPIO_AF_2,
+        .simmask  = SIM_SCGC6_SPI0_MASK
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 
diff --git a/boards/iotlab-a8-m3/include/periph_conf.h b/boards/iotlab-a8-m3/include/periph_conf.h
index 8b4db8ecbc552c3c28ad23c3bf253e319a992f37..ac4ba9c33867068e17626ca2079d42478a54ba3b 100644
--- a/boards/iotlab-a8-m3/include/periph_conf.h
+++ b/boards/iotlab-a8-m3/include/periph_conf.h
@@ -31,18 +31,19 @@ extern "C" {
  * @brief SPI configuration
  * @{
  */
-#define SPI_NUMOF           (1U)
-#define SPI_0_EN            1
-
-/* SPI 0 device configuration */
-#define SPI_0_DEV           SPI2
-#define SPI_0_CLKEN()       (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_0_CLKDIS()      (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_0_BUS_DIV       1   /* 1 -> SPI runs with full CPU clock, 0 -> half CPU clock */
-/* SPI 0 pin configuration */
-#define SPI_0_CLK_PIN       GPIO_PIN(PORT_B,13)
-#define SPI_0_MISO_PIN      GPIO_PIN(PORT_B,14)
-#define SPI_0_MOSI_PIN      GPIO_PIN(PORT_B,15)
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI2,
+        .mosi_pin = GPIO_PIN(PORT_B, 15),
+        .miso_pin = GPIO_PIN(PORT_B, 14),
+        .sclk_pin = GPIO_PIN(PORT_B, 13),
+        .cs_pin   = GPIO_UNDEF,
+        .rccmask  = RCC_APB1ENR_SPI2EN,
+        .apbbus   = APB1
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/iotlab-common/include/board_common.h b/boards/iotlab-common/include/board_common.h
index ed9b9883788414aa500a9faddcbae1696c53bfcb..f0161d7b8484866fe0a7810d5605a19988573866 100644
--- a/boards/iotlab-common/include/board_common.h
+++ b/boards/iotlab-common/include/board_common.h
@@ -53,10 +53,10 @@ extern "C" {
  *
  * {spi bus, spi speed, cs pin, int pin, reset pin, sleep pin}
  */
-#define AT86RF2XX_PARAMS_BOARD      {.spi = SPI_0, \
-                                     .spi_speed = SPI_SPEED_5MHZ, \
-                                     .cs_pin = GPIO_PIN(PORT_A, 4), \
-                                     .int_pin = GPIO_PIN(PORT_C, 4), \
+#define AT86RF2XX_PARAMS_BOARD      {.spi       = SPI_DEV(0), \
+                                     .spi_clk   = SPI_CLK_5MHZ, \
+                                     .cs_pin    = GPIO_PIN(PORT_A, 4), \
+                                     .int_pin   = GPIO_PIN(PORT_C, 4), \
                                      .sleep_pin = GPIO_PIN(PORT_A, 2), \
                                      .reset_pin = GPIO_PIN(PORT_C, 1)}
 
diff --git a/boards/iotlab-common/include/periph_conf_common.h b/boards/iotlab-common/include/periph_conf_common.h
index 3e1aa028ba433eb12b7b72e6e6c8129921e951d9..b0d104c9701b34c4c442e4c32e86bbef174c9efa 100644
--- a/boards/iotlab-common/include/periph_conf_common.h
+++ b/boards/iotlab-common/include/periph_conf_common.h
@@ -159,6 +159,29 @@ static const uart_conf_t uart_config[] = {
 #define I2C_0_SDA_PIN       GPIO_PIN(PORT_B,7)
 /** @} */
 
+/**
+ * @brief   Shared SPI clock div table
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
+ */
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 36000000Hz */
+        7,  /* -> 140625Hz */
+        6,  /* -> 281250Hz */
+        4,  /* -> 1125000Hz */
+        2,  /* -> 4500000Hz */
+        1   /* -> 9000000Hz */
+    },
+    {       /* for APB2 @ 72000000Hz */
+        7,  /* -> 281250Hz */
+        7,  /* -> 281250Hz */
+        5,  /* -> 1125000Hz */
+        3,  /* -> 4500000Hz */
+        2   /* -> 9000000Hz */
+    }
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/iotlab-m3/include/board.h b/boards/iotlab-m3/include/board.h
index a88fca79a67e3b53b8ddf9c58a91a1a81d49c581..37618a3860325396e82d763d556486c782cff079 100644
--- a/boards/iotlab-m3/include/board.h
+++ b/boards/iotlab-m3/include/board.h
@@ -38,7 +38,7 @@ extern "C" {
  * @name Define the interface for the connected flash memory
  * @{
  */
-#define EXTFLASH_SPI        SPI_1
+#define EXTFLASH_SPI        SPI_DEV(1)
 #define EXTFLASH_CS         GPIO_PIN(PORT_A,11)
 #define EXTFLASH_WRITE      GPIO_PIN(PORT_C,6)
 #define EXTFLASH_HOLD       GPIO_PIN(PORT_C,9)
diff --git a/boards/iotlab-m3/include/periph_conf.h b/boards/iotlab-m3/include/periph_conf.h
index ae7d37b4b0cd6fb2027b05f1a4b1de1af68785f7..4cf77ad22bc2160d84b4752d15971330e0f3595c 100644
--- a/boards/iotlab-m3/include/periph_conf.h
+++ b/boards/iotlab-m3/include/periph_conf.h
@@ -1,9 +1,9 @@
 /*
- * Copyright (C) 2014 Freie Universität Berlin
+ * Copyright (C) 2014-2016 Freie Universität Berlin
  *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
  */
 
 /**
@@ -31,18 +31,19 @@ extern "C" {
  * @brief SPI configuration
  * @{
  */
-#define SPI_NUMOF           (1U)
-#define SPI_0_EN            1
-
-/* SPI 0 device configuration */
-#define SPI_0_DEV           SPI1
-#define SPI_0_CLKEN()       (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()      (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_BUS_DIV       1   /* 1 -> SPI runs with full CPU clock, 0 -> half CPU clock */
-/* SPI 0 pin configuration */
-#define SPI_0_CLK_PIN       GPIO_PIN(PORT_A,5)
-#define SPI_0_MOSI_PIN      GPIO_PIN(PORT_A,7)
-#define SPI_0_MISO_PIN      GPIO_PIN(PORT_A,6)
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_UNDEF,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/limifrog-v1/include/periph_conf.h b/boards/limifrog-v1/include/periph_conf.h
index 457ec3580fd6777929a1584e441cab76e3801fb3..bec60ee54bf53bf74a57ed6b4a704c84e2b10a6a 100644
--- a/boards/limifrog-v1/include/periph_conf.h
+++ b/boards/limifrog-v1/include/periph_conf.h
@@ -109,40 +109,53 @@ static const uart_conf_t uart_config[] = {
 /** @} */
 
 /**
- * @brief SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-
-/* SPI 0 device configuration */
-#define SPI_0_DEV           SPI1  /* Densitron DD-160128FC-1a OLED display; external pins */
-#define SPI_0_CLKEN()       (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()      (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_IRQ           SPI1_IRQn
-#define SPI_0_ISR           isr_spi1
-/* SPI 0 pin configuration */
-#define SPI_0_PORT_CLKEN()  (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
-#define SPI_0_PORT          GPIOA
-#define SPI_0_PIN_SCK       5
-#define SPI_0_PIN_MOSI      7
-#define SPI_0_PIN_MISO      6
-#define SPI_0_PIN_AF        5
-
-/* SPI 1 device configuration */
-#define SPI_1_DEV           SPI3          /*  Adesto AT45DB641E data flash */
-#define SPI_1_CLKEN()       (periph_clk_en(APB1, RCC_APB1ENR_SPI3EN))
-#define SPI_1_CLKDIS()      (periph_clk_dis(APB1, RCC_APB1ENR_SPI3EN))
-#define SPI_1_IRQ           SPI3_IRQn
-#define SPI_1_ISR           isr_spi3
-/* SPI 1 pin configuration */
-#define SPI_1_PORT_CLKEN()  (periph_clk_en(AHB, RCC_AHBENR_GPIOBEN))
-#define SPI_1_PORT          GPIOB
-#define SPI_1_PIN_SCK       3
-#define SPI_1_PIN_MOSI      5
-#define SPI_1_PIN_MISO      4
-#define SPI_1_PIN_AF        6
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 32000000Hz */
+        7,  /* -> 125000Hz */
+        5,  /* -> 500000Hz */
+        4,  /* -> 1000000Hz */
+        2,  /* -> 4000000Hz */
+        1   /* -> 8000000Hz */
+    },
+    {       /* for APB2 @ 32000000Hz */
+        7,  /* -> 125000Hz */
+        5,  /* -> 500000Hz */
+        4,  /* -> 1000000Hz */
+        2,  /* -> 4000000Hz */
+        1   /* -> 8000000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_UNDEF,
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    },
+    {
+        .dev      = SPI3,
+        .mosi_pin = GPIO_PIN(PORT_B, 5),
+        .miso_pin = GPIO_PIN(PORT_B, 4),
+        .sclk_pin = GPIO_PIN(PORT_B, 3),
+        .cs_pin   = GPIO_UNDEF,
+        .af       = GPIO_AF6,
+        .rccmask  = RCC_APB1ENR_SPI3EN,
+        .apbbus   = APB1
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/maple-mini/include/periph_conf.h b/boards/maple-mini/include/periph_conf.h
index f48e95caccfe892dbbb963a77cab7595facc02e2..a8998b99ee9d678028d8d28e06698e12de8400b1 100644
--- a/boards/maple-mini/include/periph_conf.h
+++ b/boards/maple-mini/include/periph_conf.h
@@ -163,39 +163,55 @@ static const uart_conf_t uart_config[] = {
 #define I2C_1_SDA_PIN       GPIO_PIN(PORT_B, 11) /* D0 */
 /** @} */
 
+/**
+ * @brief   Shared SPI clock div table
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
+ */
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 36000000Hz */
+        7,  /* -> 140625Hz */
+        6,  /* -> 281250Hz */
+        4,  /* -> 1125000Hz */
+        2,  /* -> 4500000Hz */
+        1   /* -> 9000000Hz */
+    },
+    {       /* for APB2 @ 72000000Hz */
+        7,  /* -> 281250Hz */
+        7,  /* -> 281250Hz */
+        5,  /* -> 1125000Hz */
+        3,  /* -> 4500000Hz */
+        2   /* -> 9000000Hz */
+    }
+};
+
 /**
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            0
-#define SPI_IRQ_PRIO        1
-
-/* SPI 0 device config */
-#define SPI_0_DEV               SPI1
-#define SPI_0_CLKEN()           (RCC->APB2ENR |= RCC_APB2ENR_SPI1EN)
-#define SPI_0_CLKDIS()          (RCC->APB2ENR &= ~RCC_APB2ENR_SPI1EN)
-#define SPI_0_IRQ               SPI1_IRQn
-#define SPI_0_IRQ_HANDLER       isr_spi1
-#define SPI_0_BUS_DIV           1
-
-/* SPI 0 pin configuration */
-#define SPI_0_CLK_PIN           GPIO_PIN(PORT_A, 5) /* D6 */
-#define SPI_0_MISO_PIN          GPIO_PIN(PORT_A, 6) /* D5 */
-#define SPI_0_MOSI_PIN          GPIO_PIN(PORT_A, 7) /* D4 */
-
-/* SPI 1 device config */
-#define SPI_1_DEV               SPI2
-#define SPI_1_CLKEN()           (RCC->APB1ENR |= RCC_APB1ENR_SPI2EN)
-#define SPI_1_CLKDIS()          (RCC->APB1ENR &= ~RCC_APB1ENR_SPI2EN)
-#define SPI_1_IRQ               SPI2_IRQn
-#define SPI_1_IRQ_HANDLER       isr_spi2
-#define SPI_1_BUS_DIV           1
-/* SPI 1 pin configuration */
-#define SPI_1_CLK_PIN           GPIO_PIN(PORT_B, 13) /* D30 */
-#define SPI_1_MISO_PIN          GPIO_PIN(PORT_B, 14) /* D29 */
-#define SPI_1_MOSI_PIN          GPIO_PIN(PORT_B, 15) /* D28 */
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A,  7),
+        .miso_pin = GPIO_PIN(PORT_A,  6),
+        .sclk_pin = GPIO_PIN(PORT_A,  5),
+        .cs_pin   = GPIO_UNDEF,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    },
+    {
+        .dev      = SPI2,
+        .mosi_pin = GPIO_PIN(PORT_B, 15),
+        .miso_pin = GPIO_PIN(PORT_B, 14),
+        .sclk_pin = GPIO_PIN(PORT_B, 13),
+        .cs_pin   = GPIO_UNDEF,
+        .rccmask  = RCC_APB1ENR_SPI2EN,
+        .apbbus   = APB1
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/msb-430/Makefile.features b/boards/msb-430/Makefile.features
index be3115c5de3a1911a9b4a745715e3765dcdb4c97..90ca83aa3e51aef31d3e8d65898e410442ab17e3 100644
--- a/boards/msb-430/Makefile.features
+++ b/boards/msb-430/Makefile.features
@@ -1,6 +1,7 @@
 # Put defined MCU peripherals here (in alphabetical order)
 FEATURES_PROVIDED += periph_gpio
 FEATURES_PROVIDED += periph_timer
+FEATURES_PROVIDED += periph_spi
 FEATURES_PROVIDED += periph_uart
 
 # Various other features (if any)
diff --git a/boards/msb-430/include/periph_conf.h b/boards/msb-430/include/periph_conf.h
index cc7c57b82759d4b7595eb93fdf927286ae97e70e..97d4d487c764e5c76b4c43acb4d4ca71b457a405 100644
--- a/boards/msb-430/include/periph_conf.h
+++ b/boards/msb-430/include/periph_conf.h
@@ -75,7 +75,7 @@ extern "C" {
 #define SPI_0_EN            (1U)
 
 /* SPI configuration */
-#define SPI_DEV             (USART_0)
+#define SPI_BASE            (USART_0)
 #define SPI_IE              (SFR->IE1)
 #define SPI_IF              (SFR->IFG1)
 #define SPI_IE_RX_BIT       (1 << 6)
diff --git a/boards/msb-430h/include/periph_conf.h b/boards/msb-430h/include/periph_conf.h
index 0f51ec4a730b4a12f3447d12513b743760061e70..3a9c485fa444628951307785054c4c210108a6bc 100644
--- a/boards/msb-430h/include/periph_conf.h
+++ b/boards/msb-430h/include/periph_conf.h
@@ -77,7 +77,7 @@ extern "C" {
 #define SPI_0_EN            (1U)
 
 /* SPI configuration */
-#define SPI_DEV             (USART_0)
+#define SPI_BASE            (USART_0)
 #define SPI_IE              (SFR->IE1)
 #define SPI_IF              (SFR->IFG1)
 #define SPI_IE_RX_BIT       (1 << 6)
diff --git a/boards/msba2/include/periph_conf.h b/boards/msba2/include/periph_conf.h
index 062da79bac0f7dc8c126ed8c4be2dcea7e0fc82c..4c47032c9ed80dd2f59dc665aa8463ac09e0f079 100644
--- a/boards/msba2/include/periph_conf.h
+++ b/boards/msba2/include/periph_conf.h
@@ -82,10 +82,12 @@ extern "C" {
 
 /**
  * @brief SPI configuration
+ *
+ * The SPI implementation is very much fixed, so we don't need to configure
+ * anything besides the mandatory SPI_NUMOF.
  * @{
  */
 #define SPI_NUMOF           (1)
-#define SPI_0_EN            (1)
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/msbiot/include/board.h b/boards/msbiot/include/board.h
index 5199702afb8be3295cc10d3d8779f049796eb00f..38b7eff4f0844b7f0f3f1f25f41a0cfc9dd955ff 100644
--- a/boards/msbiot/include/board.h
+++ b/boards/msbiot/include/board.h
@@ -32,7 +32,7 @@ extern "C" {
  * @name Configure connected CC1101 (radio) device
  * @{
  */
-#define CC110X_SPI          SPI_0
+#define CC110X_SPI          SPI_DEV(0)
 #define CC110X_CS           GPIO_PIN(PORT_B, 12)
 #define CC110X_GDO0         GPIO_PIN(PORT_C, 4)
 #define CC110X_GDO1         GPIO_PIN(PORT_A, 6)
diff --git a/boards/msbiot/include/periph_conf.h b/boards/msbiot/include/periph_conf.h
index acfb0caf49d5fc5a9779a365a5f364862844f8e4..80bc37a5420980af1dba89ab3428da41c047b14e 100644
--- a/boards/msbiot/include/periph_conf.h
+++ b/boards/msbiot/include/periph_conf.h
@@ -187,34 +187,43 @@ static const uart_conf_t uart_config[] = {
 /** @} */
 
 /**
- * @name SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF             1
-#define SPI_0_EN              1
-#define SPI_1_EN              0
-#define SPI_IRQ_PRIO          1
-
-/* SPI 0 device config */
-#define SPI_0_DEV             SPI1
-#define SPI_0_CLKEN()         (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()        (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_BUS_DIV         1   /* 1 -> SPI runs with half CPU clock, 0 -> quarter CPU clock */
-#define SPI_0_IRQ             SPI1_IRQn
-#define SPI_0_IRQ_HANDLER     isr_spi1
-/* SPI 0 pin configuration */
-#define SPI_0_SCK_PORT        GPIOA
-#define SPI_0_SCK_PIN         5
-#define SPI_0_SCK_AF          5
-#define SPI_0_MISO_PORT       GPIOA
-#define SPI_0_MISO_PIN        6
-#define SPI_0_MISO_AF         5
-#define SPI_0_MOSI_PORT       GPIOA
-#define SPI_0_MOSI_PIN        7
-#define SPI_0_MOSI_AF         5
-#define SPI_0_SCK_PORT_CLKEN()      (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
-#define SPI_0_MISO_PORT_CLKEN()     (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
-#define SPI_0_MOSI_PORT_CLKEN()     (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 42000000Hz */
+        7,  /* -> 164062Hz */
+        6,  /* -> 328125Hz */
+        4,  /* -> 1312500Hz */
+        2,  /* -> 5250000Hz */
+        1   /* -> 10500000Hz */
+    },
+    {       /* for APB2 @ 84000000Hz */
+        7,  /* -> 328125Hz */
+        7,  /* -> 328125Hz */
+        5,  /* -> 1312500Hz */
+        3,  /* -> 5250000Hz */
+        2   /* -> 10500000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_PIN(PORT_A, 4),
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/mulle/board.c b/boards/mulle/board.c
index ec0fbc29b2b2aecf7505520218f7d81bb211a3b7..3bc2899f6328aaa93cedbcb62d0df4909b0e68df 100644
--- a/boards/mulle/board.c
+++ b/boards/mulle/board.c
@@ -34,6 +34,7 @@ static nvram_t mulle_nvram_dev;
 nvram_t *mulle_nvram = &mulle_nvram_dev;
 static nvram_spi_params_t nvram_spi_params = {
         .spi = MULLE_NVRAM_SPI_DEV,
+        .clk = MULLE_NVRAM_SPI_CLK,
         .cs = MULLE_NVRAM_SPI_CS,
         .address_count = MULLE_NVRAM_SPI_ADDRESS_COUNT,
 };
@@ -184,10 +185,6 @@ static int mulle_nvram_init(void)
     } rec;
     rec.u32 = 0;
 
-    if (spi_init_master(MULLE_NVRAM_SPI_DEV, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ) != 0) {
-        return -1;
-    }
-
     if (nvram_spi_init(mulle_nvram, &nvram_spi_params, MULLE_NVRAM_CAPACITY) != 0) {
         return -2;
     }
diff --git a/boards/mulle/include/board.h b/boards/mulle/include/board.h
index 80b24c885614941dfc344ba241f0d4285ebe6709..a875dbae2a136e4f7740ced5a282d7eefd4eb7f7 100644
--- a/boards/mulle/include/board.h
+++ b/boards/mulle/include/board.h
@@ -108,8 +108,8 @@ void board_init(void);
  *
  * {spi bus, spi speed, cs pin, int pin, reset pin, sleep pin}
  */
-#define AT86RF2XX_PARAMS_BOARD      {.spi = SPI_0, \
-                                     .spi_speed = SPI_SPEED_5MHZ, \
+#define AT86RF2XX_PARAMS_BOARD      {.spi = SPI_DEV(0), \
+                                     .spi_clk = SPI_CLK_5MHZ, \
                                      .cs_pin = GPIO_PIN(PORT_D, 4), \
                                      .int_pin = GPIO_PIN(PORT_B, 9), \
                                      .sleep_pin = GPIO_PIN(PORT_E, 6), \
@@ -121,31 +121,31 @@ void board_init(void);
  * @{
  */
 
-#define LIS3DH_INT1   GPIO_PIN(PORT_C, 18)
-#define LIS3DH_INT2   GPIO_PIN(PORT_C, 17)
-#define LIS3DH_CS     GPIO_PIN(PORT_D, 0)
-#define LIS3DH_SPI    SPI_2
-
+#define LIS3DH_INT1                 GPIO_PIN(PORT_C, 18)
+#define LIS3DH_INT2                 GPIO_PIN(PORT_C, 17)
+#define LIS3DH_CS                   GPIO_PIN(PORT_D, 0)
+#define LIS3DH_CLK                  SPI_CLK_5MHZ
+#define LIS3DH_SPI                  SPI_DEV(0)
 /** @} */
 
 /**
  * @name Mulle power control configuration
  */
 /** @{ */
-#define MULLE_POWER_AVDD    GPIO_PIN(PORT_B, 17) /**< AVDD enable pin */
-#define MULLE_POWER_VPERIPH GPIO_PIN(PORT_D,  7) /**< VPERIPH enable pin */
-#define MULLE_POWER_VSEC    GPIO_PIN(PORT_B, 16) /**< VSEC enable pin */
+#define MULLE_POWER_AVDD        GPIO_PIN(PORT_B, 17) /**< AVDD enable pin */
+#define MULLE_POWER_VPERIPH     GPIO_PIN(PORT_D,  7) /**< VPERIPH enable pin */
+#define MULLE_POWER_VSEC        GPIO_PIN(PORT_B, 16) /**< VSEC enable pin */
 /** @} */
 
 /**
  * @name Mulle NVRAM hardware configuration
  */
 /** @{ */
-/** FRAM SPI bus, SPI_2 in RIOT is mapped to hardware bus SPI0, see periph_conf.h */
-#define MULLE_NVRAM_SPI_DEV           SPI_2
-#define MULLE_NVRAM_SPI_CS            GPIO_PIN(PORT_D, 6) /**< FRAM CS pin */
-#define MULLE_NVRAM_CAPACITY          512     /**< FRAM size, in bytes */
-#define MULLE_NVRAM_SPI_ADDRESS_COUNT 1       /**< FRAM addressing size, in bytes */
+#define MULLE_NVRAM_SPI_DEV             SPI_DEV(0)
+#define MULLE_NVRAM_SPI_CLK             SPI_CLK_5MHZ
+#define MULLE_NVRAM_SPI_CS              GPIO_PIN(PORT_D, 6) /**< FRAM CS pin */
+#define MULLE_NVRAM_CAPACITY            512     /**< FRAM size, in bytes */
+#define MULLE_NVRAM_SPI_ADDRESS_COUNT   1       /**< FRAM addressing size, in bytes */
 /** @} */
 
 /**
diff --git a/boards/mulle/include/lis3dh_params.h b/boards/mulle/include/lis3dh_params.h
index d91f198770ecb615e2a676ac342e2b7404547140..5a42f90eacc000aa963cf0ee24c628ba4e0f07c1 100644
--- a/boards/mulle/include/lis3dh_params.h
+++ b/boards/mulle/include/lis3dh_params.h
@@ -33,6 +33,7 @@ static const  lis3dh_params_t lis3dh_params[] =
 {
     {
         .spi   = LIS3DH_SPI,
+        .clk   = LIS3DH_CLK,
         .cs    = LIS3DH_CS,
         .int1  = LIS3DH_INT1,
         .int2  = LIS3DH_INT2,
diff --git a/boards/mulle/include/periph_conf.h b/boards/mulle/include/periph_conf.h
index f51b9f13b7ae33233a32a50b513c5223e4c812d1..80b5dc64566b95b5e8b0fac8581709802c2a9dc6 100644
--- a/boards/mulle/include/periph_conf.h
+++ b/boards/mulle/include/periph_conf.h
@@ -216,159 +216,83 @@ static const pwm_conf_t pwm_config[] = {
 
 /**
  * @name SPI configuration
+ *
+ * Clock configuration values based on the configured 47988736Hz module clock.
+ *
+ * Auto-generated by:
+ * cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c
+ *
  * @{
  */
-#define SPI_NUMOF           3
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-#define SPI_2_EN            1
-#define SPI_3_EN            0
-#define SPI_4_EN            0
-#define SPI_5_EN            0
-#define SPI_6_EN            0
-#define SPI_7_EN            0
-
-#define MULLE_PASTE_PARTS(left, index, right) MULLE_PASTE_PARTS2(left, index, right)
-#define MULLE_PASTE_PARTS2(left, index, right) left##index##right
-
-/* SPI 0 device config */
-/* SPI_0 (in RIOT) is mapped to SPI0, CTAS=0 in hardware */
-#define SPI_0_INDEX             0
-#define SPI_0_CTAS              0
-#define SPI_0_DEV               MULLE_PASTE_PARTS(SPI, SPI_0_INDEX, )
-#define SPI_0_CLKEN()           (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI0_SHIFT) = 1)
-#define SPI_0_CLKDIS()          (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI0_SHIFT) = 0)
-#define SPI_0_IRQ               MULLE_PASTE_PARTS(SPI, SPI_0_INDEX, _IRQn)
-#define SPI_0_IRQ_HANDLER       MULLE_PASTE_PARTS(isr_spi, SPI_0_INDEX, )
-#define SPI_0_IRQ_PRIO          CPU_DEFAULT_IRQ_PRIO
-#define SPI_0_FREQ              SystemBusClock
-/* SPI 0 pin configuration */
-#define SPI_0_SCK_PORT          PORTD
-#define SPI_0_SCK_PIN           1
-#define SPI_0_SCK_PORT_CLKEN()  (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1)
-#define SPI_0_SCK_AF            2
-#define SPI_0_SIN_PORT          PORTD
-#define SPI_0_SIN_PIN           3
-#define SPI_0_SIN_PORT_CLKEN()  (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1)
-#define SPI_0_SIN_AF            2
-#define SPI_0_SOUT_PORT         PORTD
-#define SPI_0_SOUT_PIN          2
-#define SPI_0_SOUT_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1)
-#define SPI_0_SOUT_AF  2
-#define SPI_0_PCS0_PORT         PORTD
-#define SPI_0_PCS0_PIN          0
-#define SPI_0_PCS0_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1)
-#define SPI_0_PCS0_AF           2
-/* SPI chip select polarity */
-#define SPI_0_PCS0_ACTIVE_LOW   1
-#define SPI_0_PCS1_ACTIVE_LOW   1
-#define SPI_0_PCS2_ACTIVE_LOW   1
-#define SPI_0_PCS3_ACTIVE_LOW   1
-
-/* SPI 1 device config */
-/* SPI_1 (in RIOT) is mapped to SPI1, CTAS=0 in hardware */
-#define SPI_1_INDEX             1
-#define SPI_1_CTAS              0
-#define SPI_1_DEV               MULLE_PASTE_PARTS(SPI, SPI_1_INDEX, )
-#define SPI_1_CLKEN()           (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI1_SHIFT) = 1)
-#define SPI_1_CLKDIS()          (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI1_SHIFT) = 0)
-#define SPI_1_IRQ               MULLE_PASTE_PARTS(SPI, SPI_1_INDEX, _IRQn)
-#define SPI_1_IRQ_HANDLER       MULLE_PASTE_PARTS(isr_spi, SPI_1_INDEX, )
-#define SPI_1_IRQ_PRIO          CPU_DEFAULT_IRQ_PRIO
-#define SPI_1_FREQ              SystemBusClock
-/* SPI 0 pin configuration */
-#define SPI_1_SCK_PORT          PORTE
-#define SPI_1_SCK_PIN           2
-#define SPI_1_SCK_PORT_CLKEN()  (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTE_SHIFT) = 1)
-#define SPI_1_SCK_AF            2
-#define SPI_1_SIN_PORT          PORTE
-#define SPI_1_SIN_PIN           3
-#define SPI_1_SIN_PORT_CLKEN()  (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTE_SHIFT) = 1)
-#define SPI_1_SIN_AF            2
-#define SPI_1_SOUT_PORT         PORTE
-#define SPI_1_SOUT_PIN          1
-#define SPI_1_SOUT_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTE_SHIFT) = 1)
-#define SPI_1_SOUT_AF  2
-#define SPI_1_PCS0_PORT         PORTE
-#define SPI_1_PCS0_PIN          4
-#define SPI_1_PCS0_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTE_SHIFT) = 1)
-#define SPI_1_PCS0_AF           2
-/* SPI chip select polarity */
-#define SPI_1_PCS0_ACTIVE_LOW   1
-#define SPI_1_PCS1_ACTIVE_LOW   1
-#define SPI_1_PCS2_ACTIVE_LOW   1
-#define SPI_1_PCS3_ACTIVE_LOW   1
-
-/* SPI 2 device config */
-/* SPI_2 (in RIOT) is mapped to SPI0, CTAS=1 in hardware */
-#define SPI_2_INDEX             0
-#define SPI_2_CTAS              1
-#define SPI_2_DEV               MULLE_PASTE_PARTS(SPI, SPI_2_INDEX, )
-#define SPI_2_CLKEN()           (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI0_SHIFT) = 1)
-#define SPI_2_CLKDIS()          (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI0_SHIFT) = 0)
-#define SPI_2_IRQ               MULLE_PASTE_PARTS(SPI, SPI_2_INDEX, _IRQn)
-/* #define SPI_2_IRQ_HANDLER       MULLE_PASTE_PARTS(isr_spi, SPI_2_INDEX, ) */
-#define SPI_2_IRQ_PRIO          CPU_DEFAULT_IRQ_PRIO
-#define SPI_2_FREQ              SystemBusClock
-/* SPI 2 pin configuration, must be the same as the other RIOT device using this
- * hardware module */
-#define SPI_2_SCK_PORT          PORTD
-#define SPI_2_SCK_PIN           1
-#define SPI_2_SCK_PORT_CLKEN()  (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1)
-#define SPI_2_SCK_AF            2
-#define SPI_2_SIN_PORT          PORTD
-#define SPI_2_SIN_PIN           3
-#define SPI_2_SIN_PORT_CLKEN()  (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1)
-#define SPI_2_SIN_AF            2
-#define SPI_2_SOUT_PORT         PORTD
-#define SPI_2_SOUT_PIN          2
-#define SPI_2_SOUT_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1)
-#define SPI_2_SOUT_AF  2
-#define SPI_2_PCS0_PORT         PORTD
-#define SPI_2_PCS0_PIN          0
-#define SPI_2_PCS0_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1)
-#define SPI_2_PCS0_AF           2
-/* SPI chip select polarity */
-#define SPI_2_PCS0_ACTIVE_LOW   1
-#define SPI_2_PCS1_ACTIVE_LOW   1
-#define SPI_2_PCS2_ACTIVE_LOW   1
-#define SPI_2_PCS3_ACTIVE_LOW   1
-
-/**
- * @name SPI delay timing configuration
- * @{ */
-/* These values are necessary for communicating with the AT86RF212B when running
- * the MCU core at high clock frequencies. */
-/* NB: The given values are the reciprocals of the time, in order to compute the
- * scalers using only integer math. */
-#define SPI_0_TCSC_FREQ (5555555) /* It looks silly, but this is correct. 1/180e-9 */
-#define SPI_0_TASC_FREQ (5454545) /* It looks silly, but this is correct. 1/183e-9 */
-#define SPI_0_TDT_FREQ  (4000000) /* 1/250e-9 */
-
-/* SPI_1 timings */
-#define SPI_1_TCSC_FREQ (0)
-#define SPI_1_TASC_FREQ (0)
-#define SPI_1_TDT_FREQ  (0)
-
-/* SPI_2 timings */
-#define SPI_2_TCSC_FREQ (0)
-#define SPI_2_TASC_FREQ (0)
-#define SPI_2_TDT_FREQ  (0)
+static const uint32_t spi_clk_config[] = {
+    (
+        SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) |          /* -> 93728Hz */
+        SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(8) |
+        SPI_CTAR_PASC(0) | SPI_CTAR_ASC(8) |
+        SPI_CTAR_PDT(0) | SPI_CTAR_DT(8)
+    ),
+    (
+        SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) |          /* -> 374912Hz */
+        SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(6) |
+        SPI_CTAR_PASC(0) | SPI_CTAR_ASC(6) |
+        SPI_CTAR_PDT(0) | SPI_CTAR_DT(6)
+    ),
+    (
+        SPI_CTAR_PBR(1) | SPI_CTAR_BR(4) |          /* -> 999765Hz */
+        SPI_CTAR_PCSSCK(1) | SPI_CTAR_CSSCK(3) |
+        SPI_CTAR_PASC(1) | SPI_CTAR_ASC(3) |
+        SPI_CTAR_PDT(1) | SPI_CTAR_DT(3)
+    ),
+    (
+        SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) |          /* -> 4798873Hz */
+        SPI_CTAR_PCSSCK(2) | SPI_CTAR_CSSCK(0) |
+        SPI_CTAR_PASC(2) | SPI_CTAR_ASC(0) |
+        SPI_CTAR_PDT(2) | SPI_CTAR_DT(0)
+    ),
+    (
+        SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) |          /* -> 7998122Hz */
+        SPI_CTAR_PCSSCK(1) | SPI_CTAR_CSSCK(0) |
+        SPI_CTAR_PASC(1) | SPI_CTAR_ASC(0) |
+        SPI_CTAR_PDT(1) | SPI_CTAR_DT(0)
+    )
+};
 
-/** @} */
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI0,
+        .pin_miso = GPIO_PIN(PORT_D, 3),
+        .pin_mosi = GPIO_PIN(PORT_D, 2),
+        .pin_clk  = GPIO_PIN(PORT_D, 1),
+        .pin_cs   = {
+            GPIO_PIN(PORT_D, 0),
+            GPIO_UNDEF,
+            GPIO_UNDEF,
+            GPIO_UNDEF,
+            GPIO_UNDEF
+        },
+        .pcr      = GPIO_AF_2,
+        .simmask  = SIM_SCGC6_SPI0_MASK
+    },
+    {
+        .dev      = SPI1,
+        .pin_miso = GPIO_PIN(PORT_E, 3),
+        .pin_mosi = GPIO_PIN(PORT_E, 1),
+        .pin_clk  = GPIO_PIN(PORT_E, 2),
+        .pin_cs   = {
+            GPIO_PIN(PORT_E, 4),
+            GPIO_UNDEF,
+            GPIO_UNDEF,
+            GPIO_UNDEF,
+            GPIO_UNDEF
+        },
+        .pcr      = GPIO_AF_2,
+        .simmask  = SIM_SCGC6_SPI1_MASK
+    }
+};
 
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
-
-/**
- * @name I2C configuration
- * @{
- */
-#define I2C_NUMOF               (1U)
-#define I2C_CLK                 SystemBusClock
-#define I2C_0_EN                1
-#define I2C_1_EN                0
-#define I2C_IRQ_PRIO            CPU_DEFAULT_IRQ_PRIO
 /**
  * @name I2C baud rate configuration
  * @{
@@ -387,6 +311,16 @@ static const pwm_conf_t pwm_config[] = {
 #define KINETIS_I2C_F_MULT_FAST_PLUS (0)
 /** @} */
 
+/**
+ * @name I2C configuration
+ * @{
+ */
+#define I2C_NUMOF               (1U)
+#define I2C_CLK                 SystemBusClock
+#define I2C_0_EN                1
+#define I2C_1_EN                0
+#define I2C_IRQ_PRIO            CPU_DEFAULT_IRQ_PRIO
+
 /* I2C 0 device configuration */
 #define I2C_0_DEV               I2C0
 #define I2C_0_CLKEN()           (BITBAND_REG32(SIM->SCGC4, SIM_SCGC4_I2C0_SHIFT) = 1)
@@ -402,7 +336,6 @@ static const pwm_conf_t pwm_config[] = {
 #define I2C_0_PORT_CFG          (PORT_PCR_MUX(I2C_0_PIN_AF) | PORT_PCR_ODE_MASK)
 /** @} */
 
-
 /**
  * @name GPIO configuration
  * @{
diff --git a/boards/nrf52dk/Makefile.features b/boards/nrf52dk/Makefile.features
index a12def18a02e6511020e925cea38fd4633533c98..748d31f8961656c3c9199b847d6964dd2b1442fc 100644
--- a/boards/nrf52dk/Makefile.features
+++ b/boards/nrf52dk/Makefile.features
@@ -4,6 +4,7 @@ FEATURES_PROVIDED += periph_flashpage
 FEATURES_PROVIDED += periph_gpio
 FEATURES_PROVIDED += periph_hwrng
 FEATURES_PROVIDED += periph_rtt
+FEATURES_PROVIDED += periph_spi
 FEATURES_PROVIDED += periph_timer
 FEATURES_PROVIDED += periph_uart
 
diff --git a/boards/nrf52dk/include/periph_conf.h b/boards/nrf52dk/include/periph_conf.h
index 2975d5968f1fa624e06ebe8dadb22eb296b50195..5f128385b6855eeddd2bd65211a844878257b044 100644
--- a/boards/nrf52dk/include/periph_conf.h
+++ b/boards/nrf52dk/include/periph_conf.h
@@ -74,6 +74,21 @@ static const timer_conf_t timer_config[] = {
 #define UART_PIN_TX         6
 /** @} */
 
+/**
+ * @name SPI configuration
+ * @{
+ */
+static const spi_conf_t spi_config[] = {
+    {
+        .dev  = NRF_SPI0,
+        .sclk = 15,
+        .mosi = 13,
+        .miso = 14 }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/nrf6310/include/periph_conf.h b/boards/nrf6310/include/periph_conf.h
index 636b4e0f05a2372bd5b3d9c897bf0eb96a67d6da..cc53add564991f386acc39547bfe7d40a17da36a 100644
--- a/boards/nrf6310/include/periph_conf.h
+++ b/boards/nrf6310/include/periph_conf.h
@@ -100,22 +100,22 @@ static const timer_conf_t timer_config[] = {
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-#define SPI_IRQ_PRIO        1
-
-/* SPI Master 0 pin configuration */
-#define SPI_0_DEV           NRF_SPI0
-#define SPI_0_PIN_SCK       23
-#define SPI_0_PIN_MISO      22
-#define SPI_0_PIN_MOSI      20
-
-/* SPI Master 1 pin configuration */
-#define SPI_1_DEV           NRF_SPI1
-#define SPI_1_PIN_SCK       16
-#define SPI_1_PIN_MISO      17
-#define SPI_1_PIN_MOSI      18
+static const spi_conf_t spi_config[] = {
+    {
+        .dev  = NRF_SPI0,
+        .sclk = 23,
+        .mosi = 22,
+        .miso = 20
+    },
+    {
+        .dev  = NRF_SPI1,
+        .sclk = 16,
+        .mosi = 17,
+        .miso = 18
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/nucleo-f072/Makefile.features b/boards/nucleo-f072/Makefile.features
index 5942339b26cf9947e91bba26b812162822a3870f..4a5c8488bc8d267bedfadc74865727642de82de9 100644
--- a/boards/nucleo-f072/Makefile.features
+++ b/boards/nucleo-f072/Makefile.features
@@ -6,6 +6,7 @@ FEATURES_PROVIDED += periph_pwm
 FEATURES_PROVIDED += periph_rtc
 FEATURES_PROVIDED += periph_timer
 FEATURES_PROVIDED += periph_uart
+FEATURES_PROVIDED += periph_spi
 
 # load the common Makefile.features for Nucleo boards
 include $(RIOTBOARD)/nucleo-common/Makefile.features
diff --git a/boards/nucleo-f072/include/periph_conf.h b/boards/nucleo-f072/include/periph_conf.h
index 5bf6742b7c2dff8b5a778830e8ee0ef8a33ae973..014db5e4af33efa45478d96fa5d44a15eb3b6e6b 100644
--- a/boards/nucleo-f072/include/periph_conf.h
+++ b/boards/nucleo-f072/include/periph_conf.h
@@ -161,6 +161,46 @@ static const pwm_conf_t pwm_config[] = {
 #define PWM_NUMOF           (sizeof(pwm_config) / sizeof(pwm_config[0]))
 /** @} */
 
+/**
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
+ * @{
+ */
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 48000000Hz */
+        7,  /* -> 187500Hz */
+        6,  /* -> 375000Hz */
+        5,  /* -> 750000Hz */
+        2,  /* -> 6000000Hz */
+        1   /* -> 12000000Hz */
+    },
+    {       /* for APB2 @ 48000000Hz */
+        7,  /* -> 187500Hz */
+        6,  /* -> 375000Hz */
+        5,  /* -> 750000Hz */
+        2,  /* -> 6000000Hz */
+        1   /* -> 12000000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_PIN(PORT_A, 4),
+        .af       = GPIO_AF0,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
+/** @} */
+
 /**
  * @brief   ADC configuration
  * @{
diff --git a/boards/nucleo-f091/Makefile.features b/boards/nucleo-f091/Makefile.features
index 5942339b26cf9947e91bba26b812162822a3870f..4a5c8488bc8d267bedfadc74865727642de82de9 100644
--- a/boards/nucleo-f091/Makefile.features
+++ b/boards/nucleo-f091/Makefile.features
@@ -6,6 +6,7 @@ FEATURES_PROVIDED += periph_pwm
 FEATURES_PROVIDED += periph_rtc
 FEATURES_PROVIDED += periph_timer
 FEATURES_PROVIDED += periph_uart
+FEATURES_PROVIDED += periph_spi
 
 # load the common Makefile.features for Nucleo boards
 include $(RIOTBOARD)/nucleo-common/Makefile.features
diff --git a/boards/nucleo-f091/include/periph_conf.h b/boards/nucleo-f091/include/periph_conf.h
index 5052e1c22ed330b90a549ed4fbaba0bacdecd18a..d80a09285614eac16e35ceae4c730b7e82f98796 100644
--- a/boards/nucleo-f091/include/periph_conf.h
+++ b/boards/nucleo-f091/include/periph_conf.h
@@ -104,6 +104,48 @@ static const uart_conf_t uart_config[] = {
 #define UART_NUMOF          (sizeof(uart_config) / sizeof(uart_config[0]))
 /** @} */
 
+
+/**
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
+ * @{
+ */
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 48000000Hz */
+        7,  /* -> 187500Hz */
+        6,  /* -> 375000Hz */
+        5,  /* -> 750000Hz */
+        2,  /* -> 6000000Hz */
+        1   /* -> 12000000Hz */
+    },
+    {       /* for APB2 @ 48000000Hz */
+        7,  /* -> 187500Hz */
+        6,  /* -> 375000Hz */
+        5,  /* -> 750000Hz */
+        2,  /* -> 6000000Hz */
+        1   /* -> 12000000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_PIN(PORT_B, 6),
+        .af       = GPIO_AF0,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
+/** @} */
+
+
 /**
  * @brief   PWM configuration
  * @{
diff --git a/boards/nucleo-f103/include/periph_conf.h b/boards/nucleo-f103/include/periph_conf.h
index 335c15ffe2a8f67a37b8e389c8e4100fc666ca41..7a4a898db6696f6a5706bf30b42f20e7bd1e79dd 100644
--- a/boards/nucleo-f103/include/periph_conf.h
+++ b/boards/nucleo-f103/include/periph_conf.h
@@ -160,38 +160,51 @@ static const uart_conf_t uart_config[] = {
 /** @} */
 
 /**
- * @name SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            0
-#define SPI_IRQ_PRIO        1
-
-/* SPI 0 device config */
-#define SPI_0_DEV               SPI1
-#define SPI_0_CLKEN()           (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()          (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_IRQ               SPI1_IRQn
-#define SPI_0_IRQ_HANDLER       isr_spi1
-#define SPI_0_BUS_DIV           1
-
-/* SPI 0 pin configuration */
-#define SPI_0_CLK_PIN           GPIO_PIN(PORT_A, 5)
-#define SPI_0_MISO_PIN          GPIO_PIN(PORT_A, 6)
-#define SPI_0_MOSI_PIN          GPIO_PIN(PORT_A, 7)
-
-/* SPI 1 device config */
-#define SPI_1_DEV               SPI2
-#define SPI_1_CLKEN()           (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_1_CLKDIS()          (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_1_IRQ               SPI2_IRQn
-#define SPI_1_IRQ_HANDLER       isr_spi2
-#define SPI_1_BUS_DIV           1
-/* SPI 1 pin configuration */
-#define SPI_1_CLK_PIN           GPIO_PIN(PORT_B, 13)
-#define SPI_1_MISO_PIN          GPIO_PIN(PORT_B, 14)
-#define SPI_1_MOSI_PIN          GPIO_PIN(PORT_B, 15)
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 36000000Hz */
+        7,  /* -> 140625Hz */
+        6,  /* -> 281250Hz */
+        4,  /* -> 1125000Hz */
+        2,  /* -> 4500000Hz */
+        1   /* -> 9000000Hz */
+    },
+    {       /* for APB2 @ 72000000Hz */
+        7,  /* -> 281250Hz */
+        7,  /* -> 281250Hz */
+        5,  /* -> 1125000Hz */
+        3,  /* -> 4500000Hz */
+        2   /* -> 9000000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_UNDEF,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    },
+    {
+        .dev      = SPI2,
+        .mosi_pin = GPIO_PIN(PORT_B, 15),
+        .miso_pin = GPIO_PIN(PORT_B, 14),
+        .sclk_pin = GPIO_PIN(PORT_B, 13),
+        .cs_pin   = GPIO_UNDEF,
+        .rccmask  = RCC_APB1ENR_SPI2EN,
+        .apbbus   = APB1
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/nucleo-f207/include/periph_conf.h b/boards/nucleo-f207/include/periph_conf.h
index 664f183fd5d0dd6b2eaa94dcc448b83abe88eecb..59554be7eba394fb26eff69ad0ae70b8433afdc0 100644
--- a/boards/nucleo-f207/include/periph_conf.h
+++ b/boards/nucleo-f207/include/periph_conf.h
@@ -167,58 +167,55 @@ static const uart_conf_t uart_config[] = {
 /** @} */
 
 /**
- * @name SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-#define SPI_IRQ_PRIO        1
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 30000000Hz */
+        7,  /* -> 117187Hz */
+        5,  /* -> 468750Hz */
+        4,  /* -> 937500Hz */
+        2,  /* -> 3750000Hz */
+        1   /* -> 7500000Hz */
+    },
+    {       /* for APB2 @ 60000000Hz */
+        7,  /* -> 234375Hz */
+        6,  /* -> 468750Hz */
+        5,  /* -> 937500Hz */
+        3,  /* -> 3750000Hz */
+        2   /* -> 7500000Hz */
+    }
+};
 
-/* SPI 0 device config */
-#define SPI_0_DEV               SPI1
-#define SPI_0_CLKEN()           (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()          (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_BUS_DIV           1   /* 1 -> SPI bus runs with half CPU clock, 0 -> quarter CPU clock */
-#define SPI_0_IRQ               SPI1_IRQn
-#define SPI_0_IRQ_HANDLER       isr_spi1
-/* SPI 0 pin configuration */
-#define SPI_0_SCK_PORT          GPIOA       /* A5 pin is shared with the green LED. */
-#define SPI_0_SCK_PIN           5
-#define SPI_0_SCK_AF            5
-#define SPI_0_SCK_PORT_CLKEN()  (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
-#define SPI_0_MISO_PORT         GPIOA
-#define SPI_0_MISO_PIN          6
-#define SPI_0_MISO_AF           5
-#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
-#define SPI_0_MOSI_PORT         GPIOA
-#define SPI_0_MOSI_PIN          7
-#define SPI_0_MOSI_AF           5
-#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_PIN(PORT_A, 4),
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    },
+    {
+        .dev      = SPI2,
+        .mosi_pin = GPIO_PIN(PORT_B, 15),
+        .miso_pin = GPIO_PIN(PORT_C, 2),
+        .sclk_pin = GPIO_PIN(PORT_B, 13),
+        .cs_pin   = GPIO_PIN(PORT_B, 12),
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB1ENR_SPI2EN,
+        .apbbus   = APB1
+    }
+};
 
-/* SPI 1 device config */
-#define SPI_1_DEV               SPI2
-#define SPI_1_CLKEN()           (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_1_CLKDIS()          (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_1_BUS_DIV           0   /* 1 -> SPI bus runs with half CPU clock, 0 -> quarter CPU clock */
-#define SPI_1_IRQ               SPI2_IRQn
-#define SPI_1_IRQ_HANDLER       isr_spi2
-/* SPI 1 pin configuration */
-#define SPI_1_SCK_PORT          GPIOB
-#define SPI_1_SCK_PIN           3
-#define SPI_1_SCK_AF            5
-#define SPI_1_SCK_PORT_CLKEN()  (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN))
-#define SPI_1_MISO_PORT         GPIOB
-#define SPI_1_MISO_PIN          4
-#define SPI_1_MISO_AF           5
-#define SPI_1_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN))
-#define SPI_1_MOSI_PORT         GPIOB
-#define SPI_1_MOSI_PIN          5
-#define SPI_1_MOSI_AF           5
-#define SPI_1_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN))
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
-
 /**
  * @name I2C configuration
  * @{
@@ -258,7 +255,7 @@ static const uart_conf_t uart_config[] = {
  */
 #define ADC_CONFIG {              \
     {GPIO_PIN(PORT_A, 4), 0, 0},  \
-    {GPIO_PIN(PORT_A, 5), 1, 0}  \
+    {GPIO_PIN(PORT_C, 0), 1, 0}  \
 }
 #define ADC_NUMOF          (2)
 
diff --git a/boards/nucleo-f303/include/periph_conf.h b/boards/nucleo-f303/include/periph_conf.h
index 5b81d5b5c931ca1cacd814b18e69fcc3fa265385..ccab5c0e3fe58913e3ca1bacb79674078918ffcc 100755
--- a/boards/nucleo-f303/include/periph_conf.h
+++ b/boards/nucleo-f303/include/periph_conf.h
@@ -138,53 +138,53 @@ static const pwm_conf_t pwm_config[] = {
 /** @} */
 
 /**
- * @name SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-#define SPI_IRQ_PRIO        1
-
-/* SPI 0 device config */
-#define SPI_0_DEV               SPI1
-#define SPI_0_CLKEN()           (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()          (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_IRQ               SPI1_IRQn
-#define SPI_0_IRQ_HANDLER       isr_spi1
-/* SPI 0 pin configuration */
-#define SPI_0_SCK_PORT          GPIOA
-#define SPI_0_SCK_PIN           5
-#define SPI_0_SCK_AF            5
-#define SPI_0_SCK_PORT_CLKEN()  (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
-#define SPI_0_MISO_PORT         GPIOA
-#define SPI_0_MISO_PIN          6
-#define SPI_0_MISO_AF           5
-#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
-#define SPI_0_MOSI_PORT         GPIOA
-#define SPI_0_MOSI_PIN          7
-#define SPI_0_MOSI_AF           5
-#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
-
-/* SPI 1 device config */
-#define SPI_1_DEV               SPI3
-#define SPI_1_CLKEN()           (periph_clk_en(APB1, RCC_APB1ENR_SPI3EN))
-#define SPI_1_CLKDIS()          (periph_clk_dis(APB1, RCC_APB1ENR_SPI3EN))
-#define SPI_1_IRQ               SPI3_IRQn
-#define SPI_1_IRQ_HANDLER       isr_spi3
-/* SPI 1 pin configuration */
-#define SPI_1_SCK_PORT          GPIOC
-#define SPI_1_SCK_PIN           10
-#define SPI_1_SCK_AF            6
-#define SPI_1_SCK_PORT_CLKEN()  (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN))
-#define SPI_1_MISO_PORT         GPIOC
-#define SPI_1_MISO_PIN          11
-#define SPI_1_MISO_AF           6
-#define SPI_1_MISO_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN))
-#define SPI_1_MOSI_PORT         GPIOC
-#define SPI_1_MOSI_PIN          12
-#define SPI_1_MOSI_AF           6
-#define SPI_1_MOSI_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN))
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 36000000Hz */
+        7,  /* -> 140625Hz */
+        6,  /* -> 281250Hz */
+        4,  /* -> 1125000Hz */
+        2,  /* -> 4500000Hz */
+        1   /* -> 9000000Hz */
+    },
+    {       /* for APB2 @ 72000000Hz */
+        7,  /* -> 281250Hz */
+        7,  /* -> 281250Hz */
+        5,  /* -> 1125000Hz */
+        3,  /* -> 4500000Hz */
+        2   /* -> 9000000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_PIN(PORT_A, 4),
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    },
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_C, 12),
+        .miso_pin = GPIO_PIN(PORT_C, 11),
+        .sclk_pin = GPIO_PIN(PORT_C, 10),
+        .cs_pin   = GPIO_UNDEF,
+        .af       = GPIO_AF6,
+        .rccmask  = RCC_APB1ENR_SPI3EN,
+        .apbbus   = APB1
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/nucleo-f334/include/periph_conf.h b/boards/nucleo-f334/include/periph_conf.h
index d7b602d0ba61d579b1461da0e1bed711cff3d40a..06bd731cd3b6747db1c3648edfdfeb65d918a6ab 100644
--- a/boards/nucleo-f334/include/periph_conf.h
+++ b/boards/nucleo-f334/include/periph_conf.h
@@ -122,32 +122,43 @@ static const pwm_conf_t pwm_config[] = {
 /** @} */
 
 /**
- * @name SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF           (1U)
-#define SPI_0_EN            1
-#define SPI_IRQ_PRIO        1
-
-/* SPI 0 device config */
-#define SPI_0_DEV               SPI1
-#define SPI_0_CLKEN()           (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()          (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_IRQ               SPI1_IRQn
-#define SPI_0_IRQ_HANDLER       isr_spi1
-/* SPI 0 pin configuration */
-#define SPI_0_SCK_PORT          GPIOA
-#define SPI_0_SCK_PIN           5
-#define SPI_0_SCK_AF            5
-#define SPI_0_SCK_PORT_CLKEN()  (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
-#define SPI_0_MISO_PORT         GPIOA
-#define SPI_0_MISO_PIN          6
-#define SPI_0_MISO_AF           5
-#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
-#define SPI_0_MOSI_PORT         GPIOA
-#define SPI_0_MOSI_PIN          7
-#define SPI_0_MOSI_AF           5
-#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 36000000Hz */
+        7,  /* -> 140625Hz */
+        6,  /* -> 281250Hz */
+        4,  /* -> 1125000Hz */
+        2,  /* -> 4500000Hz */
+        1   /* -> 9000000Hz */
+    },
+    {       /* for APB2 @ 72000000Hz */
+        7,  /* -> 281250Hz */
+        7,  /* -> 281250Hz */
+        5,  /* -> 1125000Hz */
+        3,  /* -> 4500000Hz */
+        2   /* -> 9000000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_UNDEF,
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/nucleo-f401/include/periph_conf.h b/boards/nucleo-f401/include/periph_conf.h
index 5ff2e339c8fcb911c2c96bbe91ab923905d4d173..f011f1bbfcc19034073177fa4d049878c6ae1fc4 100644
--- a/boards/nucleo-f401/include/periph_conf.h
+++ b/boards/nucleo-f401/include/periph_conf.h
@@ -141,33 +141,43 @@ static const pwm_conf_t pwm_config[] = {
 /** @} */
 
 /**
- * @name SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF           (1U)
-#define SPI_0_EN            1
-#define SPI_IRQ_PRIO        1
-
-/* SPI 0 device config */
-#define SPI_0_DEV               SPI1
-#define SPI_0_CLKEN()           (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()          (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_BUS_DIV           1   /* 1 -> SPI bus runs with half CPU clock, 0 -> quarter CPU clock */
-#define SPI_0_IRQ               SPI1_IRQn
-#define SPI_0_IRQ_HANDLER       isr_spi1
-/* SPI 0 pin configuration */
-#define SPI_0_SCK_PORT          GPIOA       /* A5 pin is shared with the green LED. */
-#define SPI_0_SCK_PIN           5
-#define SPI_0_SCK_AF            5
-#define SPI_0_SCK_PORT_CLKEN()  (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
-#define SPI_0_MISO_PORT         GPIOA
-#define SPI_0_MISO_PIN          6
-#define SPI_0_MISO_AF           5
-#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
-#define SPI_0_MOSI_PORT         GPIOA
-#define SPI_0_MOSI_PIN          7
-#define SPI_0_MOSI_AF           5
-#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 42000000Hz */
+        7,  /* -> 164062Hz */
+        6,  /* -> 328125Hz */
+        4,  /* -> 1312500Hz */
+        2,  /* -> 5250000Hz */
+        1   /* -> 10500000Hz */
+    },
+    {       /* for APB2 @ 84000000Hz */
+        7,  /* -> 328125Hz */
+        7,  /* -> 328125Hz */
+        5,  /* -> 1312500Hz */
+        3,  /* -> 5250000Hz */
+        2   /* -> 10500000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_PIN(PORT_A, 4),
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 
diff --git a/boards/nucleo-f446/include/periph_conf.h b/boards/nucleo-f446/include/periph_conf.h
index b6738f594137cf4d8db507e27bec03abc91212c9..47ed25898c8157c823a2680ecefe7b5a6ea034f4 100644
--- a/boards/nucleo-f446/include/periph_conf.h
+++ b/boards/nucleo-f446/include/periph_conf.h
@@ -167,33 +167,43 @@ static const pwm_conf_t pwm_config[] = {
 /** @} */
 
 /**
- * @name SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF           (1U)
-#define SPI_0_EN            1
-#define SPI_IRQ_PRIO        1
-
-/* SPI 0 device config */
-#define SPI_0_DEV               SPI1
-#define SPI_0_CLKEN()           (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()          (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_BUS_DIV           1   /* 1 -> SPI bus runs with half CPU clock, 0 -> quarter CPU clock */
-#define SPI_0_IRQ               SPI1_IRQn
-#define SPI_0_IRQ_HANDLER       isr_spi1
-/* SPI 0 pin configuration */
-#define SPI_0_SCK_PORT          GPIOA       /* A5 pin is shared with the green LED. */
-#define SPI_0_SCK_PIN           5
-#define SPI_0_SCK_AF            5
-#define SPI_0_SCK_PORT_CLKEN()  (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
-#define SPI_0_MISO_PORT         GPIOA
-#define SPI_0_MISO_PIN          6
-#define SPI_0_MISO_AF           5
-#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
-#define SPI_0_MOSI_PORT         GPIOA
-#define SPI_0_MOSI_PIN          7
-#define SPI_0_MOSI_AF           5
-#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 90000000Hz */
+        7,  /* -> 351562Hz */
+        7,  /* -> 351562Hz */
+        6,  /* -> 703125Hz */
+        3,  /* -> 5625000Hz */
+        2   /* -> 11250000Hz */
+    },
+    {       /* for APB2 @ 180000000Hz */
+        7,  /* -> 703125Hz */
+        7,  /* -> 703125Hz */
+        7,  /* -> 703125Hz */
+        4,  /* -> 5625000Hz */
+        3   /* -> 11250000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_PIN(PORT_A, 4),
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 
diff --git a/boards/nucleo-l1/include/periph_conf.h b/boards/nucleo-l1/include/periph_conf.h
index 409a8e1bc7309f5a4f04e7092450d068a832f39e..dbec32fe24a8bfba2441ec2c8d4b29683f238f1c 100644
--- a/boards/nucleo-l1/include/periph_conf.h
+++ b/boards/nucleo-l1/include/periph_conf.h
@@ -1,9 +1,9 @@
 /*
  * Copyright (C) 2014-2016 Freie Universität Berlin
  *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
  */
 
 /**
@@ -105,25 +105,43 @@ static const uart_conf_t uart_config[] = {
 /** @} */
 
 /**
- * @brief SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF           (1U)
-#define SPI_0_EN            1
-
-/* SPI 0 device configuration */
-#define SPI_0_DEV           SPI1
-#define SPI_0_CLKEN()       (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()      (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_IRQ           SPI1_IRQn
-#define SPI_0_ISR           isr_spi1
-/* SPI 0 pin configuration */
-#define SPI_0_PORT_CLKEN()  (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
-#define SPI_0_PORT          GPIOA
-#define SPI_0_PIN_SCK       5
-#define SPI_0_PIN_MOSI      7
-#define SPI_0_PIN_MISO      6
-#define SPI_0_PIN_AF        5
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 32000000Hz */
+        7,  /* -> 125000Hz */
+        5,  /* -> 500000Hz */
+        4,  /* -> 1000000Hz */
+        2,  /* -> 4000000Hz */
+        1   /* -> 8000000Hz */
+    },
+    {       /* for APB2 @ 32000000Hz */
+        7,  /* -> 125000Hz */
+        5,  /* -> 500000Hz */
+        4,  /* -> 1000000Hz */
+        2,  /* -> 4000000Hz */
+        1   /* -> 8000000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_UNDEF,
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/opencm9-04/include/periph_conf.h b/boards/opencm9-04/include/periph_conf.h
index 4a24abdf2e1b93d3c5a05fc122b85449c03fce63..91168e89a1d9eb7d8f4c3c7f97d30c1affb5cee2 100644
--- a/boards/opencm9-04/include/periph_conf.h
+++ b/boards/opencm9-04/include/periph_conf.h
@@ -135,13 +135,6 @@ static const uart_conf_t uart_config[] = {
 #define I2C_NUMOF           (0)
 /** @} */
 
-/**
- * @name SPI configuration
- * @{
- */
-#define SPI_NUMOF           (0)
-/** @} */
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/openmote-cc2538/include/periph_conf.h b/boards/openmote-cc2538/include/periph_conf.h
index 845487b02dac21616e187122d3608492362c80fe..88b9fa8e3b467d6183052fe12d71fe2e9de88614 100644
--- a/boards/openmote-cc2538/include/periph_conf.h
+++ b/boards/openmote-cc2538/include/periph_conf.h
@@ -30,7 +30,7 @@
  * @name Clock system configuration
  * @{
  */
-#define CLOCK_CORECLOCK     (32000000U)         /* desired core clock frequency, 32MHz */
+#define CLOCK_CORECLOCK     (32000000U)     /* desired core clock frequency, 32MHz */
 /** @} */
 
 /**
@@ -104,14 +104,26 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = {
 };
 /** @} */
 
+/**
+ * @brief   Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz)
+ *
+ * Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where
+ * 1 < CPSR < 255 and
+ * 0 < SCR  < 256
+ */
+static const spi_clk_conf_t spi_clk_config[] = {
+    { .cpsr = 10, .scr = 31 },  /* 100khz */
+    { .cpsr =  2, .scr = 39 },  /* 400khz */
+    { .cpsr =  2, .scr = 15 },  /* 1MHz */
+    { .cpsr =  2, .scr =  2 },  /* ~4.5MHz */
+    { .cpsr =  2, .scr =  1 }   /* ~10.7MHz */
+};
+
 /**
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           1
-#define SPI_0_EN            1
-
-static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
+static const spi_conf_t spi_config[] = {
     {
         .dev      = SSI0,
         .mosi_pin = GPIO_PA5,
@@ -120,6 +132,8 @@ static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
         .cs_pin   = GPIO_PA3,
     },
 };
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/pba-d-01-kw2x/include/board.h b/boards/pba-d-01-kw2x/include/board.h
index d29b40bda896558febf002d9fd070f84b0d2409d..2cb1159ac66599c94f3ceca81c7e6e380804b96e 100644
--- a/boards/pba-d-01-kw2x/include/board.h
+++ b/boards/pba-d-01-kw2x/include/board.h
@@ -68,10 +68,10 @@ extern "C"
 @name KW2XRF configuration
 @{
 */
-#define KW2XRF_SPI        (SPI_1)
+#define KW2XRF_SPI        (SPI_DEV(1))
 #define KW2XRF_CS         (GPIO_PIN(KW2XDRF_PORT, KW2XDRF_PCS0_PIN))
 #define KW2XRF_INT        (GPIO_PIN(KW2XDRF_PORT, KW2XDRF_IRQ_PIN))
-#define KW2XRF_SPI_SPEED  (SPI_SPEED_10MHZ)
+#define KW2XRF_SPI_SPEED  (SPI_CLK_10MHZ)
 #define KW2XRF_SHARED_SPI 0
 /** @}*/
 
diff --git a/boards/pba-d-01-kw2x/include/periph_conf.h b/boards/pba-d-01-kw2x/include/periph_conf.h
index bc8de6c30c1223a1f7c3eeee6e3c2cad84bb05c1..c587b9970020ed0f72dd55b02c44f6cf41dbfa9a 100644
--- a/boards/pba-d-01-kw2x/include/periph_conf.h
+++ b/boards/pba-d-01-kw2x/include/periph_conf.h
@@ -163,59 +163,82 @@ static const pwm_conf_t pwm_config[] = {
 
 
 /**
- * @name SPI configuration
+ * @name    SPI device configuration
+ *
+ * Clock configuration values based on the configured 48Mhz module clock.
+ *
+ * Auto-generated by:
+ * cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c
+ *
  * @{
  */
-#define SPI_NUMOF               (2U)
-#define SPI_0_EN                1
-#define SPI_1_EN                1
-#define SPI_IRQ_PRIO            1
-#define KINETIS_SPI_USE_HW_CS   1
-
-/* SPI 0 device config */
-#define SPI_0_DEV               SPI0
-#define SPI_0_INDEX             0
-#define SPI_0_CTAS              0
-#define SPI_0_CLKEN()           (SIM->SCGC6 |= (SIM_SCGC6_SPI0_MASK))
-#define SPI_0_CLKDIS()          (SIM->SCGC6 &= ~(SIM_SCGC6_SPI0_MASK))
-#define SPI_0_IRQ               SPI0_IRQn
-#define SPI_0_IRQ_HANDLER       isr_spi0
-#define SPI_0_FREQ              (48e6)
-
-/* SPI 0 pin configuration */
-#define SPI_0_PORT              PORTC
-#define SPI_0_PORT_CLKEN()      (SIM->SCGC5 |= (SIM_SCGC5_PORTC_MASK))
-#define SPI_0_AF                2
-
-#define SPI_0_PCS0_PIN          4
-#define SPI_0_SCK_PIN           5
-#define SPI_0_SOUT_PIN          6
-#define SPI_0_SIN_PIN           7
-
-#define SPI_0_PCS0_ACTIVE_LOW   1
-
-/* SPI 1 device config */
-#define SPI_1_DEV               SPI1
-#define SPI_1_INDEX             1
-#define SPI_1_CTAS              0
-#define SPI_1_CLKEN()           (SIM->SCGC6 |= (SIM_SCGC6_SPI1_MASK))
-#define SPI_1_CLKDIS()          (SIM->SCGC6 &= ~(SIM_SCGC6_SPI1_MASK))
-#define SPI_1_IRQ               SPI1_IRQn
-#define SPI_1_IRQ_HANDLER       isr_spi1
-#define SPI_1_FREQ              (48e6)
-
-/* SPI 1 pin1configuration */
-#define SPI_1_PORT              KW2XDRF_PORT_DEV
-#define SPI_1_PORT_CLKEN()      KW2XDRF_PORT_CLKEN();
-#define SPI_1_AF                KW2XDRF_PIN_AF
-
-#define SPI_1_PCS0_PIN          KW2XDRF_PCS0_PIN
-#define SPI_1_SCK_PIN           KW2XDRF_SCK_PIN
-#define SPI_1_SOUT_PIN          KW2XDRF_SOUT_PIN
-#define SPI_1_SIN_PIN           KW2XDRF_SIN_PIN
-
-#define SPI_1_PCS0_ACTIVE_LOW   1
+static const uint32_t spi_clk_config[] = {
+    (
+        SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) |          /* -> 93750Hz */
+        SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(8) |
+        SPI_CTAR_PASC(0) | SPI_CTAR_ASC(8) |
+        SPI_CTAR_PDT(0) | SPI_CTAR_DT(8)
+    ),
+    (
+        SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) |          /* -> 375000Hz */
+        SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(6) |
+        SPI_CTAR_PASC(0) | SPI_CTAR_ASC(6) |
+        SPI_CTAR_PDT(0) | SPI_CTAR_DT(6)
+    ),
+    (
+        SPI_CTAR_PBR(1) | SPI_CTAR_BR(4) |          /* -> 1000000Hz */
+        SPI_CTAR_PCSSCK(1) | SPI_CTAR_CSSCK(3) |
+        SPI_CTAR_PASC(1) | SPI_CTAR_ASC(3) |
+        SPI_CTAR_PDT(1) | SPI_CTAR_DT(3)
+    ),
+    (
+        SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) |          /* -> 4800000Hz */
+        SPI_CTAR_PCSSCK(2) | SPI_CTAR_CSSCK(0) |
+        SPI_CTAR_PASC(2) | SPI_CTAR_ASC(0) |
+        SPI_CTAR_PDT(2) | SPI_CTAR_DT(0)
+    ),
+    (
+        SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) |          /* -> 8000000Hz */
+        SPI_CTAR_PCSSCK(1) | SPI_CTAR_CSSCK(0) |
+        SPI_CTAR_PASC(1) | SPI_CTAR_ASC(0) |
+        SPI_CTAR_PDT(1) | SPI_CTAR_DT(0)
+    )
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI0,
+        .pin_miso = GPIO_PIN(PORT_C, 7),
+        .pin_mosi = GPIO_PIN(PORT_C, 6),
+        .pin_clk  = GPIO_PIN(PORT_C, 5),
+        .pin_cs   = {
+            GPIO_PIN(PORT_C, 4),
+            GPIO_UNDEF,
+            GPIO_UNDEF,
+            GPIO_UNDEF,
+            GPIO_UNDEF
+        },
+        .simmask  = SIM_SCGC6_SPI0_MASK,
+        .pcr      = GPIO_AF_2
+    },
+    {
+        .dev      = SPI1,
+        .pin_miso = GPIO_PIN(PORT_B, 17),
+        .pin_mosi = GPIO_PIN(PORT_B, 16),
+        .pin_clk  = GPIO_PIN(PORT_B, 11),
+        .pin_cs   = {
+            GPIO_PIN(PORT_B, 10),
+            GPIO_UNDEF,
+            GPIO_UNDEF,
+            GPIO_UNDEF,
+            GPIO_UNDEF
+        },
+        .simmask  = SIM_SCGC6_SPI1_MASK,
+        .pcr      = GPIO_AF_2
+    }
+};
 
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 
diff --git a/boards/pca10005/include/periph_conf.h b/boards/pca10005/include/periph_conf.h
index de0ebb2cf5a9e3b03c8a62ca1635335f14ea6f9a..09d183d89ed30b79f85e977759a25e2640b90c92 100644
--- a/boards/pca10005/include/periph_conf.h
+++ b/boards/pca10005/include/periph_conf.h
@@ -83,22 +83,22 @@ static const timer_conf_t timer_config[] = {
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-#define SPI_IRQ_PRIO        1
-
-/* SPI_0 device configuration */
-#define SPI_0_DEV           NRF_SPI0
-#define SPI_0_PIN_MOSI      17
-#define SPI_0_PIN_MISO      18
-#define SPI_0_PIN_SCK       19
-
-/* SPI_1 device configuration */
-#define SPI_1_DEV           NRF_SPI1
-#define SPI_1_PIN_MOSI      20
-#define SPI_1_PIN_MISO      21
-#define SPI_1_PIN_SCK       22
+static const spi_conf_t spi_config[] = {
+    {
+        .dev  = NRF_SPI0,
+        .sclk = 19,
+        .mosi = 17,
+        .miso = 18
+    },
+    {
+        .dev  = NRF_SPI1,
+        .sclk = 22,
+        .mosi = 20,
+        .miso = 21
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/remote-common/include/periph_common.h b/boards/remote-common/include/periph_common.h
index 5a018d251937804d5555a52ee3ddce8a1d8d9316..51404de41254b01e4d529198889919f26e9feca5 100644
--- a/boards/remote-common/include/periph_common.h
+++ b/boards/remote-common/include/periph_common.h
@@ -21,7 +21,6 @@
 #ifndef PERIPH_COMMON_H
 #define PERIPH_COMMON_H
 
-#include "cc2538_gpio.h"
 #include "periph_cpu.h"
 
 #ifdef __cplusplus
diff --git a/boards/remote-pa/include/board.h b/boards/remote-pa/include/board.h
index 59ff1d90d1ec944fcdd3e3cce2b476209f76329d..407957515b42cc5e71f693bdbabcc67d95cfe7aa 100644
--- a/boards/remote-pa/include/board.h
+++ b/boards/remote-pa/include/board.h
@@ -24,8 +24,6 @@
 #define BOARD_H
 
 #include "cpu.h"
-#include "periph/gpio.h"
-#include "board_common.h"
 
 #ifdef __cplusplus
  extern "C" {
@@ -74,6 +72,11 @@
 #define RF_SWITCH_TOGGLE    (RF_SWITCH_PORT->DATA ^= (1 << RF_SWITCH_PIN))
 /** @} */
 
+/**
+ * @brief Initialize board specific hardware, including clock, LEDs and std-IO
+ */
+void board_init(void);
+
 #ifdef __cplusplus
 } /* end extern "C" */
 #endif
diff --git a/boards/remote-pa/include/periph_conf.h b/boards/remote-pa/include/periph_conf.h
index ee753928d466a18217f89e3fa087c4844ab13714..d82249a62d9379aadcf8274430fb182f4c186caf 100644
--- a/boards/remote-pa/include/periph_conf.h
+++ b/boards/remote-pa/include/periph_conf.h
@@ -1,10 +1,10 @@
 /*
- * Copyright (C) 2014 Freie Universität Berlin
- * Copyright (C) 2015 Zolertia SL
+ * Copyright (C) 2014-2016 Freie Universität Berlin
+ *               2015 Zolertia SL
  *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
  */
 
 /**
@@ -15,14 +15,12 @@
  * @brief       Peripheral MCU configuration for the Re-Mote board prototype A
  *
  * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- *              Antonio Lignan <alinan@zolertia.com>
+ * @author      Antonio Lignan <alinan@zolertia.com>
  */
 
 #ifndef PERIPH_CONF_H
 #define PERIPH_CONF_H
 
-#include "cc2538_gpio.h"
-#include "periph_cpu.h"
 #include "periph_common.h"
 
 #ifdef __cplusplus
@@ -70,29 +68,43 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = {
 };
 /** @} */
 
+/**
+ * @brief   Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz)
+ *
+ * Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where
+ * 1 < CPSR < 255 and
+ * 0 < SCR  < 256
+ */
+static const spi_clk_conf_t spi_clk_config[] = {
+    { .cpsr = 10, .scr = 31 },  /* 100khz */
+    { .cpsr =  2, .scr = 39 },  /* 400khz */
+    { .cpsr =  2, .scr = 15 },  /* 1MHz */
+    { .cpsr =  2, .scr =  2 },  /* ~4.5MHz */
+    { .cpsr =  2, .scr =  1 }   /* ~10.7MHz */
+};
+
 /**
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           2
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-
-static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
+static const spi_conf_t spi_config[] = {
     {
         .dev      = SSI0,
         .mosi_pin = GPIO_PD0,
         .miso_pin = GPIO_PC4,
         .sck_pin  = GPIO_PD1,
-        .cs_pin   = GPIO_PD3,
+        .cs_pin   = GPIO_PD3
     },
     {
         .dev      = SSI1,
         .mosi_pin = GPIO_PC7,
         .miso_pin = GPIO_PA4,
         .sck_pin  = GPIO_PB5,
-    },
+        .cs_pin   = GPIO_UNDEF
+    }
 };
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/remote-reva/include/board.h b/boards/remote-reva/include/board.h
index b93dd9f8f5e825b35c5bf364b012de7d46f59f8e..637206258d11689e7d65423a01af78bc58e2b816 100644
--- a/boards/remote-reva/include/board.h
+++ b/boards/remote-reva/include/board.h
@@ -23,9 +23,6 @@
 #define BOARD_H
 
 #include "cpu.h"
-#include "periph/gpio.h"
-#include "periph/spi.h"
-#include "board_common.h"
 
 #ifdef __cplusplus
  extern "C" {
@@ -111,6 +108,11 @@
 #define CC1200_GPD2_GPIO    GPIO_PB0
 /** @} */
 
+/**
+ * @brief Initialize board specific hardware, including clock, LEDs and std-IO
+ */
+void board_init(void);
+
 #ifdef __cplusplus
 } /* end extern "C" */
 #endif
diff --git a/boards/remote-reva/include/periph_conf.h b/boards/remote-reva/include/periph_conf.h
index 2dfd7b1b2ef29a089e3928b4b703f45ca7cf3a02..6ccb84f87fcf5c403870f883a73238ee3a601742 100644
--- a/boards/remote-reva/include/periph_conf.h
+++ b/boards/remote-reva/include/periph_conf.h
@@ -1,10 +1,10 @@
 /*
- * Copyright (C) 2014 Freie Universität Berlin
- * Copyright (C) 2015 Zolertia SL
+ * Copyright (C) 2014-2016 Freie Universität Berlin
+ *               2015 Zolertia SL
  *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
  */
 
 /**
@@ -15,14 +15,12 @@
  * @brief       Peripheral MCU configuration for the RE-Mote board revision A
  *
  * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- *              Antonio Lignan <alinan@zolertia.com>
+ * @author      Antonio Lignan <alinan@zolertia.com>
  */
 
 #ifndef PERIPH_CONF_H
 #define PERIPH_CONF_H
 
-#include "cc2538_gpio.h"
-#include "periph_cpu.h"
 #include "periph_common.h"
 
 #ifdef __cplusplus
@@ -70,30 +68,43 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = {
 };
 /** @} */
 
+/**
+ * @brief   Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz)
+ *
+ * Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where
+ * 1 < CPSR < 255 and
+ * 0 < SCR  < 256
+ */
+static const spi_clk_conf_t spi_clk_config[] = {
+    { .cpsr = 10, .scr = 31 },  /* 100khz */
+    { .cpsr =  2, .scr = 39 },  /* 400khz */
+    { .cpsr =  2, .scr = 15 },  /* 1MHz */
+    { .cpsr =  2, .scr =  2 },  /* ~4.5MHz */
+    { .cpsr =  2, .scr =  1 }   /* ~10.7MHz */
+};
+
 /**
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           2
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-
-static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
+static const spi_conf_t spi_config[] = {
     {
         .dev      = SSI0,
         .mosi_pin = GPIO_PB1,
         .miso_pin = GPIO_PB3,
         .sck_pin  = GPIO_PB2,
-        .cs_pin   = GPIO_PB5,
+        .cs_pin   = GPIO_PB5
     },
     {
         .dev      = SSI1,
         .mosi_pin = GPIO_PC5,
         .miso_pin = GPIO_PC6,
         .sck_pin  = GPIO_PC4,
-        .cs_pin   = GPIO_PA7,
-    },
+        .cs_pin   = GPIO_PA7
+    }
 };
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/remote-revb/include/board.h b/boards/remote-revb/include/board.h
index 7e1e212e99c341a889a24794b4bebdb06ee06c07..6d1eb842a853e70e02ddfca595117a2083574f34 100644
--- a/boards/remote-revb/include/board.h
+++ b/boards/remote-revb/include/board.h
@@ -23,9 +23,6 @@
 #define BOARD_H
 
 #include "cpu.h"
-#include "periph/gpio.h"
-#include "periph/spi.h"
-#include "board_common.h"
 
 #ifdef __cplusplus
  extern "C" {
@@ -114,7 +111,7 @@
  * @name Onboard micro-sd slot pin definitions
  * @{
  */
-#define SDCARD_SPI_PARAM_SPI       SPI_1
+#define SDCARD_SPI_PARAM_SPI       SPI_DEV(1)
 #define SDCARD_SPI_PARAM_CS        GPIO_PIN(0,7)
 #define SDCARD_SPI_PARAM_CLK       GPIO_PIN(2,4)
 #define SDCARD_SPI_PARAM_MOSI      GPIO_PIN(2,5)
@@ -123,6 +120,11 @@
 #define SDCARD_SPI_PARAM_POWER_AH  false
 /** @} */
 
+/**
+ * @brief Initialize board specific hardware, including clock, LEDs and std-IO
+ */
+void board_init(void);
+
 #ifdef __cplusplus
 } /* end extern "C" */
 #endif
diff --git a/boards/remote-revb/include/periph_conf.h b/boards/remote-revb/include/periph_conf.h
index 4890135cce8a012495721aa62c869e8e08608abc..a4269867ae7ceb634b5468d4500aa0fc050918a1 100644
--- a/boards/remote-revb/include/periph_conf.h
+++ b/boards/remote-revb/include/periph_conf.h
@@ -70,30 +70,43 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = {
 };
 /** @} */
 
+/**
+ * @brief   Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz)
+ *
+ * Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where
+ * 1 < CPSR < 255 and
+ * 0 < SCR  < 256
+ */
+static const spi_clk_conf_t spi_clk_config[] = {
+    { .cpsr = 10, .scr = 31 },  /* 100khz */
+    { .cpsr =  2, .scr = 39 },  /* 400khz */
+    { .cpsr =  2, .scr = 15 },  /* 1MHz */
+    { .cpsr =  2, .scr =  2 },  /* ~4.5MHz */
+    { .cpsr =  2, .scr =  1 }   /* ~10.7MHz */
+};
+
 /**
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           2
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-
-static const periph_spi_conf_t spi_config[SPI_NUMOF] = {
+static const spi_conf_t spi_config[] = {
     {
         .dev      = SSI0,
         .mosi_pin = GPIO_PB1,
         .miso_pin = GPIO_PB3,
         .sck_pin  = GPIO_PB2,
-        .cs_pin   = GPIO_PB5,
+        .cs_pin   = GPIO_PB5
     },
     {
         .dev      = SSI1,
         .mosi_pin = GPIO_PC5,
         .miso_pin = GPIO_PC6,
         .sck_pin  = GPIO_PC4,
-        .cs_pin   = GPIO_PA7,
-    },
+        .cs_pin   = GPIO_PA7
+    }
 };
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/saml21-xpro/include/periph_conf.h b/boards/saml21-xpro/include/periph_conf.h
index aedcae7c999e167746c9912db583b35ecfae89ba..b4d2d2d0447b4c020a7e1db6eef253c31dbcb49c 100644
--- a/boards/saml21-xpro/include/periph_conf.h
+++ b/boards/saml21-xpro/include/periph_conf.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
  *               2015 FreshTemp, LLC.
- *               2014 Freie Universität Berlin
+ *               2014-2016 Freie Universität Berlin
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License v2.1. See the file LICENSE in the top level
@@ -16,12 +16,15 @@
  * @brief       Peripheral MCU configuration for the Atmel SAM L21 Xplained Pro board
  *
  * @author      Thomas Eichinger <thomas.eichinger@fu-berlin.de>
- * @autor       Kaspar Schleiser <kaspar@schleiser.de>
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  */
 
 #ifndef PERIPH_CONF_H
 #define PERIPH_CONF_H
 
+#include "periph_cpu.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -29,7 +32,7 @@ extern "C" {
 /**
  * @brief GCLK reference speed
  */
-#define GCLK_REF (16000000U)
+#define CLOCK_CORECLOCK     (16000000U)
 
 /**
  * @name Timer peripheral configuration
@@ -71,8 +74,22 @@ extern "C" {
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF          (1)
-#define SPI_0_EN           1
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = &(SERCOM0->SPI),
+        .miso_pin = GPIO_PIN(PA, 4),
+        .mosi_pin = GPIO_PIN(PA, 6),
+        .clk_pin  = GPIO_PIN(PA, 7),
+        .miso_mux = GPIO_MUX_D,
+        .mosi_mux = GPIO_MUX_D,
+        .clk_mux  = GPIO_MUX_D,
+        .miso_pad = SPI_PAD_MISO_0,
+        .mosi_pad = SPI_PAD_MOSI_2_SCK_3
+
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/samr21-xpro/include/board.h b/boards/samr21-xpro/include/board.h
index 418a4f726d76e28c682d9a573dc646da75f81065..373cb35e3461ef0678d89e7766c7b141e5b2da19 100644
--- a/boards/samr21-xpro/include/board.h
+++ b/boards/samr21-xpro/include/board.h
@@ -43,8 +43,8 @@ extern "C" {
  *
  * {spi bus, spi speed, cs pin, int pin, reset pin, sleep pin}
  */
-#define AT86RF2XX_PARAMS_BOARD      {.spi = SPI_0, \
-                                     .spi_speed = SPI_SPEED_5MHZ, \
+#define AT86RF2XX_PARAMS_BOARD      {.spi = SPI_DEV(0), \
+                                     .spi_clk = SPI_CLK_5MHZ, \
                                      .cs_pin = GPIO_PIN(PB, 31), \
                                      .int_pin = GPIO_PIN(PB, 0), \
                                      .sleep_pin = GPIO_PIN(PA, 20), \
diff --git a/boards/samr21-xpro/include/periph_conf.h b/boards/samr21-xpro/include/periph_conf.h
index 9834707849c3d8c196a17655d1b1e53dfc9b4b77..29f47cd2cd1f204d72d5a4c6e5e87c09cc298552 100644
--- a/boards/samr21-xpro/include/periph_conf.h
+++ b/boards/samr21-xpro/include/periph_conf.h
@@ -168,37 +168,32 @@ static const pwm_conf_t pwm_config[] = {
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF          (2)
-#define SPI_0_EN           1
-#define SPI_1_EN           1
-
-/*      SPI0             */
-#define SPI_0_DEV           SERCOM4->SPI
-#define SPI_IRQ_0           SERCOM4_IRQn
-#define SPI_0_GCLK_ID       SERCOM4_GCLK_ID_CORE
-/* SPI 0 pin configuration */
-#define SPI_0_SCLK          GPIO_PIN(PC, 18)
-#define SPI_0_SCLK_MUX      GPIO_MUX_F
-#define SPI_0_MISO          GPIO_PIN(PC, 19)
-#define SPI_0_MISO_MUX      GPIO_MUX_F
-#define SPI_0_MISO_PAD      SPI_PAD_MISO_0
-#define SPI_0_MOSI          GPIO_PIN(PB, 30)
-#define SPI_0_MOSI_MUX      GPIO_MUX_F
-#define SPI_0_MOSI_PAD      SPI_PAD_MOSI_2_SCK_3
-
-/*      SPI1             */
-#define SPI_1_DEV           SERCOM5->SPI
-#define SPI_IRQ_1           SERCOM5_IRQn
-#define SPI_1_GCLK_ID       SERCOM5_GCLK_ID_CORE
-/* SPI 1 pin configuration */
-#define SPI_1_SCLK          GPIO_PIN(PB, 23)
-#define SPI_1_SCLK_MUX      GPIO_MUX_D
-#define SPI_1_MISO          GPIO_PIN(PB, 02)
-#define SPI_1_MISO_MUX      GPIO_MUX_D
-#define SPI_1_MISO_PAD      SPI_PAD_MISO_0
-#define SPI_1_MOSI          GPIO_PIN(PB, 22)
-#define SPI_1_MOSI_MUX      GPIO_MUX_D
-#define SPI_1_MOSI_PAD      SPI_PAD_MOSI_2_SCK_3
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = &SERCOM4->SPI,
+        .miso_pin = GPIO_PIN(PC, 19),
+        .mosi_pin = GPIO_PIN(PB, 30),
+        .clk_pin  = GPIO_PIN(PC, 18),
+        .miso_mux = GPIO_MUX_F,
+        .mosi_mux = GPIO_MUX_F,
+        .clk_mux  = GPIO_MUX_F,
+        .miso_pad = SPI_PAD_MISO_0,
+        .mosi_pad = SPI_PAD_MOSI_2_SCK_3
+    },
+    {
+        .dev      = &SERCOM5->SPI,
+        .miso_pin = GPIO_PIN(PB, 2),
+        .mosi_pin = GPIO_PIN(PB, 22),
+        .clk_pin  = GPIO_PIN(PB, 23),
+        .miso_mux = GPIO_MUX_D,
+        .mosi_mux = GPIO_MUX_D,
+        .clk_mux  = GPIO_MUX_D,
+        .miso_pad = SPI_PAD_MISO_0,
+        .mosi_pad = SPI_PAD_MOSI_2_SCK_3
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/sodaq-autonomo/include/periph_conf.h b/boards/sodaq-autonomo/include/periph_conf.h
index a5793881e1d6ab5978264d61c6c40924c868db84..456196ef0d5a2592965dc55e8fb8ad101ad1e6fa 100644
--- a/boards/sodaq-autonomo/include/periph_conf.h
+++ b/boards/sodaq-autonomo/include/periph_conf.h
@@ -133,7 +133,7 @@ static const uart_conf_t uart_config[] = {
         .mux    = GPIO_MUX_C,
         .rx_pad = UART_PAD_RX_1,
         .tx_pad = UART_PAD_TX_2,
-    },
+    }
 };
 
 /* interrupt function name mapping */
@@ -184,27 +184,21 @@ static const pwm_conf_t pwm_config[] = {
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           (1)
-#define SPI_0_EN            1
-#define SPI_1_EN            0
-
-/*      SPI0             */
-#define SPI_0_DEV           SERCOM3->SPI
-#define SPI_IRQ_0           SERCOM3_IRQn
-#define SPI_0_GCLK_ID       SERCOM3_GCLK_ID_CORE
-/* SPI 0 pin configuration */
-#define SPI_0_SCLK          GPIO_PIN(PA, 21)
-#define SPI_0_SCLK_MUX      GPIO_MUX_D
-#define SPI_0_MISO          GPIO_PIN(PA, 22)
-#define SPI_0_MISO_MUX      GPIO_MUX_C
-#define SPI_0_MISO_PAD      SPI_PAD_MISO_0
-#define SPI_0_MOSI          GPIO_PIN(PA, 20)
-#define SPI_0_MOSI_MUX      GPIO_MUX_D
-#define SPI_0_MOSI_PAD      SPI_PAD_MOSI_2_SCK_3
-
-// How/where do we define SS?
-#define SPI_0_SS            GPIO_PIN(PA, 23)
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = &SERCOM3->SPI,
+        .miso_pin = GPIO_PIN(PA, 22),
+        .mosi_pin = GPIO_PIN(PA, 20),
+        .clk_pin  = GPIO_PIN(PA, 21),
+        .miso_mux = GPIO_MUX_C,
+        .mosi_mux = GPIO_MUX_D,
+        .clk_mux  = GPIO_MUX_D,
+        .miso_pad = SPI_PAD_MISO_0,
+        .mosi_pad = SPI_PAD_MOSI_2_SCK_3,
+    },
+};
 
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/spark-core/Makefile.features b/boards/spark-core/Makefile.features
index 1442fd8e7ed0b10ae5a0a486e4632e0b3aed2a4e..3de96ca4b3451ac7f228e0f259c6127f5c3e9dd0 100644
--- a/boards/spark-core/Makefile.features
+++ b/boards/spark-core/Makefile.features
@@ -1,6 +1,7 @@
 # Put defined MCU peripherals here (in alphabetical order)
 FEATURES_PROVIDED += periph_gpio
 FEATURES_PROVIDED += periph_timer
+FEATURES_PROVIDED += periph_spi
 FEATURES_PROVIDED += periph_uart
 
 # Various other features (if any)
diff --git a/boards/spark-core/include/board.h b/boards/spark-core/include/board.h
index 0d46ed3e5d6b118281b438738eab90d6a0d33772..6b9bae98d3b1fffc202f4e65a560dcd3e53385fe 100644
--- a/boards/spark-core/include/board.h
+++ b/boards/spark-core/include/board.h
@@ -81,7 +81,7 @@
  * @name CC3000 pin configuration
  * @{
  */
-#define CC3000_SPI          SPI_0
+#define CC3000_SPI          SPI_DEV(0)
 #define CC3000_CS           GPIO_PIN(PORT_B,12)
 #define CC3000_EN           GPIO_PIN(PORT_B,8)
 #define CC3000_INT          GPIO_PIN(PORT_B,11)
@@ -91,7 +91,7 @@
  * @name EXTFLASH pin configuration
  * @{
  */
-#define EXTFLASH_SPI        SPI_0
+#define EXTFLASH_SPI        SPI_DEV(0)
 #define EXTFLASH            GPIO_PIN(PORT_B,9)
 /** @} */
 
diff --git a/boards/spark-core/include/periph_conf.h b/boards/spark-core/include/periph_conf.h
index 77697481e373c34824398c328525e8ce33d39a22..28432466354b5df1366d550eb8421a6c143b8c52 100644
--- a/boards/spark-core/include/periph_conf.h
+++ b/boards/spark-core/include/periph_conf.h
@@ -106,21 +106,42 @@ static const uart_conf_t uart_config[] = {
 /** @} */
 
 /**
- * @brief SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF           (1U)
-#define SPI_0_EN            1
-
-/* SPI 0 device configuration */
-#define SPI_0_DEV           SPI1
-#define SPI_0_CLKEN()       (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()      (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_BUS_DIV       0   /* 1 -> SPI runs with full CPU clock, 0 -> half CPU clock */
-/* SPI 0 pin configuration */
-#define SPI_0_CLK_PIN       GPIO_PIN(PORT_B,15)
-#define SPI_0_MOSI_PIN      GPIO_PIN(PORT_B,17)
-#define SPI_0_MISO_PIN      GPIO_PIN(PORT_B,16)
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 36000000Hz */
+        7,  /* -> 140625Hz */
+        6,  /* -> 281250Hz */
+        4,  /* -> 1125000Hz */
+        2,  /* -> 4500000Hz */
+        1   /* -> 9000000Hz */
+    },
+    {       /* for APB2 @ 72000000Hz */
+        7,  /* -> 281250Hz */
+        7,  /* -> 281250Hz */
+        5,  /* -> 1125000Hz */
+        3,  /* -> 4500000Hz */
+        2   /* -> 9000000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_B, 17),
+        .miso_pin = GPIO_PIN(PORT_B, 16),
+        .sclk_pin = GPIO_PIN(PORT_B, 15),
+        .cs_pin   = GPIO_UNDEF,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/stm32f0discovery/include/periph_conf.h b/boards/stm32f0discovery/include/periph_conf.h
index cb2f3c72e0c4e1782eacbe338ea78da9cc84800c..5b277917695be6a743833aab2e3fa2fa47a2aadd 100644
--- a/boards/stm32f0discovery/include/periph_conf.h
+++ b/boards/stm32f0discovery/include/periph_conf.h
@@ -123,38 +123,47 @@ static const uart_conf_t uart_config[] = {
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-#define SPI_IRQ_PRIO        1
-
-/* SPI 0 device config */
-#define SPI_0_DEV           SPI1
-#define SPI_0_CLKEN()       (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()      (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_IRQ           SPI1_IRQn
-#define SPI_0_ISR           isr_spi1
-/* SPI 1 pin configuration */
-#define SPI_0_PORT          GPIOA
-#define SPI_0_PORT_CLKEN()  (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
-#define SPI_0_PIN_SCK       5
-#define SPI_0_PIN_MISO      6
-#define SPI_0_PIN_MOSI      7
-#define SPI_0_PIN_AF        0
-
-/* SPI 1 device config */
-#define SPI_1_DEV           SPI2
-#define SPI_1_CLKEN()       (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_1_CLKDIS()      (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_1_IRQ           SPI2_IRQn
-#define SPI_1_ISR           isr_spi2
-/* SPI 1 pin configuration */
-#define SPI_1_PORT          GPIOB
-#define SPI_1_PORT_CLKEN()  (periph_clk_en(AHB, RCC_AHBENR_GPIOBEN))
-#define SPI_1_PIN_SCK       13
-#define SPI_1_PIN_MISO      14
-#define SPI_1_PIN_MOSI      15
-#define SPI_1_PIN_AF        0
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 48000000Hz */
+        7,  /* -> 187500Hz */
+        6,  /* -> 375000Hz */
+        5,  /* -> 750000Hz */
+        2,  /* -> 6000000Hz */
+        1   /* -> 12000000Hz */
+    },
+    {       /* for APB2 @ 48000000Hz */
+        7,  /* -> 187500Hz */
+        6,  /* -> 375000Hz */
+        5,  /* -> 750000Hz */
+        2,  /* -> 6000000Hz */
+        1   /* -> 12000000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_UNDEF,
+        .af       = GPIO_AF0,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    },
+    {
+        .dev      = SPI2,
+        .mosi_pin = GPIO_PIN(PORT_B, 15),
+        .miso_pin = GPIO_PIN(PORT_B, 14),
+        .sclk_pin = GPIO_PIN(PORT_B, 13),
+        .cs_pin   = GPIO_UNDEF,
+        .af       = GPIO_AF0,
+        .rccmask  = RCC_APB1ENR_SPI2EN,
+        .apbbus   = APB1
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/stm32f3discovery/include/periph_conf.h b/boards/stm32f3discovery/include/periph_conf.h
index fda093ae63c274cdaed4a2c58869936d6229f6ec..cf658a87e9ba9a66e06868a631042644e8dcb5d4 100644
--- a/boards/stm32f3discovery/include/periph_conf.h
+++ b/boards/stm32f3discovery/include/periph_conf.h
@@ -153,50 +153,47 @@ static const pwm_conf_t pwm_config[] = {
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-#define SPI_IRQ_PRIO        1
-
-/* SPI 0 device config */
-#define SPI_0_DEV               SPI1
-#define SPI_0_CLKEN()           (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()          (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_IRQ               SPI1_IRQn
-#define SPI_0_IRQ_HANDLER       isr_spi1
-/* SPI 0 pin configuration */
-#define SPI_0_SCK_PORT          GPIOA
-#define SPI_0_SCK_PIN           5
-#define SPI_0_SCK_AF            5
-#define SPI_0_SCK_PORT_CLKEN()  (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
-#define SPI_0_MISO_PORT         GPIOA
-#define SPI_0_MISO_PIN          6
-#define SPI_0_MISO_AF           5
-#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
-#define SPI_0_MOSI_PORT         GPIOA
-#define SPI_0_MOSI_PIN          7
-#define SPI_0_MOSI_AF           5
-#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN))
-
-/* SPI 1 device config */
-#define SPI_1_DEV               SPI3
-#define SPI_1_CLKEN()           (periph_clk_en(APB1, RCC_APB1ENR_SPI3EN))
-#define SPI_1_CLKDIS()          (periph_clk_dis(APB1, RCC_APB1ENR_SPI3EN))
-#define SPI_1_IRQ               SPI3_IRQn
-#define SPI_1_IRQ_HANDLER       isr_spi3
-/* SPI 1 pin configuration */
-#define SPI_1_SCK_PORT          GPIOC
-#define SPI_1_SCK_PIN           10
-#define SPI_1_SCK_AF            6
-#define SPI_1_SCK_PORT_CLKEN()  (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN))
-#define SPI_1_MISO_PORT         GPIOC
-#define SPI_1_MISO_PIN          11
-#define SPI_1_MISO_AF           6
-#define SPI_1_MISO_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN))
-#define SPI_1_MOSI_PORT         GPIOC
-#define SPI_1_MOSI_PIN          12
-#define SPI_1_MOSI_AF           6
-#define SPI_1_MOSI_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN))
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 36000000Hz */
+        7,  /* -> 140625Hz */
+        6,  /* -> 281250Hz */
+        4,  /* -> 1125000Hz */
+        2,  /* -> 4500000Hz */
+        1   /* -> 9000000Hz */
+    },
+    {       /* for APB2 @ 72000000Hz */
+        7,  /* -> 281250Hz */
+        7,  /* -> 281250Hz */
+        5,  /* -> 1125000Hz */
+        3,  /* -> 4500000Hz */
+        2   /* -> 9000000Hz */
+    }
+};
+
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_UNDEF,
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    },
+    {
+        .dev      = SPI3,
+        .mosi_pin = GPIO_PIN(PORT_C, 12),
+        .miso_pin = GPIO_PIN(PORT_C, 11),
+        .sclk_pin = GPIO_PIN(PORT_C, 10),
+        .cs_pin   = GPIO_PIN(PORT_A, 15),
+        .af       = GPIO_AF6,
+        .rccmask  = RCC_APB1ENR_SPI3EN,
+        .apbbus   = APB1
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/stm32f4discovery/include/periph_conf.h b/boards/stm32f4discovery/include/periph_conf.h
index 0263c03ee1c9012f6ed98daf8e73c6a4447dda72..a41819bc54c60b5393c2e87fe3b8075ef161108f 100644
--- a/boards/stm32f4discovery/include/periph_conf.h
+++ b/boards/stm32f4discovery/include/periph_conf.h
@@ -182,55 +182,53 @@ static const pwm_conf_t pwm_config[] = {
 /** @} */
 
 /**
- * @name SPI configuration
+ * @brief   SPI configuration
+ *
+ * @note    The spi_divtable is auto-generated from
+ *          `cpu/stm32_common/dist/spi_divtable/spi_divtable.c`
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-#define SPI_IRQ_PRIO        1
+static const uint8_t spi_divtable[2][5] = {
+    {       /* for APB1 @ 42000000Hz */
+        7,  /* -> 164062Hz */
+        6,  /* -> 328125Hz */
+        4,  /* -> 1312500Hz */
+        2,  /* -> 5250000Hz */
+        1   /* -> 10500000Hz */
+    },
+    {       /* for APB2 @ 84000000Hz */
+        7,  /* -> 328125Hz */
+        7,  /* -> 328125Hz */
+        5,  /* -> 1312500Hz */
+        3,  /* -> 5250000Hz */
+        2   /* -> 10500000Hz */
+    }
+};
 
-/* SPI 0 device config */
-#define SPI_0_DEV               SPI1
-#define SPI_0_CLKEN()           (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_CLKDIS()          (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN))
-#define SPI_0_BUS_DIV           1   /* 1 -> SPI runs with half CPU clock, 0 -> quarter CPU clock */
-#define SPI_0_IRQ               SPI1_IRQn
-#define SPI_0_IRQ_HANDLER       isr_spi1
-/* SPI 0 pin configuration */
-#define SPI_0_SCK_PORT          GPIOA
-#define SPI_0_SCK_PIN           5
-#define SPI_0_SCK_AF            5
-#define SPI_0_SCK_PORT_CLKEN()  (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
-#define SPI_0_MISO_PORT         GPIOA
-#define SPI_0_MISO_PIN          6
-#define SPI_0_MISO_AF           5
-#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
-#define SPI_0_MOSI_PORT         GPIOA
-#define SPI_0_MOSI_PIN          7
-#define SPI_0_MOSI_AF           5
-#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN))
+static const spi_conf_t spi_config[] = {
+    {
+        .dev      = SPI1,
+        .mosi_pin = GPIO_PIN(PORT_A, 7),
+        .miso_pin = GPIO_PIN(PORT_A, 6),
+        .sclk_pin = GPIO_PIN(PORT_A, 5),
+        .cs_pin   = GPIO_PIN(PORT_A, 4),
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB2ENR_SPI1EN,
+        .apbbus   = APB2
+    },
+    {
+        .dev      = SPI2,
+        .mosi_pin = GPIO_PIN(PORT_B, 15),
+        .miso_pin = GPIO_PIN(PORT_B, 14),
+        .sclk_pin = GPIO_PIN(PORT_B, 13),
+        .cs_pin   = GPIO_PIN(PORT_B, 12),
+        .af       = GPIO_AF5,
+        .rccmask  = RCC_APB1ENR_SPI2EN,
+        .apbbus   = APB1
+    }
+};
 
-/* SPI 1 device config */
-#define SPI_1_DEV               SPI2
-#define SPI_1_CLKEN()           (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_1_CLKDIS()          (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN))
-#define SPI_1_BUS_DIV           0   /* 1 -> SPI runs with half CPU clock, 0 -> quarter CPU clock */
-#define SPI_1_IRQ               SPI2_IRQn
-#define SPI_1_IRQ_HANDLER       isr_spi2
-/* SPI 1 pin configuration */
-#define SPI_1_SCK_PORT          GPIOB
-#define SPI_1_SCK_PIN           13
-#define SPI_1_SCK_AF            5
-#define SPI_1_SCK_PORT_CLKEN()  (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN))
-#define SPI_1_MISO_PORT         GPIOB
-#define SPI_1_MISO_PIN          14
-#define SPI_1_MISO_AF           5
-#define SPI_1_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN))
-#define SPI_1_MOSI_PORT         GPIOB
-#define SPI_1_MOSI_PIN          15
-#define SPI_1_MOSI_AF           5
-#define SPI_1_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN))
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/telosb/include/board.h b/boards/telosb/include/board.h
index b84ffc2ab8c8cf5ed11a6d7a0f01c11774896947..4e700d9779e00e26d6b0347480f6e431b83000a6 100644
--- a/boards/telosb/include/board.h
+++ b/boards/telosb/include/board.h
@@ -102,8 +102,8 @@ extern "C" {
 /**
  * @brief   Definition of the interface to the CC2420 radio
  */
-#define CC2420_PARAMS_BOARD   {.spi        = SPI_0, \
-                               .spi_clk    = SPI_SPEED_1MHZ , \
+#define CC2420_PARAMS_BOARD   {.spi        = SPI_DEV(0), \
+                               .spi_clk    = SPI_CLK_1MHZ , \
                                .pin_cs     = GPIO_PIN(P4, 2), \
                                .pin_fifo   = GPIO_PIN(P1, 3), \
                                .pin_fifop  = GPIO_PIN(P1, 0), \
diff --git a/boards/telosb/include/periph_conf.h b/boards/telosb/include/periph_conf.h
index d684542de133b1aa0450d975e763de886e0352ab..e86752e6a3b1e993f596e76cb1b644d6f5273330 100644
--- a/boards/telosb/include/periph_conf.h
+++ b/boards/telosb/include/periph_conf.h
@@ -75,7 +75,7 @@ extern "C" {
 #define SPI_0_EN            (1U)
 
 /* SPI configuration */
-#define SPI_DEV             (USART_0)
+#define SPI_BASE            (USART_0)
 #define SPI_IE              (SFR->IE1)
 #define SPI_IF              (SFR->IFG1)
 #define SPI_IE_RX_BIT       (1 << 6)
diff --git a/boards/udoo/include/periph_conf.h b/boards/udoo/include/periph_conf.h
index 1514e2d143899169a3e0cdcaad2fe7f7e6ecd6af..d9a729ece450aa98a40ca9343bb1cf70c4593ccb 100644
--- a/boards/udoo/include/periph_conf.h
+++ b/boards/udoo/include/periph_conf.h
@@ -86,29 +86,18 @@ static const uart_conf_t uart_config[] = {
 * @name SPI configuration
 * @{
 */
-#define SPI_NUMOF           (1U)
-#define SPI_0_EN            1
-
-/* SPI 0 device config */
-#define SPI_0_DEV           SPI0
-#define SPI_0_CLKEN()       (PMC->PMC_PCER0 |= (1 << ID_SPI0));
-#define SPI_0_CLKDIS()      (PMC->PMC_PCER0 &= ~(1 << ID_SPI0));
-#define SPI_0_IRQ           SPI0_IRQn
-#define SPI_0_IRQ_HANDLER   isr_spi0
-#define SPI_0_IRQ_PRIO      1
-
-/* SPI 0 pin configuration */
-#define SPI_0_MISO_PIN      PIO_PA25A_SPI0_MISO
-#define SPI_0_MOSI_PIN      PIO_PA26A_SPI0_MOSI
-#define SPI_0_SCK_PIN       PIO_PA27A_SPI0_SPCK
-
-#define SPI_0_MISO_PORT     PIOA
-#define SPI_0_MOSI_PORT     PIOA
-#define SPI_0_SCK_PORT      PIOA
-
-#define SPI_0_MISO_PORT_CLKEN()  (PMC->PMC_PCER0 |= (1 << ID_PIOA));
-#define SPI_0_MOSI_PORT_CLKEN()  (PMC->PMC_PCER0 |= (1 << ID_PIOA));
-#define SPI_0_SCK_PORT_CLKEN()   (PMC->PMC_PCER0 |= (1 << ID_PIOA));
+static const spi_conf_t spi_config[] = {
+    {
+        .dev   = SPI0,
+        .id    = ID_SPI0,
+        .clk   = GPIO_PIN(PA, 25),
+        .mosi  = GPIO_PIN(PA, 26),
+        .miso  = GPIO_PIN(PA, 27),
+        .mux   = GPIO_MUX_A
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 #ifdef __cplusplus
diff --git a/boards/weio/include/periph_conf.h b/boards/weio/include/periph_conf.h
index 8eff676a5f52a738b9498dd30d2faae003bc3642..597ceee93a41fa852d27948549d5b6c3c3a5964b 100644
--- a/boards/weio/include/periph_conf.h
+++ b/boards/weio/include/periph_conf.h
@@ -81,9 +81,20 @@ extern "C" {
  * @brief SPI configuration
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            1
+static const spi_conf_t spi_config[] = {
+    {
+        .dev        = LPC_SSP0,
+        .preset_bit = (1 << 0),
+        .ahb_bit    = (1 << 11)
+    },
+    {
+        .dev        = LPC_SSP1,
+        .preset_bit = (1 << 2),
+        .ahb_bit    = (1 << 18)
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /* @} */
 
 /**
diff --git a/boards/wsn430-common/include/periph_conf.h b/boards/wsn430-common/include/periph_conf.h
index 80aed6f41c705d631927e98fc75bee3927d8b993..0ad41ec7a91319497433ee72e3a0032b45f414cf 100644
--- a/boards/wsn430-common/include/periph_conf.h
+++ b/boards/wsn430-common/include/periph_conf.h
@@ -75,7 +75,7 @@ extern "C" {
 #define SPI_0_EN            (1U)
 
 /* SPI configuration */
-#define SPI_DEV             (USART_0)
+#define SPI_BASE            (USART_0)
 #define SPI_IE              (SFR->IE1)
 #define SPI_IF              (SFR->IFG1)
 #define SPI_IE_RX_BIT       (1 << 6)
diff --git a/boards/wsn430-v1_3b/Makefile.features b/boards/wsn430-v1_3b/Makefile.features
index 8c46a99149b8bb0fd42da0789000883409c3c31b..c3dad712131c133cfbcde0040068e8813e9f3420 100644
--- a/boards/wsn430-v1_3b/Makefile.features
+++ b/boards/wsn430-v1_3b/Makefile.features
@@ -1,6 +1,7 @@
 # Put defined MCU peripherals here (in alphabetical order)
 FEATURES_PROVIDED += periph_gpio
 FEATURES_PROVIDED += periph_timer
+FEATURES_PROVIDED += periph_spi
 FEATURES_PROVIDED += periph_uart
 
 # Various other features (if any)
diff --git a/boards/wsn430-v1_4/Makefile.features b/boards/wsn430-v1_4/Makefile.features
index 8c46a99149b8bb0fd42da0789000883409c3c31b..c3dad712131c133cfbcde0040068e8813e9f3420 100644
--- a/boards/wsn430-v1_4/Makefile.features
+++ b/boards/wsn430-v1_4/Makefile.features
@@ -1,6 +1,7 @@
 # Put defined MCU peripherals here (in alphabetical order)
 FEATURES_PROVIDED += periph_gpio
 FEATURES_PROVIDED += periph_timer
+FEATURES_PROVIDED += periph_spi
 FEATURES_PROVIDED += periph_uart
 
 # Various other features (if any)
diff --git a/boards/yunjia-nrf51822/include/periph_conf.h b/boards/yunjia-nrf51822/include/periph_conf.h
index 2e67cc9b36e594284dd401f77c405722d2416a1e..ae07c27b1b5964dc8433b89fe40fd5f2c6e9fcb2 100644
--- a/boards/yunjia-nrf51822/include/periph_conf.h
+++ b/boards/yunjia-nrf51822/include/periph_conf.h
@@ -81,22 +81,22 @@ static const timer_conf_t timer_config[] = {
  * @name SPI configuration
  * @{
  */
-#define SPI_NUMOF           (2U)
-#define SPI_0_EN            1
-#define SPI_1_EN            1
-#define SPI_IRQ_PRIO        1
-
-/* SPI_0 device configuration */
-#define SPI_0_DEV           NRF_SPI0
-#define SPI_0_PIN_MOSI      17
-#define SPI_0_PIN_MISO      18
-#define SPI_0_PIN_SCK       19
-
-/* SPI_1 device configuration */
-#define SPI_1_DEV           NRF_SPI1
-#define SPI_1_PIN_MOSI      20
-#define SPI_1_PIN_MISO      21
-#define SPI_1_PIN_SCK       22
+static const spi_conf_t spi_config[] = {
+    {
+        .dev  = NRF_SPI0,
+        .sclk = 19,
+        .mosi = 17,
+        .miso = 18
+    },
+    {
+        .dev  = NRF_SPI1,
+        .sclk = 22,
+        .mosi = 20,
+        .miso = 21
+    }
+};
+
+#define SPI_NUMOF           (sizeof(spi_config) / sizeof(spi_config[0]))
 /** @} */
 
 /**
diff --git a/boards/z1/include/board.h b/boards/z1/include/board.h
index d3c1bc7993412605072cd938eaadcd25b031d419..1646253bf38722669c6518b0b01e12db951acab3 100644
--- a/boards/z1/include/board.h
+++ b/boards/z1/include/board.h
@@ -110,8 +110,8 @@ extern "C" {
 /**
  * @brief   Definition of the interface to the CC2420 radio
  */
-#define CC2420_PARAMS_BOARD         {.spi        = SPI_0, \
-                                     .spi_clk    = SPI_SPEED_5MHZ, \
+#define CC2420_PARAMS_BOARD         {.spi        = SPI_DEV(0), \
+                                     .spi_clk    = SPI_CLK_5MHZ, \
                                      .pin_cs     = GPIO_PIN(P3, 0), \
                                      .pin_fifo   = GPIO_PIN(P1, 3), \
                                      .pin_fifop  = GPIO_PIN(P1, 2), \
diff --git a/boards/z1/include/periph_conf.h b/boards/z1/include/periph_conf.h
index 3196da8df6278b1074a3d6a5d0f9c29391247a2f..a0261978d57119d1afe1e49a0e352e4765f39893 100644
--- a/boards/z1/include/periph_conf.h
+++ b/boards/z1/include/periph_conf.h
@@ -76,7 +76,7 @@ extern "C" {
 
 /* SPI configuration */
 #define SPI_USE_USCI
-#define SPI_DEV             (USCI_0_B_SPI)
+#define SPI_BASE            (USCI_0_B_SPI)
 #define SPI_IE              (SFR->IE2)
 #define SPI_IF              (SFR->IFG2)
 #define SPI_IE_RX_BIT       (1 << 2)
diff --git a/cpu/atmega1281/cpu.c b/cpu/atmega1281/cpu.c
index 0159ec5b8c55bf97f7b583bcac65110c4dc51fff..2d184cf544dba12d8672a318c0c897bc5d492970 100644
--- a/cpu/atmega1281/cpu.c
+++ b/cpu/atmega1281/cpu.c
@@ -18,12 +18,13 @@
  */
 
 #include "cpu.h"
+#include "periph/init.h"
 
 /**
  * @brief Initialize the CPU, set IRQ priorities
  */
 void cpu_init(void)
 {
-    /* Right now we need to do nothing here */
-    ;
+    /* trigger static peripheral initialization */
+    periph_init();
 }
diff --git a/cpu/atmega2560/cpu.c b/cpu/atmega2560/cpu.c
index e79c67dc6b080bbc949baa71debbdcbe56d136b5..8ea4e28b5f0f154af9ab068beccf1465bc76aa75 100644
--- a/cpu/atmega2560/cpu.c
+++ b/cpu/atmega2560/cpu.c
@@ -18,12 +18,13 @@
  */
 
 #include "cpu.h"
+#include "periph/init.h"
 
 /**
  * @brief Initialize the CPU, set IRQ priorities
  */
 void cpu_init(void)
 {
-    /* Right now we need to do nothing here */
-    ;
+    /* trigger static peripheral initialization */
+    periph_init();
 }
diff --git a/cpu/atmega328p/cpu.c b/cpu/atmega328p/cpu.c
index 3de168ab4f3610d5ec88d3b68b057085d93ba9a5..ed865bd42a56f188d2da978e2ffb5be8b2aef006 100644
--- a/cpu/atmega328p/cpu.c
+++ b/cpu/atmega328p/cpu.c
@@ -18,12 +18,13 @@
  */
 
 #include "cpu.h"
+#include "periph/init.h"
 
 /**
  * @brief Initialize the CPU, set IRQ priorities
  */
 void cpu_init(void)
 {
-    /* Right now we need to do nothing here */
-    ;
+    /* trigger static peripheral initialization */
+    periph_init();
 }
diff --git a/cpu/atmega_common/include/periph_cpu_common.h b/cpu/atmega_common/include/periph_cpu_common.h
index 62d3e200d26d0d18dc44764274de4c411942661e..c355a843ccb6c625785a77a863103fad67921b08 100644
--- a/cpu/atmega_common/include/periph_cpu_common.h
+++ b/cpu/atmega_common/include/periph_cpu_common.h
@@ -32,6 +32,16 @@ extern "C" {
  */
 #define GPIO_PIN(x, y)          ((x << 4) | y)
 
+/**
+ * @brief   Use some common SPI functions
+ * @{
+ */
+#define PERIPH_SPI_NEEDS_INIT_CS
+#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
+#define PERIPH_SPI_NEEDS_TRANSFER_REG
+#define PERIPH_SPI_NEEDS_TRANSFER_REGS
+/** @} */
+
 /**
  * @brief   SPI mode select macro
  *
@@ -47,13 +57,13 @@ extern "C" {
  * correct configuration there
  * @{
  */
-#define HAVE_SPI_CONF_T
+#define HAVE_SPI_MODE_T
 typedef enum {
-    SPI_CONF_FIRST_RISING   = SPI_MODE_SEL(0, 0),   /**< mode 0 */
-    SPI_CONF_SECOND_RISING  = SPI_MODE_SEL(0, 1),   /**< mode 1 */
-    SPI_CONF_FIRST_FALLING  = SPI_MODE_SEL(1, 0),   /**< mode 2 */
-    SPI_CONF_SECOND_FALLING = SPI_MODE_SEL(1, 1)    /**< mode 3 */
-} spi_conf_t;
+    SPI_MODE_0 = SPI_MODE_SEL(0, 0),    /**< mode 0 */
+    SPI_MODE_1 = SPI_MODE_SEL(0, 1),    /**< mode 1 */
+    SPI_MODE_2 = SPI_MODE_SEL(1, 0),    /**< mode 2 */
+    SPI_MODE_3 = SPI_MODE_SEL(1, 1)     /**< mode 3 */
+} spi_mode_t;
 /** @} */
 
 /**
@@ -62,7 +72,7 @@ typedef enum {
  * We encode the speed in bits 2, 1, and 0, where bit0 and bit1 hold the SPCR
  * prescaler bits, while bit2 holds the SPI2X bit.
  */
-#define SPI_SPEED_SEL(s2x, pr1, pr0)    ((s2x << 2) | (pr1 << 1) | pr0)
+#define SPI_CLK_SEL(s2x, pr1, pr0)    ((s2x << 2) | (pr1 << 1) | pr0)
 
 /**
  * @brief   Override SPI speed values
@@ -70,14 +80,14 @@ typedef enum {
  * We assume a master clock speed of 16MHz here.
  * @{
  */
-#define HAVE_SPI_SPEED_T
+#define HAVE_SPI_CLK_T
 typedef enum {
-    SPI_SPEED_100KHZ = SPI_SPEED_SEL(0, 1, 1),      /**< 16/128 -> 125KHz */
-    SPI_SPEED_400KHZ = SPI_SPEED_SEL(1, 1, 0),      /**< 16/32  -> 500KHz */
-    SPI_SPEED_1MHZ   = SPI_SPEED_SEL(0, 0, 1),      /**< 16/16  -> 1MHz */
-    SPI_SPEED_5MHZ   = SPI_SPEED_SEL(0, 0, 0),      /**< 16/4   -> 4MHz */
-    SPI_SPEED_10MHZ  = SPI_SPEED_SEL(1, 0, 0)       /**< 16/2   -> 8MHz */
-} spi_speed_t;
+    SPI_CLK_100KHZ = SPI_CLK_SEL(0, 1, 1),      /**< 16/128 -> 125KHz */
+    SPI_CLK_400KHZ = SPI_CLK_SEL(1, 1, 0),      /**< 16/32  -> 500KHz */
+    SPI_CLK_1MHZ   = SPI_CLK_SEL(0, 0, 1),      /**< 16/16  -> 1MHz */
+    SPI_CLK_5MHZ   = SPI_CLK_SEL(0, 0, 0),      /**< 16/4   -> 4MHz */
+    SPI_CLK_10MHZ  = SPI_CLK_SEL(1, 0, 0)       /**< 16/2   -> 8MHz */
+} spi_clk_t;
 /** @} */
 
 #ifdef __cplusplus
diff --git a/cpu/atmega_common/periph/spi.c b/cpu/atmega_common/periph/spi.c
index 7d1338ae6ec512decf8a0ff4e39dc668c46d66c9..9464f68ac9a791044e5e4a255087b0f34d3bf533 100644
--- a/cpu/atmega_common/periph/spi.c
+++ b/cpu/atmega_common/periph/spi.c
@@ -22,31 +22,30 @@
 
 #include "cpu.h"
 #include "mutex.h"
+#include "assert.h"
 #include "periph/spi.h"
 
-#define ENABLE_DEBUG    (0)
-#include "debug.h"
-
-/* guard this file in case no SPI device is defined */
-#if SPI_NUMOF
-
 /**
  * @brief   Extract BR0, BR1 and SPI2X bits from speed value
  * @{
  */
-#define SPEED_MASK          (0x3)
+#define CLK_MASK            (0x3)
 #define S2X_SHIFT           (2)
 /** @} */
 
 static mutex_t lock = MUTEX_INIT;
 
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
+void spi_init(spi_t bus)
+{
+    assert(bus == 0);
+    /* power off the SPI peripheral */
+    MEGA_PRR |= (1 << PRSPI);
+    /* trigger the pin configuration */
+    spi_init_pins(bus);;
+}
+
+void spi_init_pins(spi_t bus)
 {
-    DEBUG("spi.c: conf = %d, speed = %d\n", conf, speed);
-    /* make sure device is valid (there is only one...) */
-    if (dev != 0) {
-        return -1;
-    }
 
     /* the pin configuration for this CPU is fixed:
      * - PB3: MISO (configure as input - done automatically)
@@ -59,93 +58,59 @@ int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
      * select externally for now)
      */
     DDRB |= ((1 << DDB2) | (1 << DDB1) | (1 << DDB0));
+}
+
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    (void)cs;
 
-    /* make sure the SPI is not powered off */
+    /* lock the bus and power on the SPI peripheral */
+    mutex_lock(&lock);
     MEGA_PRR &= ~(1 << PRSPI);
 
     /* configure as master, with given mode and clock */
-    SPSR = (speed >> S2X_SHIFT);
-    SPCR = ((1 << SPE) | (1 << MSTR) | conf | (speed & SPEED_MASK));
+    SPSR = (clk >> S2X_SHIFT);
+    SPCR = ((1 << SPE) | (1 << MSTR) | mode | (clk & CLK_MASK));
+    SPCR |= (1 << SPE);
 
-    /* clear interrupt flag by reading SPSR */
+    /* clear interrupt flag by reading SPSR and data register by reading SPDR */
     (void)SPSR;
-
-    /* clear data register */
     (void)SPDR;
 
-    return 0;
-}
-
-int spi_acquire(spi_t dev)
-{
-    mutex_lock(&lock);
-    return 0;
+    return SPI_OK;
 }
 
-int spi_release(spi_t dev)
+void spi_release(spi_t bus)
 {
+    /* power off and release the bus */
+    SPCR &= ~(1 << SPE);
+    MEGA_PRR |= (1 << PRSPI);
     mutex_unlock(&lock);
-    return 0;
-}
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data))
-{
-    (void) dev;
-    (void) conf;
-    (void) cb;
-
-    /* not implemented */
-    return -1;
 }
 
-void spi_transmission_begin(spi_t dev, char reset_val)
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
 {
-    (void)dev;
-    (void)reset_val;
+    uint8_t *out_buf = (uint8_t *)out;
+    uint8_t *in_buf = (uint8_t *)in;
 
-    /* not implemented */
-}
+    assert(out_buf || in_buf);
 
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    return spi_transfer_bytes(dev, &out, in, 1);
-}
+    if (cs != SPI_CS_UNDEF) {
+        gpio_clear((gpio_t)cs);
+    }
 
-int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length)
-{
-    for (unsigned int i = 0; i < length; i++) {
-        char tmp = (out) ? out[i] : 0;
+    for (size_t i = 0; i < len; i++) {
+        uint8_t tmp = (out_buf) ? out_buf[i] : 0;
         SPDR = tmp;
         while (!(SPSR & (1 << SPIF))) {}
         tmp = SPDR;
-        if (in) {
-            in[i] = tmp;
+        if (in_buf) {
+            in_buf[i] = tmp;
         }
     }
 
-    return (int)length;
-}
-
-int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in)
-{
-    spi_transfer_bytes(dev, (char *)&reg, NULL, 1);
-    return spi_transfer_bytes(dev, &out, in, 1);
-}
-
-int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length)
-{
-    spi_transfer_bytes(dev, (char *)&reg, NULL, 1);
-    return spi_transfer_bytes(dev, out, in, length);
-}
-
-void spi_poweron(spi_t dev)
-{
-    SPCR |= (1 << SPE);
-}
-
-void spi_poweroff(spi_t dev)
-{
-    SPCR &= ~(1 << SPE);
+    if ((!cont) && (cs != SPI_CS_UNDEF)) {
+        gpio_set((gpio_t)cs);
+    }
 }
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/cc2538/cpu.c b/cpu/cc2538/cpu.c
index 68c7b39e914897a22099aef59e96609cadaef08d..60bf9342bf3590cec0e90b658dc2998495dd48cd 100644
--- a/cpu/cc2538/cpu.c
+++ b/cpu/cc2538/cpu.c
@@ -20,6 +20,7 @@
 #include <assert.h>
 
 #include "cpu.h"
+#include "periph/init.h"
 
 #define BIT(n)          ( 1UL << (n) )
 
@@ -47,6 +48,8 @@ void cpu_init(void)
     SYS_CTRL->I_MAP = 1;
     /* initialize the clock system */
     cpu_clock_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 /**
diff --git a/cpu/cc2538/include/cc2538_ssi.h b/cpu/cc2538/include/cc2538_ssi.h
index 2dc08cff02e43c385797cdfa5c182c624ee2621a..5fbdc004dbc7c2eabb1c05b00133382ca74ac84a 100644
--- a/cpu/cc2538/include/cc2538_ssi.h
+++ b/cpu/cc2538/include/cc2538_ssi.h
@@ -77,6 +77,46 @@ typedef struct {
 #define SSI0 ( (cc2538_ssi_t*)0x40008000 ) /**< SSI0 Instance */
 #define SSI1 ( (cc2538_ssi_t*)0x40009000 ) /**< SSI1 Instance */
 
+/**
+ * @brief   Define CR0 register bitfields
+ * @{
+ */
+#define SSI_CR0_DSS(x)          ((x - 1) << 0)
+#define SSI_CR0_SPO             (1 << 6)
+#define SSI_CR0_SPH             (1 << 7)
+/** @} */
+
+/**
+ * @brief   Define CR1 register bitfields
+ * @{
+ */
+#define SSI_CR1_LBM             (1 << 0)
+#define SSI_CR1_SSE             (1 << 1)
+#define SSI_CR1_MS              (1 << 2)
+#define SSI_CR1_SOD             (1 << 3)
+/** @} */
+
+/**
+ * @brief   Define SR register bitfields
+ * @{
+ */
+#define SSI_SR_TFE              (1 << 0)
+#define SSI_SR_TNF              (1 << 1)
+#define SSI_SR_RNE              (1 << 2)
+#define SSI_SR_RFF              (1 << 3)
+#define SSI_SR_BSY              (1 << 4)
+/** @} */
+
+/**
+ * @brief   Define CC register bitfields
+ * @{
+ */
+#define SSI_SS_PIOSC            (1 << 0)
+#define SSI_SS_DSEN             (1 << 2)
+#define SSI_SS_SYSDIV           (0)
+#define SSI_SS_IODIV            (SSI_SS_PIOSC)
+/** @} */
+
 #ifdef __cplusplus
 } /* end extern "C" */
 #endif
diff --git a/cpu/cc2538/include/cpu_conf.h b/cpu/cc2538/include/cpu_conf.h
index 8c7695d46ec317fd5a49e20a80ae9c4c69095d47..7376a90241326015473083ce09857849882bed67 100644
--- a/cpu/cc2538/include/cpu_conf.h
+++ b/cpu/cc2538/include/cpu_conf.h
@@ -26,6 +26,7 @@
 #include "cc2538_gptimer.h"
 #include "cc2538_ioc.h"
 #include "cc2538_soc_adc.h"
+#include "cc2538_ssi.h"
 #include "cc2538_rfcore.h"
 #include "cc2538_sys_ctrl.h"
 
diff --git a/cpu/cc2538/include/periph_cpu.h b/cpu/cc2538/include/periph_cpu.h
index 78f1194d2ac274dcca8c04488e6719bb2f8149d6..2fbe199bbb8c0cbd6be6ed0a3d1cc8da5aa7f917 100644
--- a/cpu/cc2538/include/periph_cpu.h
+++ b/cpu/cc2538/include/periph_cpu.h
@@ -21,9 +21,7 @@
 
 #include <stdint.h>
 
-#include "cc2538_gptimer.h"
-#include "cc2538_ssi.h"
-#include "cc2538_gpio.h"
+#include "cpu.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -50,10 +48,25 @@ typedef uint32_t gpio_t;
  */
 #define GPIO_PIN(port, pin) (gpio_t)(((uint32_t)GPIO_A + (port << 12)) | pin)
 
+/**
+ * @brief   Define a custom GPIO_UNDEF value
+ */
+#define GPIO_UNDEF 99
+
+/**
+ * @brief   I2C configuration options
+ */
+typedef struct {
+    gpio_t scl_pin;         /**< pin used for SCL */
+    gpio_t sda_pin;         /**< pin used for SDA */
+} i2c_conf_t;
+
 /**
  * @brief declare needed generic SPI functions
  * @{
  */
+#define PERIPH_SPI_NEEDS_INIT_CS
+#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
 #define PERIPH_SPI_NEEDS_TRANSFER_REG
 #define PERIPH_SPI_NEEDS_TRANSFER_REGS
 /** @} */
@@ -74,12 +87,39 @@ typedef enum {
 /** @} */
 
 /**
- * @brief   I2C configuration options
+ * @brief   Override SPI mode settings
+ * @{
+ */
+#define HAVE_SPI_MODE_T
+typedef enum {
+    SPI_MODE_0 = 0,                             /**< CPOL=0, CPHA=0 */
+    SPI_MODE_1 = (SSI_CR0_SPH),                 /**< CPOL=0, CPHA=1 */
+    SPI_MODE_2 = (SSI_CR0_SPO),                 /**< CPOL=1, CPHA=0 */
+    SPI_MODE_3 = (SSI_CR0_SPO | SSI_CR0_SPH)    /**< CPOL=1, CPHA=1 */
+} spi_mode_t;
+/** @ */
+
+/**
+ * @brief   Override SPI clock settings
+ * @{
+ */
+#define HAVE_SPI_CLK_T
+typedef enum {
+    SPI_CLK_100KHZ = 0,     /**< drive the SPI bus with 100KHz */
+    SPI_CLK_400KHZ = 1,     /**< drive the SPI bus with 400KHz */
+    SPI_CLK_1MHZ   = 2,     /**< drive the SPI bus with 1MHz */
+    SPI_CLK_5MHZ   = 3,     /**< drive the SPI bus with 5MHz */
+    SPI_CLK_10MHZ  = 4      /**< drive the SPI bus with 10MHz */
+} spi_clk_t;
+/** @} */
+
+/**
+ * @brief   Datafields for static SPI clock configuration values
  */
 typedef struct {
-    gpio_t scl_pin;         /**< pin used for SCL */
-    gpio_t sda_pin;         /**< pin used for SDA */
-} i2c_conf_t;
+    uint8_t cpsr;           /**< CPSR clock divider */
+    uint8_t scr;            /**< SCR clock divider */
+} spi_clk_conf_t;
 
 /**
  * @brief   SPI configuration data structure
@@ -91,7 +131,7 @@ typedef struct {
     gpio_t miso_pin;        /**< pin used for MISO */
     gpio_t sck_pin;         /**< pin used for SCK */
     gpio_t cs_pin;          /**< pin used for CS */
-} periph_spi_conf_t;
+} spi_conf_t;
 /** @} */
 
 /**
diff --git a/cpu/cc2538/periph/spi.c b/cpu/cc2538/periph/spi.c
index 75dd2cba50a1c98c158e6f2f356855e100a9c44e..8a3a3add9a479180debdc796f00eb43f9b8abbd1 100644
--- a/cpu/cc2538/periph/spi.c
+++ b/cpu/cc2538/periph/spi.c
@@ -1,327 +1,175 @@
 /*
  * Copyright (C) 2015 Loci Controls Inc.
+ *               2016 Freie Universität Berlin
  *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
  */
 
 /**
- * @addtogroup  driver_periph
+ * @addtogroup  cpu_cc2538
  * @{
  *
  * @file
  * @brief       Low-level SPI driver implementation
  *
  * @author      Ian Martin <ian@locicontrols.com>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  *
  * @}
  */
 
-#include <assert.h>
-#include <stdio.h>
-
-#include "cc2538_ssi.h"
-
 #include "cpu.h"
 #include "mutex.h"
+#include "assert.h"
 #include "periph/spi.h"
-#include "periph_conf.h"
-
-/* guard file in case no SPI device is defined */
-#if SPI_NUMOF
-
-/* clock sources for the SSI_CC register */
-#define CS_SYS_DIV            0
-#define CS_IO_DIV             1
-
-#define SSI0_MASK             (1 << 0)
-#define SSI1_MASK             (1 << 1)
-
-#ifndef SPI_DATA_BITS_NUMOF
-#define SPI_DATA_BITS_NUMOF   8
-#endif
-
-#define spin_until(condition) while (!(condition)) thread_yield()
 
 /**
- * @brief Array holding one pre-initialized mutex for each SPI device
+ * @brief   Array holding one pre-initialized mutex for each SPI device
  */
-static mutex_t locks[SPI_NUMOF] = {MUTEX_INIT};
+static mutex_t locks[SPI_NUMOF];
 
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
+static inline cc2538_ssi_t *dev(spi_t bus)
 {
-    cc2538_ssi_t* ssi = spi_config[dev].dev;
-
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-
-    /* power on the SPI device */
-    spi_poweron(dev);
-
-    /* configure SCK, MISO and MOSI pin */
-    spi_conf_pins(dev);
-
-    /* Disable the SSI and configure it for SPI master mode */
-    ssi->CR1 = 0;
-
-    /* 3. Configure the SSI clock source */
-    ssi->CC = CS_SYS_DIV;
-
-    /* 4. Configure the clock prescale divisor by writing the SSI_CPSR register.
-     * frequency of the SSIClk is defined by: SSIClk = SysClk / (CPSDVSR x (1 + SCR))
-     */
-
-    const int32_t speed_lut[] = {
-        [SPI_SPEED_100KHZ] =   100000 /* Hz */,
-        [SPI_SPEED_400KHZ] =   400000 /* Hz */,
-        [SPI_SPEED_1MHZ  ] =  1000000 /* Hz */,
-        [SPI_SPEED_5MHZ  ] =  5000000 /* Hz */,
-        [SPI_SPEED_10MHZ ] = 10000000 /* Hz */,
-    };
-
-    int32_t SysClk = sys_clock_freq();
-    int32_t f_desired = speed_lut[speed];
-    int32_t f_actual;
-    int32_t err;
-    int32_t best_err = INT32_MAX;
-    int32_t div1;
-    int32_t div2;
-    int32_t best_div1 = 2;
-    int32_t best_div2 = 1;
-
-    /* System clock is first divided by CPSDVSR, then by SCR */
-    for (div1 = 2; div1 <= 254; div1++) {
-        div2 = SysClk;
-        int32_t denom = div1 * f_desired;
-        div2 += denom / 2;
-        div2 /= denom;
-
-        if (div2 < 1) {
-            div2 = 1;
-        }
-        else if (div2 > 256) {
-            div2 = 256;
-        }
-
-        f_actual = SysClk / (div1 * div2);
-        err = f_actual - f_desired;
-        if (err < 0) {
-            err = -err;
-        }
-        if (err <= best_err) {
-            best_div1 = div1;
-            best_div2 = div2;
-            best_err = err;
-        }
-    }
-
-    ssi->CPSR        = best_div1;     /* CPSDVSR */
-    ssi->CR0bits.SCR = best_div2 - 1; /* Serial clock rate (SCR) */
-
-    switch (conf) {
-        case SPI_CONF_FIRST_RISING:
-            ssi->CR0bits.SPO = 0;
-            ssi->CR0bits.SPH = 0;
-            break;
-
-        case SPI_CONF_SECOND_RISING:
-            ssi->CR0bits.SPO = 0;
-            ssi->CR0bits.SPH = 1;
-            break;
-
-        case SPI_CONF_FIRST_FALLING:
-            ssi->CR0bits.SPO = 1;
-            ssi->CR0bits.SPH = 0;
-            break;
-
-        case SPI_CONF_SECOND_FALLING:
-            ssi->CR0bits.SPO = 1;
-            ssi->CR0bits.SPH = 1;
-            break;
-    }
-
-    ssi->CR0bits.FRF = 0;                       /* SPI protocol mode */
-    ssi->CR0bits.DSS = SPI_DATA_BITS_NUMOF - 1; /* The data size */
-
-    ssi->CR1bits.SSE = 1;
+    return spi_config[bus].dev;
+}
 
-    return 0;
+static inline void poweron(spi_t bus)
+{
+    SYS_CTRL_RCGCSSI |= (1 << bus);
+    SYS_CTRL_SCGCSSI |= (1 << bus);
+    SYS_CTRL_DCGCSSI |= (1 << bus);
 }
 
-int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data))
+static inline void poweroff(spi_t bus)
 {
-    /* slave mode is not (yet) supported */
-    return -1;
+    SYS_CTRL_RCGCSSI &= ~(1 << bus);
+    SYS_CTRL_SCGCSSI &= ~(1 << bus);
+    SYS_CTRL_DCGCSSI &= ~(1 << bus);
 }
 
-int spi_conf_pins(spi_t dev)
+void spi_init(spi_t bus)
 {
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
+    assert(bus <= SPI_NUMOF);
+
+    /* temporarily power on the device */
+    poweron(bus);
+    /* configure device to be a master and disable SSI operation mode */
+    dev(bus)->CR1 = 0;
+    /* configure system clock as SSI clock source */
+    dev(bus)->CC = SSI_SS_IODIV;
+    /* and power off the bus again */
+    poweroff(bus);
+
+    /* trigger SPI pin configuration */
+    spi_init_pins(bus);
+}
 
-    switch ((uintptr_t)spi_config[dev].dev) {
+void spi_init_pins(spi_t bus)
+{
+    switch ((uintptr_t)spi_config[bus].dev) {
         case (uintptr_t)SSI0:
-            IOC_PXX_SEL[spi_config[dev].mosi_pin] = SSI0_TXD;
-            IOC_PXX_SEL[spi_config[dev].sck_pin ] = SSI0_CLKOUT;
-            IOC_PXX_SEL[spi_config[dev].cs_pin  ] = SSI0_FSSOUT;
+            IOC_PXX_SEL[spi_config[bus].mosi_pin] = SSI0_TXD;
+            IOC_PXX_SEL[spi_config[bus].sck_pin ] = SSI0_CLKOUT;
+            IOC_PXX_SEL[spi_config[bus].cs_pin  ] = SSI0_FSSOUT;
 
-            IOC_SSIRXD_SSI0 = spi_config[dev].miso_pin;
+            IOC_SSIRXD_SSI0 = spi_config[bus].miso_pin;
             break;
 
         case (uintptr_t)SSI1:
-            IOC_PXX_SEL[spi_config[dev].mosi_pin] = SSI1_TXD;
-            IOC_PXX_SEL[spi_config[dev].sck_pin ] = SSI1_CLKOUT;
-            IOC_PXX_SEL[spi_config[dev].cs_pin  ] = SSI1_FSSOUT;
+            IOC_PXX_SEL[spi_config[bus].mosi_pin] = SSI1_TXD;
+            IOC_PXX_SEL[spi_config[bus].sck_pin ] = SSI1_CLKOUT;
+            IOC_PXX_SEL[spi_config[bus].cs_pin  ] = SSI1_FSSOUT;
 
-            IOC_SSIRXD_SSI1 = spi_config[dev].miso_pin;
+            IOC_SSIRXD_SSI1 = spi_config[bus].miso_pin;
             break;
     }
 
-    IOC_PXX_OVER[spi_config[dev].mosi_pin] = IOC_OVERRIDE_OE;
-    IOC_PXX_OVER[spi_config[dev].sck_pin ] = IOC_OVERRIDE_OE;
-    IOC_PXX_OVER[spi_config[dev].cs_pin  ] = IOC_OVERRIDE_OE;
-    IOC_PXX_OVER[spi_config[dev].miso_pin] = IOC_OVERRIDE_DIS;
-
-    gpio_hardware_control(spi_config[dev].mosi_pin);
-    gpio_hardware_control(spi_config[dev].miso_pin);
-    gpio_hardware_control(spi_config[dev].sck_pin);
-    gpio_hardware_control(spi_config[dev].cs_pin);
+    IOC_PXX_OVER[spi_config[bus].mosi_pin] = IOC_OVERRIDE_OE;
+    IOC_PXX_OVER[spi_config[bus].miso_pin] = IOC_OVERRIDE_DIS;
+    IOC_PXX_OVER[spi_config[bus].sck_pin ] = IOC_OVERRIDE_OE;
+    IOC_PXX_OVER[spi_config[bus].cs_pin  ] = IOC_OVERRIDE_OE;
 
-    return 0;
+    gpio_hardware_control(spi_config[bus].mosi_pin);
+    gpio_hardware_control(spi_config[bus].miso_pin);
+    gpio_hardware_control(spi_config[bus].sck_pin);
+    gpio_hardware_control(spi_config[bus].cs_pin);
 }
 
-int spi_acquire(spi_t dev)
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
 {
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
+    /* lock the bus */
+    mutex_lock(&locks[bus]);
+    /* power on device */
+    poweron(bus);
+    /* configure SCR clock field, data-width and mode */
+    dev(bus)->CR0 = 0;
+    dev(bus)->CPSR = (spi_clk_config[clk].cpsr);
+    dev(bus)->CR0 = ((spi_clk_config[clk].scr << 8) | mode | SSI_CR0_DSS(8));
+    /* enable SSI device */
+    dev(bus)->CR1 = SSI_CR1_SSE;
+
+    return SPI_OK;
 }
 
-int spi_release(spi_t dev)
+void spi_release(spi_t bus)
 {
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
+    /* disable and power off device */
+    dev(bus)->CR1 = 0;
+    poweroff(bus);
+    /* and release lock... */
+    mutex_unlock(&locks[bus]);
 }
 
-static char ssi_flush_input(cc2538_ssi_t *ssi)
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
 {
-    char tmp = 0;
-
-    while (ssi->SRbits.RNE) {
-        tmp = ssi->DR;
-    }
+    uint8_t *out_buf = (uint8_t *)out;
+    uint8_t *in_buf = (uint8_t *)in;
 
-    return tmp;
-}
+    assert(out_buf || in_buf);
 
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    cc2538_ssi_t* ssi = spi_config[dev].dev;
-    char tmp;
-
-    ssi_flush_input(ssi);
-
-    /* transmit byte */
-    spin_until(ssi->SRbits.TNF);
-    ssi->DR = out;
-
-    /* receive byte */
-    spin_until(ssi->SRbits.RNE);
-    tmp = ssi->DR;
-
-    if (in) {
-        *in = tmp;
+    if (cs != SPI_CS_UNDEF) {
+        gpio_clear((gpio_t)cs);
     }
 
-    return 1;
-}
-
-int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length)
-{
-    cc2538_ssi_t* ssi = spi_config[dev].dev;
-    unsigned int tx_n = 0, rx_n = 0;
-
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-
-    ssi_flush_input(ssi);
-
-    /* transmit and receive bytes */
-    while (tx_n < length) {
-        spin_until(ssi->SRbits.TNF || ssi->SRbits.RNE);
-
-        if (ssi->SRbits.TNF) {
-            ssi->DR = out[tx_n];
-            tx_n++;
+    if (!in_buf) {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SSI_SR_TNF)) {}
+            dev(bus)->DR = out_buf[i];
         }
-        else if (ssi->SRbits.RNE) {
-            assert(rx_n < length);
-            in[rx_n] = ssi->DR;
-            rx_n++;
+        /* flush RX FIFO while busy*/
+        while ((dev(bus)->SR & SSI_SR_BSY)) {
+            dev(bus)->DR;
         }
     }
-
-    /* receive remaining bytes */
-    while (rx_n < length) {
-        spin_until(ssi->SRbits.RNE);
-        assert(rx_n < length);
-        in[rx_n] = ssi->DR;
-        rx_n++;
+    else if (!out_buf) { /*TODO this case is currently untested */
+        size_t in_cnt = 0;
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SSI_SR_TNF)) {}
+            dev(bus)->DR = 0;
+            if (dev(bus)->SR & SSI_SR_RNE) {
+                in_buf[in_cnt++] = dev(bus)->DR;
+            }
+        }
+        /* get remaining bytes */
+        while (dev(bus)->SR & SSI_SR_RNE) {
+            in_buf[in_cnt++] = dev(bus)->DR;
+        }
     }
-
-    return rx_n;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    /* slave mode is not (yet) supported */
-}
-
-void spi_poweron(spi_t dev)
-{
-    switch ((uintptr_t)spi_config[dev].dev) {
-        case (uintptr_t)SSI0:
-            /* enable SSI0 in all three power modes */
-            SYS_CTRL_RCGCSSI |= SSI0_MASK;
-            SYS_CTRL_SCGCSSI |= SSI0_MASK;
-            SYS_CTRL_DCGCSSI |= SSI0_MASK;
-            break;
-
-        case (uintptr_t)SSI1:
-            /* enable SSI1 in all three power modes */
-            SYS_CTRL_RCGCSSI |= SSI1_MASK;
-            SYS_CTRL_SCGCSSI |= SSI1_MASK;
-            SYS_CTRL_DCGCSSI |= SSI1_MASK;
-            break;
+    else {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SSI_SR_TNF)) {}
+            dev(bus)->DR = out_buf[i];
+            while (!(dev(bus)->SR & SSI_SR_RNE)){}
+            in_buf[i] = dev(bus)->DR;
+        }
+    /* wait until no more busy */
+    while ((dev(bus)->SR & SSI_SR_BSY)) {}
     }
-}
-
-void spi_poweroff(spi_t dev)
-{
-    switch ((uintptr_t)spi_config[dev].dev) {
-        case (uintptr_t)SSI0:
-            /* disable SSI0 in all three power modes */
-            SYS_CTRL_RCGCSSI &= ~SSI0_MASK;
-            SYS_CTRL_SCGCSSI &= ~SSI0_MASK;
-            SYS_CTRL_DCGCSSI &= ~SSI0_MASK;
-            break;
 
-        case (uintptr_t)SSI1:
-            /* disable SSI1 in all three power modes */
-            SYS_CTRL_RCGCSSI &= ~SSI1_MASK;
-            SYS_CTRL_SCGCSSI &= ~SSI1_MASK;
-            SYS_CTRL_DCGCSSI &= ~SSI1_MASK;
-            break;
+    if ((!cont) && (cs != SPI_CS_UNDEF)) {
+        gpio_set((gpio_t)cs);
     }
 }
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/cc26x0/cpu.c b/cpu/cc26x0/cpu.c
index 2f4f55ecd21def6aff2631927f79be870a046dcb..232bdc343ee81e1b8279b661db2ac30173c35927 100644
--- a/cpu/cc26x0/cpu.c
+++ b/cpu/cc26x0/cpu.c
@@ -17,8 +17,9 @@
  * @}
  */
 
- #include "cpu.h"
- #include "periph_conf.h"
+#include "cpu.h"
+#include "periph_conf.h"
+#include "periph/init.h"
 
 #ifndef HF_CLOCK_SOURCE
 #define HF_CLOCK_SOURCE DDI_0_OSC_CTL0_SCLK_HF_SRC_SEL_RCOSC /* set 48MHz RCOSC */
@@ -42,6 +43,9 @@ void cpu_init(void)
 
     /* initialize the system clock */
     cpu_clock_init();
+
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 static void cpu_clock_init(void)
diff --git a/cpu/ezr32wg/cpu.c b/cpu/ezr32wg/cpu.c
index d48dc6e3464b40c2361144680a801c23c2113460..afa1927184f748860e83c3f250912512d1aa0707 100644
--- a/cpu/ezr32wg/cpu.c
+++ b/cpu/ezr32wg/cpu.c
@@ -19,6 +19,7 @@
 
 #include "cpu.h"
 #include "periph_conf.h"
+#include "periph/init.h"
 
 /**
  * @brief   Configure clock sources and the CPU frequency
@@ -59,4 +60,6 @@ void cpu_init(void)
     cortexm_init();
     /* Initialise clock sources and generic clocks */
     clk_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
diff --git a/cpu/k60/cpu.c b/cpu/k60/cpu.c
index f25d4056ccee85aacb4f68e3f8d6d00942d976a7..327100e9b1661dd93fb301b29100b2308997c683 100644
--- a/cpu/k60/cpu.c
+++ b/cpu/k60/cpu.c
@@ -9,6 +9,7 @@
 #include <stdint.h>
 #include "cpu.h"
 #include "board.h"
+#include "periph/init.h"
 
 /**
  * @ingroup     cpu_k60
@@ -48,6 +49,8 @@ void cpu_init(void)
     cortexm_init();
     /* Check that we are running on the CPU that this code was built for */
     check_running_cpu_revision();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 static void check_running_cpu_revision(void)
diff --git a/cpu/k64f/cpu.c b/cpu/k64f/cpu.c
index 567ce64e4239169a91dcb6de591bff1504b93247..cfb6583bc6eba3bcb2c3fffe4d77434b2cc361b6 100644
--- a/cpu/k64f/cpu.c
+++ b/cpu/k64f/cpu.c
@@ -23,6 +23,7 @@
 #include "cpu.h"
 #include "mcg.h"
 #include "cpu_conf.h"
+#include "periph/init.h"
 
 #define SIM_CLKDIV1_60MHZ      (SIM_CLKDIV1_OUTDIV1(0) | \
                                 SIM_CLKDIV1_OUTDIV2(0) | \
@@ -40,6 +41,8 @@ void cpu_init(void)
     cortexm_init();
     /* initialize the clock system */
     cpu_clock_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 /**
diff --git a/cpu/kinetis_common/Makefile.include b/cpu/kinetis_common/Makefile.include
index b98008a42823eeba4b38a3232ef68e2ec2c812c5..a0464ae67fe45a1356ff097803b356e9952c79b7 100644
--- a/cpu/kinetis_common/Makefile.include
+++ b/cpu/kinetis_common/Makefile.include
@@ -9,6 +9,7 @@ export UNDEF += $(BINDIR)/kinetis_common/fcfield.o
 
 # include kinetis common periph drivers
 export USEMODULE += kinetis_common_periph
+export USEMODULE += periph_common
 
 #include layered power mode module
 USEMODULE += pm_layered
diff --git a/cpu/kinetis_common/dist/calc_spi_scalers/Makefile b/cpu/kinetis_common/dist/calc_spi_scalers/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1ada319e2da48b4611e5d9cbb355dd0547bf8186
--- /dev/null
+++ b/cpu/kinetis_common/dist/calc_spi_scalers/Makefile
@@ -0,0 +1,12 @@
+NAME        = calc_spi_scalers
+CC          = gcc
+CFLAGS      = -std=c99 -Wall
+SRC         = $(wildcard *.c)
+
+.PHONY: all clean
+
+all:
+	$(CC) $(CFLAGS) -o $(NAME) $(SRC)
+
+clean:
+	rm -f $(NAME)
diff --git a/cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c b/cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c
new file mode 100644
index 0000000000000000000000000000000000000000..a80045b462b45766f43d8796f3b9e4c18386b0b0
--- /dev/null
+++ b/cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2014 Hamburg University of Applied Sciences
+ *               2014 PHYTEC Messtechnik GmbH
+ *               2015 Eistec AB
+ *               2016 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @brief       SPI bus scaler computation
+ *
+ * This helper tool calculates the needed SPI scaler values for a given APB bus
+ * clock speed. The result of the computation must be placed in a board's
+ * periph_conf.h for quick reference by the SPI drivers.
+ *
+ * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
+ * @author      Johann Fischer <j.fischer@phytec.de>
+ * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * @brief Targeted SPI bus speed values (pre-defined by RIOT)
+ */
+static uint32_t targets[] = { 100000, 400000, 1000000, 5000000, 10000000 };
+
+/**
+ * @brief Helper function for finding optimal baud rate scalers.
+ *
+ * Find the prescaler and scaler settings that will yield a clock frequency
+ * as close as possible (but not above) the target frequency, given the module
+ * runs at module_clock Hz.
+ *
+ * Hardware properties (Baud rate configuration):
+ * Possible prescalers: 2, 3, 5, 7
+ * Possible scalers: 2, 4, 6 (sic!), 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768
+ *
+ * SCK baud rate = (f_BUS/PBR) x [(1+DBR)/BR]
+ *
+ * where PBR is the prescaler, BR is the scaler, DBR is the Double BaudRate bit.
+ *
+ * @note We are not using the DBR bit because it may affect the SCK duty cycle.
+ *
+ * @param module_clock Module clock frequency (e.g. F_BUS)
+ * @param target_clock Desired baud rate
+ * @param closest_prescaler pointer where to write the optimal prescaler index.
+ * @param closest_scaler pointer where to write the optimal scaler index.
+ *
+ * @return The actual achieved frequency on success
+ * @return Less than 0 on error.
+ */
+
+static long find_closest_baudrate_scalers(const uint32_t module_clock, const long target_clock,
+                                          uint8_t *closest_prescaler, uint8_t *closest_scaler)
+{
+    uint8_t i;
+    uint8_t k;
+    long freq;
+    static const uint8_t num_scalers = 16;
+    static const uint8_t num_prescalers = 4;
+    static const int br_scalers[16] = {
+        2,     4,     6,     8,    16,    32,    64,   128,
+        256,   512,  1024,  2048,  4096,  8192, 16384, 32768
+    };
+    static const int br_prescalers[4] = {2, 3, 5, 7};
+
+    long closest_frequency = -1;
+
+    /* Test all combinations until we arrive close to the target clock */
+    for (i = 0; i < num_prescalers; ++i) {
+        for (k = 0; k < num_scalers; ++k) {
+            freq = module_clock / (br_scalers[k] * br_prescalers[i]);
+
+            if (freq <= target_clock) {
+                /* Found closest lower frequency at this prescaler setting,
+                 * compare to the best result */
+                if (closest_frequency < freq) {
+                    closest_frequency = freq;
+                    *closest_scaler = k;
+                    *closest_prescaler = i;
+                }
+
+                break;
+            }
+        }
+    }
+
+    if (closest_frequency < 0) {
+        /* Error, no solution found, this line is never reachable with current
+         * hardware settings unless a _very_ low target clock is requested.
+         * (scaler_max * prescaler_max) = 229376 => target_min@100MHz = 435 Hz*/
+        return -1;
+    }
+
+    return closest_frequency;
+}
+
+/**
+ * @brief Helper function for finding optimal delay scalers.
+ *
+ * Find the prescaler and scaler settings that will yield a delay timing
+ * as close as possible (but not shorter than) the target delay, given the
+ * module runs at module_clock Hz.
+ *
+ * Hardware properties (delay configuration):
+ * Possible prescalers: 1, 3, 5, 7
+ * Possible scalers: 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536
+ *
+ * delay = (1/f_BUS) x prescaler x scaler
+ *
+ * Because we want to do this using only integers, the target_freq parameter is
+ * the reciprocal of the delay time.
+ *
+ * @param module_clock Module clock frequency (e.g. F_BUS)
+ * @param target_freq Reciprocal (i.e. 1/t [Hz], frequency) of the desired delay time.
+ * @param closest_prescaler pointer where to write the optimal prescaler index.
+ * @param closest_scaler pointer where to write the optimal scaler index.
+ *
+ * @return The actual achieved frequency on success
+ * @return Less than 0 on error.
+ */
+static long find_closest_delay_scalers(const uint32_t module_clock, const long target_freq,
+                                      uint8_t *closest_prescaler, uint8_t *closest_scaler)
+{
+    uint8_t i;
+    uint8_t k;
+    long freq;
+    int prescaler;
+    int scaler;
+    static const uint8_t num_scalers = 16;
+    static const uint8_t num_prescalers = 4;
+
+    long closest_frequency = -1;
+
+    /* Test all combinations until we arrive close to the target clock */
+    for (i = 0; i < num_prescalers; ++i) {
+        for (k = 0; k < num_scalers; ++k) {
+            prescaler = (i * 2) + 1;
+            scaler = (1 << (k + 1)); /* 2^(k+1) */
+            freq = module_clock / (prescaler * scaler);
+
+            if (freq <= target_freq) {
+                /* Found closest lower frequency at this prescaler setting,
+                 * compare to the best result */
+                if (closest_frequency < freq) {
+                    closest_frequency = freq;
+                    *closest_scaler = k;
+                    *closest_prescaler = i;
+                }
+
+                break;
+            }
+        }
+    }
+
+    if (closest_frequency < 0) {
+        /* Error, no solution found, this line is never reachable with current
+         * hardware settings unless a _very_ low target clock is requested.
+         * (scaler_max * prescaler_max) = 458752 */
+        return -1;
+    }
+
+    return closest_frequency;
+}
+
+
+int main(int argc, char **argv)
+{
+    uint32_t modclk;
+    int i;
+
+    if (argc != 2) {
+        printf("usage: %s <module clock>\n", argv[0]);
+        return 1;
+    }
+
+    modclk = (uint32_t)atoi(argv[1]);
+    if (modclk == 0) {
+        printf("error: invalid input value\n");
+        return 1;
+    }
+
+    printf("\nCalculating SPI clock scalers for a module clock of: %iHz\n\n",
+            (int)modclk);
+
+
+    puts("static const uint32_t spi_clk_config[] = {");
+
+    for (i = 0; i < (sizeof(targets) / sizeof(targets[0])); i++) {
+        uint8_t tmp, ptmp;
+        long res;
+        /* bus clock */
+        res = find_closest_baudrate_scalers(modclk, targets[i], &ptmp, &tmp);
+        if (res < 0) {
+            puts("error: no applicable bus clock scalers could be found!");
+            return 1;
+        }
+        puts("    (");
+        printf("        SPI_CTAR_PBR(%i) | SPI_CTAR_BR(%i) |          /* -> %iHz */\n",
+               (int)ptmp, (int)tmp, (int)res);
+
+        /* t_csc: chip select to fist clock signal delay */
+        if (find_closest_delay_scalers(modclk, targets[i], &ptmp, &tmp) < 0) {
+            puts("error: no applicable delay values for t_csc found\n");
+            return 1;
+        }
+        printf("        SPI_CTAR_PCSSCK(%i) | SPI_CTAR_CSSCK(%i) |\n", (int)ptmp, (int)tmp);
+
+        /* t_asc: delay after last clock signal to release of chip select */
+        if (find_closest_delay_scalers(modclk, targets[i], &ptmp, &tmp) < 0) {
+            puts("error: no applicable delay values for t_asc found\n");
+            return 1;
+        }
+        printf("        SPI_CTAR_PASC(%i) | SPI_CTAR_ASC(%i) |\n", (int)ptmp, (int)tmp);
+
+        /* t_psc: delay between release and next assertion of chip select */
+        if (find_closest_delay_scalers(modclk, targets[i], &ptmp, &tmp) < 0) {
+            puts("error: no applicable delay values for t_csc found\n");
+            return 1;
+        }
+        printf("        SPI_CTAR_PDT(%i) | SPI_CTAR_DT(%i)\n", (int)ptmp, (int)tmp);
+
+        if (i == (sizeof(targets) / sizeof(targets[0])) - 1) {
+            puts("    )");
+        }
+        else {
+            puts("    ),");
+        }
+    }
+    puts("};");
+
+    return 0;
+}
diff --git a/cpu/kinetis_common/include/periph_cpu.h b/cpu/kinetis_common/include/periph_cpu.h
index c87c7f85815c87c413c63c181a7c83c28ff5c2f6..5be69a2800d326724db99f7a7f0f42150f6a46df 100644
--- a/cpu/kinetis_common/include/periph_cpu.h
+++ b/cpu/kinetis_common/include/periph_cpu.h
@@ -66,6 +66,28 @@ typedef uint16_t gpio_t;
  */
 #define PWM_CHAN_MAX        (4U)
 
+/**
+ * @brief   Define a CPU specific SPI hardware chip select line macro
+ *
+ * We simply map the 5 hardware channels to the numbers [0-4], this still allows
+ * us to differentiate between GPIP_PINs and SPI_HWSC lines.
+ */
+#define SPI_HWCS(x)         (x)
+
+/**
+ * @brief   Kinetis CPUs have a maximum number of 5 hardware chip select lines
+ */
+#define SPI_HWCS_NUMOF      (5)
+
+/**
+ * @brief   This CPU makes use of the following shared SPI functions
+ * @{
+ */
+#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
+#define PERIPH_SPI_NEEDS_TRANSFER_REG
+#define PERIPH_SPI_NEEDS_TRANSFER_REGS
+/** @} */
+
 #ifndef DOXYGEN
 /**
  * @brief   Override GPIO modes
@@ -88,7 +110,7 @@ typedef enum {
  *
  * To combine values just aggregate them using a logical OR.
  */
-enum {
+typedef enum {
     GPIO_AF_ANALOG = PORT_PCR_MUX(0),       /**< use pin as analog input */
     GPIO_AF_GPIO   = PORT_PCR_MUX(1),       /**< use pin as GPIO */
     GPIO_AF_2      = PORT_PCR_MUX(2),       /**< use alternate function 2 */
@@ -100,7 +122,7 @@ enum {
     GPIO_PCR_OD    = (PORT_PCR_ODE_MASK),   /**< open-drain mode */
     GPIO_PCR_PD    = (PORT_PCR_PE_MASK),    /**< enable pull-down */
     GPIO_PCR_PU    = (PORT_PCR_PE_MASK | PORT_PCR_PS_MASK)  /**< enable PU */
-};
+} gpio_pcr_t;
 
 #ifndef DOXYGEN
 /**
@@ -161,6 +183,21 @@ typedef enum {
 /** @} */
 #endif /* ndef DOXYGEN */
 
+#ifndef DOXYGEN
+/**
+ * @brief   Override default ADC resolution values
+ * @{
+ */
+#define HAVE_SPI_MODE_T
+typedef enum {
+    SPI_MODE_0 = 0,                                         /**< CPOL=0, CPHA=0 */
+    SPI_MODE_1 = (SPI_CTAR_CPHA_MASK),                      /**< CPOL=0, CPHA=1 */
+    SPI_MODE_2 = (SPI_CTAR_CPOL_MASK),                      /**< CPOL=1, CPHA=0 */
+    SPI_MODE_3 = (SPI_CTAR_CPOL_MASK | SPI_CTAR_CPHA_MASK)  /**< CPOL=1, CPHA=1 */
+} spi_mode_t;
+/** @} */
+#endif /* ndef DOXYGEN */
+
 /**
  * @brief   CPU specific ADC configuration
  */
@@ -208,15 +245,28 @@ typedef struct {
  */
 typedef struct {
     FTM_Type* ftm;          /**< used FTM */
-    struct {                /**< logical channel configuration */
+    struct {
         gpio_t pin;         /**< GPIO pin used, set to GPIO_UNDEF */
         uint8_t af;         /**< alternate function mapping */
         uint8_t ftm_chan;   /**< the actual FTM channel used */
-    } chan[PWM_CHAN_MAX];
+    } chan[PWM_CHAN_MAX];   /**< logical channel configuration */
     uint8_t chan_numof;     /**< number of actually configured channels */
     uint8_t ftm_num;        /**< FTM number used */
 } pwm_conf_t;
 
+/**
+ * @brief   SPI module configuration options
+ */
+typedef struct {
+    SPI_Type *dev;                      /**< SPI device to use */
+    gpio_t pin_miso;                    /**< MISO pin used */
+    gpio_t pin_mosi;                    /**< MOSI pin used */
+    gpio_t pin_clk;                     /**< CLK pin used */
+    gpio_t pin_cs[SPI_HWCS_NUMOF];      /**< pins used for HW cs lines */
+    gpio_pcr_t pcr;                     /**< alternate pin function values */
+    uint32_t simmask;                   /**< bit in the SIM register */
+} spi_conf_t;
+
 /**
  * @brief   Possible timer module types
  */
@@ -227,9 +277,11 @@ enum {
 
 /**
  * @brief   Hardware timer type-specific device macros
+ * @{
  */
 #define TIMER_PIT_DEV(x)   (TIMER_DEV(0 + (x)))
 #define TIMER_LPTMR_DEV(x) (TIMER_DEV(PIT_NUMOF + (x)))
+/** @} */
 
 /**
  * @brief   CPU internal function for initializing PORTs
diff --git a/cpu/kinetis_common/periph/spi.c b/cpu/kinetis_common/periph/spi.c
index a03b63d72b5d20401bca27447ddc08520e565a35..a781e423befd1635a484b7df03121122e4aa7d9a 100644
--- a/cpu/kinetis_common/periph/spi.c
+++ b/cpu/kinetis_common/periph/spi.c
@@ -1,28 +1,14 @@
 /*
  * Copyright (C) 2014 Hamburg University of Applied Sciences
- * Copyright (C) 2014 PHYTEC Messtechnik GmbH
- * Copyright (C) 2015 Eistec AB
+ *               2014 PHYTEC Messtechnik GmbH
+ *               2015 Eistec AB
+ *               2016 Freie Universität Berlin
  *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
  */
 
-#include <stdio.h>
-
-#include "board.h"
-#include "cpu.h"
-#include "periph/spi.h"
-#include "periph_conf.h"
-#include "mutex.h"
-
-#define ENABLE_DEBUG (0)
-#include "debug.h"
-
-#ifndef KINETIS_SPI_USE_HW_CS
-#define KINETIS_SPI_USE_HW_CS   0
-#endif
-
 /**
  * @ingroup     cpu_kinetis_common_spi
  *
@@ -34,1541 +20,179 @@
  * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
  * @author      Johann Fischer <j.fischer@phytec.de>
  * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  *
  * @}
  */
 
-/* guard this file in case no SPI device is defined */
-#if SPI_NUMOF
-
-#if SPI_0_EN
-#ifdef SPI_0_PORT
-#define SPI_0_SCK_PORT          SPI_0_PORT
-#define SPI_0_SOUT_PORT         SPI_0_PORT
-#define SPI_0_SIN_PORT          SPI_0_PORT
-#define SPI_0_PCS0_PORT         SPI_0_PORT
-#endif
-
-#ifdef SPI_0_PORT_CLKEN
-#define SPI_0_SCK_PORT_CLKEN    SPI_0_PORT_CLKEN
-#define SPI_0_SOUT_PORT_CLKEN   SPI_0_PORT_CLKEN
-#define SPI_0_SIN_PORT_CLKEN    SPI_0_PORT_CLKEN
-#define SPI_0_PCS0_PORT_CLKEN   SPI_0_PORT_CLKEN
-#endif
-
-#ifdef SPI_0_AF
-#define SPI_0_SCK_AF            SPI_0_AF
-#define SPI_0_SOUT_AF           SPI_0_AF
-#define SPI_0_SIN_AF            SPI_0_AF
-#define SPI_0_PCS0_AF           SPI_0_AF
-#endif
-
-#ifndef SPI_0_TCSC_FREQ
-#define SPI_0_TCSC_FREQ    (0)
-#endif
-
-#ifndef SPI_0_TASC_FREQ
-#define SPI_0_TASC_FREQ    (0)
-#endif
-
-#ifndef SPI_0_TDT_FREQ
-#define SPI_0_TDT_FREQ     (0)
-#endif
-#endif /* SPI_0_EN */
-
-#if SPI_1_EN
-#ifdef SPI_1_PORT
-#define SPI_1_SCK_PORT          SPI_1_PORT
-#define SPI_1_SOUT_PORT         SPI_1_PORT
-#define SPI_1_SIN_PORT          SPI_1_PORT
-#define SPI_1_PCS0_PORT         SPI_1_PORT
-#endif
-
-#ifdef SPI_1_PORT_CLKEN
-#define SPI_1_SCK_PORT_CLKEN    SPI_1_PORT_CLKEN
-#define SPI_1_SOUT_PORT_CLKEN   SPI_1_PORT_CLKEN
-#define SPI_1_SIN_PORT_CLKEN    SPI_1_PORT_CLKEN
-#define SPI_1_PCS0_PORT_CLKEN   SPI_1_PORT_CLKEN
-#endif
-
-#ifdef SPI_1_AF
-#define SPI_1_SCK_AF            SPI_1_AF
-#define SPI_1_SOUT_AF           SPI_1_AF
-#define SPI_1_SIN_AF            SPI_1_AF
-#define SPI_1_PCS0_AF           SPI_1_AF
-#endif
-
-#ifndef SPI_1_TCSC_FREQ
-#define SPI_1_TCSC_FREQ    (0)
-#endif
-
-#ifndef SPI_1_TASC_FREQ
-#define SPI_1_TASC_FREQ    (0)
-#endif
-
-#ifndef SPI_1_TDT_FREQ
-#define SPI_1_TDT_FREQ     (0)
-#endif
-#endif /* SPI_1_EN */
-
-#if SPI_2_EN
-#ifdef SPI_2_PORT
-#define SPI_2_SCK_PORT          SPI_2_PORT
-#define SPI_2_SOUT_PORT         SPI_2_PORT
-#define SPI_2_SIN_PORT          SPI_2_PORT
-#define SPI_2_PCS0_PORT         SPI_2_PORT
-#endif
-
-#ifdef SPI_2_PORT_CLKEN
-#define SPI_2_SCK_PORT_CLKEN    SPI_2_PORT_CLKEN
-#define SPI_2_SOUT_PORT_CLKEN   SPI_2_PORT_CLKEN
-#define SPI_2_SIN_PORT_CLKEN    SPI_2_PORT_CLKEN
-#define SPI_2_PCS0_PORT_CLKEN   SPI_2_PORT_CLKEN
-#endif
-
-#ifdef SPI_2_AF
-#define SPI_2_SCK_AF            SPI_2_AF
-#define SPI_2_SOUT_AF           SPI_2_AF
-#define SPI_2_SIN_AF            SPI_2_AF
-#define SPI_2_PCS0_AF           SPI_2_AF
-#endif
-
-#ifndef SPI_2_TCSC_FREQ
-#define SPI_2_TCSC_FREQ    (0)
-#endif
-
-#ifndef SPI_2_TASC_FREQ
-#define SPI_2_TASC_FREQ    (0)
-#endif
-
-#ifndef SPI_2_TDT_FREQ
-#define SPI_2_TDT_FREQ     (0)
-#endif
-#endif /* SPI_2_EN */
-
-#if SPI_3_EN
-#ifdef SPI_3_PORT
-#define SPI_3_SCK_PORT          SPI_3_PORT
-#define SPI_3_SOUT_PORT         SPI_3_PORT
-#define SPI_3_SIN_PORT          SPI_3_PORT
-#define SPI_3_PCS0_PORT         SPI_3_PORT
-#endif
-
-#ifdef SPI_3_PORT_CLKEN
-#define SPI_3_SCK_PORT_CLKEN    SPI_3_PORT_CLKEN
-#define SPI_3_SOUT_PORT_CLKEN   SPI_3_PORT_CLKEN
-#define SPI_3_SIN_PORT_CLKEN    SPI_3_PORT_CLKEN
-#define SPI_3_PCS0_PORT_CLKEN   SPI_3_PORT_CLKEN
-#endif
-
-#ifdef SPI_3_AF
-#define SPI_3_SCK_AF            SPI_3_AF
-#define SPI_3_SOUT_AF           SPI_3_AF
-#define SPI_3_SIN_AF            SPI_3_AF
-#define SPI_3_PCS0_AF           SPI_3_AF
-#endif
-
-#ifndef SPI_3_TCSC_FREQ
-#define SPI_3_TCSC_FREQ    (0)
-#endif
-
-#ifndef SPI_3_TASC_FREQ
-#define SPI_3_TASC_FREQ    (0)
-#endif
-
-#ifndef SPI_3_TDT_FREQ
-#define SPI_3_TDT_FREQ     (0)
-#endif
-#endif /* SPI_3_EN */
-
-#if SPI_4_EN
-#ifdef SPI_4_PORT
-#define SPI_4_SCK_PORT          SPI_4_PORT
-#define SPI_4_SOUT_PORT         SPI_4_PORT
-#define SPI_4_SIN_PORT          SPI_4_PORT
-#define SPI_4_PCS0_PORT         SPI_4_PORT
-#endif
-
-#ifdef SPI_4_PORT_CLKEN
-#define SPI_4_SCK_PORT_CLKEN    SPI_4_PORT_CLKEN
-#define SPI_4_SOUT_PORT_CLKEN   SPI_4_PORT_CLKEN
-#define SPI_4_SIN_PORT_CLKEN    SPI_4_PORT_CLKEN
-#define SPI_4_PCS0_PORT_CLKEN   SPI_4_PORT_CLKEN
-#endif
-
-#ifdef SPI_4_AF
-#define SPI_4_SCK_AF            SPI_4_AF
-#define SPI_4_SOUT_AF           SPI_4_AF
-#define SPI_4_SIN_AF            SPI_4_AF
-#define SPI_4_PCS0_AF           SPI_4_AF
-#endif
-
-#ifndef SPI_4_TCSC_FREQ
-#define SPI_4_TCSC_FREQ    (0)
-#endif
-
-#ifndef SPI_4_TASC_FREQ
-#define SPI_4_TASC_FREQ    (0)
-#endif
-
-#ifndef SPI_4_TDT_FREQ
-#define SPI_4_TDT_FREQ     (0)
-#endif
-#endif /* SPI_4_EN */
-
-#if SPI_5_EN
-#ifdef SPI_5_PORT
-#define SPI_5_SCK_PORT          SPI_5_PORT
-#define SPI_5_SOUT_PORT         SPI_5_PORT
-#define SPI_5_SIN_PORT          SPI_5_PORT
-#define SPI_5_PCS0_PORT         SPI_5_PORT
-#endif
-
-#ifdef SPI_5_PORT_CLKEN
-#define SPI_5_SCK_PORT_CLKEN    SPI_5_PORT_CLKEN
-#define SPI_5_SOUT_PORT_CLKEN   SPI_5_PORT_CLKEN
-#define SPI_5_SIN_PORT_CLKEN    SPI_5_PORT_CLKEN
-#define SPI_5_PCS0_PORT_CLKEN   SPI_5_PORT_CLKEN
-#endif
-
-#ifdef SPI_5_AF
-#define SPI_5_SCK_AF            SPI_5_AF
-#define SPI_5_SOUT_AF           SPI_5_AF
-#define SPI_5_SIN_AF            SPI_5_AF
-#define SPI_5_PCS0_AF           SPI_5_AF
-#endif
-
-#ifndef SPI_5_TCSC_FREQ
-#define SPI_5_TCSC_FREQ    (0)
-#endif
-
-#ifndef SPI_5_TASC_FREQ
-#define SPI_5_TASC_FREQ    (0)
-#endif
-
-#ifndef SPI_5_TDT_FREQ
-#define SPI_5_TDT_FREQ     (0)
-#endif
-#endif /* SPI_5_EN */
-
-#if SPI_6_EN
-#ifdef SPI_6_PORT
-#define SPI_6_SCK_PORT          SPI_6_PORT
-#define SPI_6_SOUT_PORT         SPI_6_PORT
-#define SPI_6_SIN_PORT          SPI_6_PORT
-#define SPI_6_PCS0_PORT         SPI_6_PORT
-#endif
-
-#ifdef SPI_6_PORT_CLKEN
-#define SPI_6_SCK_PORT_CLKEN    SPI_6_PORT_CLKEN
-#define SPI_6_SOUT_PORT_CLKEN   SPI_6_PORT_CLKEN
-#define SPI_6_SIN_PORT_CLKEN    SPI_6_PORT_CLKEN
-#define SPI_6_PCS0_PORT_CLKEN   SPI_6_PORT_CLKEN
-#endif
-
-#ifdef SPI_6_AF
-#define SPI_6_SCK_AF            SPI_6_AF
-#define SPI_6_SOUT_AF           SPI_6_AF
-#define SPI_6_SIN_AF            SPI_6_AF
-#define SPI_6_PCS0_AF           SPI_6_AF
-#endif
-
-#ifndef SPI_6_TCSC_FREQ
-#define SPI_6_TCSC_FREQ    (0)
-#endif
-
-#ifndef SPI_6_TASC_FREQ
-#define SPI_6_TASC_FREQ    (0)
-#endif
-
-#ifndef SPI_6_TDT_FREQ
-#define SPI_6_TDT_FREQ     (0)
-#endif
-#endif /* SPI_6_EN */
-
-#if SPI_7_EN
-#ifdef SPI_7_PORT
-#define SPI_7_SCK_PORT          SPI_7_PORT
-#define SPI_7_SOUT_PORT         SPI_7_PORT
-#define SPI_7_SIN_PORT          SPI_7_PORT
-#define SPI_7_PCS0_PORT         SPI_7_PORT
-#endif
-
-#ifdef SPI_7_PORT_CLKEN
-#define SPI_7_SCK_PORT_CLKEN    SPI_7_PORT_CLKEN
-#define SPI_7_SOUT_PORT_CLKEN   SPI_7_PORT_CLKEN
-#define SPI_7_SIN_PORT_CLKEN    SPI_7_PORT_CLKEN
-#define SPI_7_PCS0_PORT_CLKEN   SPI_7_PORT_CLKEN
-#endif
-
-#ifdef SPI_7_AF
-#define SPI_7_SCK_AF            SPI_7_AF
-#define SPI_7_SOUT_AF           SPI_7_AF
-#define SPI_7_SIN_AF            SPI_7_AF
-#define SPI_7_PCS0_AF           SPI_7_AF
-#endif
-
-#ifndef SPI_7_TCSC_FREQ
-#define SPI_7_TCSC_FREQ    (0)
-#endif
-
-#ifndef SPI_7_TASC_FREQ
-#define SPI_7_TASC_FREQ    (0)
-#endif
-
-#ifndef SPI_7_TDT_FREQ
-#define SPI_7_TDT_FREQ     (0)
-#endif
-#endif /* SPI_7_EN */
-
-#define KINETIS_CFG_SPI_IO(num)    \
-            spi_dev = SPI_ ## num ## _DEV;\
-            module_clock = SPI_ ## num ## _FREQ;\
-            tcsc_freq = SPI_ ## num ## _TCSC_FREQ;\
-            tasc_freq = SPI_ ## num ## _TASC_FREQ;\
-            tdt_freq = SPI_ ## num ## _TDT_FREQ;\
-            ctas = SPI_ ## num ## _CTAS;\
-            /* enable clocks */\
-            SPI_ ## num ## _CLKEN();\
-            SPI_ ## num ## _SCK_PORT_CLKEN();\
-            SPI_ ## num ## _SOUT_PORT_CLKEN();\
-            SPI_ ## num ## _SIN_PORT_CLKEN();\
-            /* Set PORT to AF mode */\
-            SPI_ ## num ## _SCK_PORT->PCR[SPI_ ## num ## _SCK_PIN] =\
-                PORT_PCR_MUX(SPI_ ## num ## _SCK_AF);\
-            SPI_ ## num ## _SOUT_PORT->PCR[SPI_ ## num ## _SOUT_PIN] =\
-                PORT_PCR_MUX(SPI_ ## num ## _SOUT_AF);\
-            SPI_ ## num ## _SIN_PORT->PCR[SPI_ ## num ## _SIN_PIN] =\
-                PORT_PCR_MUX(SPI_ ## num ## _SIN_AF);\
-            if (KINETIS_SPI_USE_HW_CS) {\
-                SPI_ ## num ## _PCS0_PORT_CLKEN();\
-                SPI_ ## num ## _PCS0_PORT->PCR[SPI_ ## num ## _PCS0_PIN] =\
-                    PORT_PCR_MUX(SPI_ ## num ## _PCS0_AF);\
-            }
-
-/**
- * @brief Array holding one pre-initialized mutex for each hardware SPI device
- */
-/* We try to avoid adding duplicate entries with the same index by comparing the
- * SPI_x_INDEX macros, the #if statements become quite long though.
- *
- * If not checking for multiple initializations GCC will warn about it
- * but the binary still works. It does look strange in the preprocessed output, however.
- *
- * The warning message is:
- * warning: initialized field overwritten [-Woverride-init]
- * warning: (near initialization for ‘locks[0]’) [-Woverride-init]
- *
- * Example of preprocessed source:
- * static mutex_t locks[] = {
- *     [0] = { 0, { ((void *)0) } },
- *     [1] = { 0, { ((void *)0) } },
- *     [0] = { 0, { ((void *)0) } }, // index [0] is given (the same, again) initial value.
- * };
- */
+#include "cpu.h"
+#include "mutex.h"
+#include "assert.h"
+#include "periph/spi.h"
 
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0_INDEX] = MUTEX_INIT,
-#endif
-#if SPI_1_EN && (SPI_1_INDEX != SPI_0_INDEX)
-    [SPI_1_INDEX] = MUTEX_INIT,
-#endif
-#if SPI_2_EN && (SPI_2_INDEX != SPI_0_INDEX) && (SPI_2_INDEX != SPI_1_INDEX)
-    [SPI_2_INDEX] = MUTEX_INIT,
-#endif
-#if SPI_3_EN && (SPI_3_INDEX != SPI_0_INDEX) && (SPI_3_INDEX != SPI_1_INDEX) \
-    && (SPI_3_INDEX != SPI_2_INDEX)
-    [SPI_3_INDEX] = MUTEX_INIT,
-#endif
-#if SPI_4_EN && (SPI_4_INDEX != SPI_0_INDEX) && (SPI_4_INDEX != SPI_1_INDEX) \
-    && (SPI_4_INDEX != SPI_2_INDEX) && (SPI_4_INDEX != SPI_3_INDEX)
-    [SPI_4_INDEX] = MUTEX_INIT,
-#endif
-#if SPI_5_EN && (SPI_5_INDEX != SPI_0_INDEX) && (SPI_5_INDEX != SPI_1_INDEX) \
-    && (SPI_5_INDEX != SPI_2_INDEX) && (SPI_5_INDEX != SPI_3_INDEX) \
-    && (SPI_5_INDEX != SPI_4_INDEX)
-    [SPI_5_INDEX] = MUTEX_INIT,
-#endif
-#if SPI_6_EN && (SPI_6_INDEX != SPI_0_INDEX) && (SPI_6_INDEX != SPI_1_INDEX) \
-    && (SPI_6_INDEX != SPI_2_INDEX) && (SPI_6_INDEX != SPI_3_INDEX) \
-    && (SPI_6_INDEX != SPI_4_INDEX) && (SPI_6_INDEX != SPI_5_INDEX)
-    [SPI_6_INDEX] = MUTEX_INIT,
-#endif
-#if SPI_7_EN && (SPI_7_INDEX != SPI_0_INDEX) && (SPI_7_INDEX != SPI_1_INDEX) \
-    && (SPI_7_INDEX != SPI_2_INDEX) && (SPI_7_INDEX != SPI_3_INDEX) \
-    && (SPI_7_INDEX != SPI_4_INDEX) && (SPI_7_INDEX != SPI_5_INDEX) \
-    && (SPI_7_INDEX != SPI_6_INDEX)
-    [SPI_7_INDEX] = MUTEX_INIT,
-#endif
-};
+#define ENABLE_DEBUG        (0)
+#include "debug.h"
 
 /**
- * @brief Array of pointers that map RIOT SPI device number to actual hardware
- * module lock.
- *
- * Every RIOT device shares the bus lock with any other bus devices for the same
- * hardware module. This allows us to let two RIOT devices point to the same
- * hardware but using different CTAR registers for timing information.
+ * @brief   We use this mask to differentiate between SPI_HWCS() and GPIO_PIN()
  */
-static mutex_t *locks_map[] = {
-#if SPI_0_EN
-    [SPI_0] = &locks[SPI_0_INDEX],
-#endif
-#if SPI_1_EN
-    [SPI_1] = &locks[SPI_1_INDEX],
-#endif
-#if SPI_2_EN
-    [SPI_2] = &locks[SPI_2_INDEX],
-#endif
-#if SPI_3_EN
-    [SPI_3] = &locks[SPI_3_INDEX],
-#endif
-#if SPI_4_EN
-    [SPI_4] = &locks[SPI_4_INDEX],
-#endif
-#if SPI_5_EN
-    [SPI_5] = &locks[SPI_5_INDEX],
-#endif
-#if SPI_6_EN
-    [SPI_6] = &locks[SPI_6_INDEX],
-#endif
-#if SPI_7_EN
-    [SPI_7] = &locks[SPI_7_INDEX],
-#endif
-};
-
-typedef struct {
-    char(*cb)(char data);
-} spi_state_t;
-
-static inline void irq_handler_transfer(SPI_Type *spi, spi_t dev);
-
-static spi_state_t spi_config[SPI_NUMOF];
-
-#define SPI_IDLE_DATA (0xff)
+#define SWCS_MASK           (0xfff0)
 
 /**
- * @brief Helper function for finding optimal baud rate scalers.
- *
- * Find the prescaler and scaler settings that will yield a clock frequency
- * as close as possible (but not above) the target frequency, given the module
- * runs at module_clock Hz.
- *
- * Hardware properties (Baud rate configuration):
- * Possible prescalers: 2, 3, 5, 7
- * Possible scalers: 2, 4, 6 (sic!), 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768
- *
- * SCK baud rate = (f_BUS/PBR) x [(1+DBR)/BR]
- *
- * where PBR is the prescaler, BR is the scaler, DBR is the Double BaudRate bit.
- *
- * @note We are not using the DBR bit because it may affect the SCK duty cycle.
- *
- * @param module_clock Module clock frequency (e.g. F_BUS)
- * @param target_clock Desired baud rate
- * @param closest_prescaler pointer where to write the optimal prescaler index.
- * @param closest_scaler pointer where to write the optimal scaler index.
- *
- * @return The actual achieved frequency on success
- * @return Less than 0 on error.
+ * @brief   Allocation device locks
  */
-static long find_closest_baudrate_scalers(const uint32_t module_clock, const long target_clock,
-        uint8_t *closest_prescaler, uint8_t *closest_scaler)
-{
-    uint8_t i;
-    uint8_t k;
-    long freq;
-    static const uint8_t num_scalers = 16;
-    static const uint8_t num_prescalers = 4;
-    static const int br_scalers[16] = {
-        2,     4,     6,     8,    16,    32,    64,   128,
-        256,   512,  1024,  2048,  4096,  8192, 16384, 32768
-    };
-    static const int br_prescalers[4] = {2, 3, 5, 7};
-
-    long closest_frequency = -1;
-
-    /* Test all combinations until we arrive close to the target clock */
-    for (i = 0; i < num_prescalers; ++i) {
-        for (k = 0; k < num_scalers; ++k) {
-            freq = module_clock / (br_scalers[k] * br_prescalers[i]);
-
-            if (freq <= target_clock) {
-                /* Found closest lower frequency at this prescaler setting,
-                 * compare to the best result */
-                if (closest_frequency < freq) {
-                    closest_frequency = freq;
-                    *closest_scaler = k;
-                    *closest_prescaler = i;
-                }
-
-                break;
-            }
-        }
-    }
+static mutex_t locks[SPI_NUMOF];
 
-    if (closest_frequency < 0) {
-        /* Error, no solution found, this line is never reachable with current
-         * hardware settings unless a _very_ low target clock is requested.
-         * (scaler_max * prescaler_max) = 229376 => target_min@100MHz = 435 Hz*/
-        return -1;
-    }
-
-    return closest_frequency;
-}
-
-/**
- * @brief Helper function for finding optimal delay scalers.
- *
- * Find the prescaler and scaler settings that will yield a delay timing
- * as close as possible (but not shorter than) the target delay, given the
- * module runs at module_clock Hz.
- *
- * Hardware properties (delay configuration):
- * Possible prescalers: 1, 3, 5, 7
- * Possible scalers: 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536
- *
- * delay = (1/f_BUS) x prescaler x scaler
- *
- * Because we want to do this using only integers, the target_freq parameter is
- * the reciprocal of the delay time.
- *
- * @param module_clock Module clock frequency (e.g. F_BUS)
- * @param target_freq Reciprocal (i.e. 1/t [Hz], frequency) of the desired delay time.
- * @param closest_prescaler pointer where to write the optimal prescaler index.
- * @param closest_scaler pointer where to write the optimal scaler index.
- *
- * @return The actual achieved frequency on success
- * @return Less than 0 on error.
- */
-static long find_closest_delay_scalers(const uint32_t module_clock, const long target_freq,
-                                      uint8_t *closest_prescaler, uint8_t *closest_scaler)
+static inline SPI_Type *dev(spi_t bus)
 {
-    uint8_t i;
-    uint8_t k;
-    long freq;
-    int prescaler;
-    int scaler;
-    static const uint8_t num_scalers = 16;
-    static const uint8_t num_prescalers = 4;
-
-    long closest_frequency = -1;
-
-    /* Test all combinations until we arrive close to the target clock */
-    for (i = 0; i < num_prescalers; ++i) {
-        for (k = 0; k < num_scalers; ++k) {
-            prescaler = (i * 2) + 1;
-            scaler = (1 << (k + 1)); /* 2^(k+1) */
-            freq = module_clock / (prescaler * scaler);
-
-            if (freq <= target_freq) {
-                /* Found closest lower frequency at this prescaler setting,
-                 * compare to the best result */
-                if (closest_frequency < freq) {
-                    closest_frequency = freq;
-                    *closest_scaler = k;
-                    *closest_prescaler = i;
-                }
-
-                break;
-            }
-        }
-    }
-
-    if (closest_frequency < 0) {
-        /* Error, no solution found, this line is never reachable with current
-         * hardware settings unless a _very_ low target clock is requested.
-         * (scaler_max * prescaler_max) = 458752 */
-        return -1;
-    }
-
-    return closest_frequency;
+    return spi_config[bus].dev;
 }
 
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
+static inline void poweron(spi_t bus)
 {
-    SPI_Type *spi_dev;
-    uint8_t br_prescaler = 0xff;
-    uint8_t br_scaler = 0xff;
-    uint8_t prescaler_tmp = 0xff;
-    uint8_t scaler_tmp = 0xff;
-    uint32_t ctas = 0;
-    uint32_t ctar = 0;
-    uint32_t br_desired;
-    uint32_t module_clock;
-    uint32_t tcsc_freq;
-    uint32_t tasc_freq;
-    uint32_t tdt_freq;
-
-    switch (speed) {
-        case SPI_SPEED_100KHZ:
-            br_desired = 100000;
-            break;
-
-        case SPI_SPEED_400KHZ:
-            br_desired = 400000;
+    switch((uint32_t)dev(bus)) {
+        case (uint32_t)SPI0:
+        case (uint32_t)SPI1:
+            SIM->SCGC6 |= (spi_config[bus].simmask);
             break;
-
-        case SPI_SPEED_1MHZ:
-            br_desired = 1000000;
-            break;
-
-        case SPI_SPEED_5MHZ:
-            br_desired = 5000000;
-            break;
-
-        case SPI_SPEED_10MHZ:
-            br_desired = 10000000;
+#ifdef SPI2
+        case (uint32_t)SPI2:
+            SIM->SCGC3 |= (spi_config[bus].simmask);
             break;
-
-        default:
-            return -2;
+#endif
     }
+}
 
-    switch (dev) {
-#if SPI_0_EN
-
-        case SPI_0:
-            KINETIS_CFG_SPI_IO(0);
-            break;
-#endif /* SPI_0_EN */
-
-#if SPI_1_EN
-
-        case SPI_1:
-            KINETIS_CFG_SPI_IO(1);
-            break;
-#endif /* SPI_1_EN */
-
-#if SPI_2_EN
-
-        case SPI_2:
-            KINETIS_CFG_SPI_IO(2);
-            break;
-#endif /* SPI_2_EN */
-
-#if SPI_3_EN
-
-        case SPI_3:
-            KINETIS_CFG_SPI_IO(3);
-            break;
-#endif /* SPI_3_EN */
-
-#if SPI_4_EN
-
-        case SPI_4:
-            KINETIS_CFG_SPI_IO(4);
-            break;
-#endif /* SPI_4_EN */
-
-#if SPI_5_EN
-
-        case SPI_5:
-            KINETIS_CFG_SPI_IO(5);
-            break;
-#endif /* SPI_5_EN */
-
-#if SPI_6_EN
-
-        case SPI_6:
-            KINETIS_CFG_SPI_IO(6);
+static inline void poweroff(spi_t bus)
+{
+    switch((uint32_t)dev(bus)) {
+        case (uint32_t)SPI0:
+        case (uint32_t)SPI1:
+            SIM->SCGC6 &= ~(spi_config[bus].simmask);
             break;
-#endif /* SPI_6_EN */
-
-#if SPI_7_EN
-
-        case SPI_7:
-            KINETIS_CFG_SPI_IO(7);
+#ifdef SPI2
+        case (uint32_t)SPI2:
+            SIM->SCGC3 &= ~(spi_config[bus].simmask);
             break;
-#endif /* SPI_7_EN */
-
-        default:
-            return -1;
+#endif
     }
+}
 
-    /* Find baud rate scaler and prescaler settings */
-    if (find_closest_baudrate_scalers(module_clock, br_desired,
-                                      &br_prescaler, &br_scaler) < 0) {
-        /* Desired baud rate is too low to be reachable at current module clock frequency. */
-        return -2;
-    }
+void spi_init(spi_t bus)
+{
+    /* make sure given bus device is valid */
+    assert(bus < SPI_NUMOF);
 
-    ctar |= SPI_CTAR_PBR(br_prescaler) | SPI_CTAR_BR(br_scaler);
+    /* initialize the buses lock */
+    mutex_init(&locks[bus]);
+    /* trigger pin initialization */
+    spi_init_pins(bus);
+    /* power on the bus temporarily */
+    poweron(bus);
 
-    /* Find the other delay divisors */
-    /* tCSC */
-    if (tcsc_freq == 0) {
-        /* Default to same as baud rate if set to zero. */
-        tcsc_freq = br_desired;
-    }
+    /* make the base configuration: configure as SPI master, set CS inactive
+     * state (for HWCS lines) and clear FIFO counters and disable FIFOs */
+    dev(bus)->MCR = (SPI_MCR_MSTR_MASK | SPI_MCR_PCSIS_MASK |
+                     SPI_MCR_CLR_RXF_MASK | SPI_MCR_CLR_TXF_MASK |
+                     SPI_MCR_DIS_RXF_MASK | SPI_MCR_DIS_TXF_MASK |
+                     SPI_MCR_DOZE_MASK | SPI_MCR_HALT_MASK | SPI_MCR_MDIS_MASK);
 
-    if (find_closest_delay_scalers(module_clock, tcsc_freq,
-                                   &prescaler_tmp, &scaler_tmp) < 0) {
-        /* failed to find a solution */
-        return -2;
-    }
+    /* disable all DMA and interrupt requests */
+    dev(bus)->RSER = 0;
 
-    ctar |= SPI_CTAR_PCSSCK(prescaler_tmp) | SPI_CTAR_CSSCK(scaler_tmp);
+    /* and power off the bus until it is actually used */
+    poweroff(bus);
+}
 
-    /* tASC */
-    if (tasc_freq == 0) {
-        /* Default to same as baud rate if set to zero. */
-        tasc_freq = br_desired;
-    }
+void spi_init_pins(spi_t bus)
+{
+    gpio_init_port(spi_config[bus].pin_miso, spi_config[bus].pcr);
+    gpio_init_port(spi_config[bus].pin_mosi, spi_config[bus].pcr);
+    gpio_init_port(spi_config[bus].pin_clk , spi_config[bus].pcr);
+}
 
-    if (find_closest_delay_scalers(module_clock, tasc_freq,
-                                   &prescaler_tmp, &scaler_tmp) < 0) {
-        /* failed to find a solution */
-        return -2;
+int spi_init_cs(spi_t bus, spi_cs_t cs)
+{
+    if (bus >= SPI_NUMOF) {
+        return SPI_NODEV;
     }
-
-    ctar |= SPI_CTAR_PASC(prescaler_tmp) | SPI_CTAR_ASC(scaler_tmp);
-
-    /* tDT */
-    if (tdt_freq == 0) {
-        /* Default to same as baud rate if set to zero. */
-        tdt_freq = br_desired;
+    if (cs == SPI_CS_UNDEF) {
+        return SPI_NOCS;
     }
 
-    if (find_closest_delay_scalers(module_clock, tdt_freq,
-                                   &prescaler_tmp, &scaler_tmp) < 0) {
-        /* failed to find a solution */
-        return -2;
+    if (cs & SWCS_MASK) {
+        gpio_init((gpio_t)cs, GPIO_OUT);
     }
-
-    ctar |= SPI_CTAR_PDT(prescaler_tmp) | SPI_CTAR_DT(scaler_tmp);
-
-
-    /* Set clock polarity and phase. */
-    switch (conf) {
-        case SPI_CONF_FIRST_RISING:
-            break;
-
-        case SPI_CONF_SECOND_RISING:
-            ctar |= SPI_CTAR_CPHA_MASK;
-            break;
-
-        case SPI_CONF_FIRST_FALLING:
-            ctar |= SPI_CTAR_CPOL_MASK;
-            break;
-
-        case SPI_CONF_SECOND_FALLING:
-            ctar |= SPI_CTAR_CPHA_MASK | SPI_CTAR_CPOL_MASK;
-            break;
-
-        default:
-            return -2;
+    else {
+        if ((cs >= SPI_HWCS_NUMOF) ||
+            (spi_config[bus].pin_cs[cs] == GPIO_UNDEF)) {
+            return SPI_NOCS;
+        }
+        gpio_init_port(spi_config[bus].pin_cs[cs], spi_config[bus].pcr);
     }
 
-    /* Update CTAR register with new timing settings, 8-bit frame size. */
-    spi_dev->CTAR[ctas] = SPI_CTAR_FMSZ(7) | ctar;
+    return SPI_OK;
+}
 
-    /* enable SPI */
-    spi_dev->MCR = SPI_MCR_MSTR_MASK
-                   | SPI_MCR_DOZE_MASK
-                   | SPI_MCR_CLR_TXF_MASK
-                   | SPI_MCR_CLR_RXF_MASK;
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    /* lock and power on the bus */
+    mutex_lock(&locks[bus]);
+    poweron(bus);
 
-    if (KINETIS_SPI_USE_HW_CS) {
-        spi_dev->MCR |= SPI_MCR_PCSIS(1);
-    }
+    /* enable the device */
+    dev(bus)->MCR &= ~(SPI_MCR_HALT_MASK | SPI_MCR_MDIS_MASK);
 
-    spi_dev->RSER = (uint32_t)0;
+    /* configure clock and mode */
+    dev(bus)->CTAR[0] = (mode | SPI_CTAR_FMSZ(7) | spi_clk_config[clk]);
 
-    return 0;
+    return SPI_OK;
 }
 
-int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data))
+void spi_release(spi_t bus)
 {
-    SPI_Type *spi_dev;
+    /* disable, power off, and unlock the bus */
+    dev(bus)->MCR |= (SPI_MCR_HALT_MASK | SPI_MCR_MDIS_MASK);
+    poweroff(bus);
+    mutex_unlock(&locks[bus]);
+}
 
-    switch (dev) {
-#if SPI_0_EN
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
+{
+    uint8_t *out_buf = (uint8_t *)out;
+    uint8_t *in_buf = (uint8_t *)in;
+    uint32_t flags = SPI_PUSHR_CONT_MASK;
 
-        case SPI_0:
-            spi_dev = SPI_0_DEV;
-            /* enable clocks */
-            SPI_0_CLKEN();
-            SPI_0_PCS0_PORT_CLKEN();
-            SPI_0_SCK_PORT_CLKEN();
-            SPI_0_SOUT_PORT_CLKEN();
-            SPI_0_SIN_PORT_CLKEN();
-            /* Set PORT to AF mode */
-            SPI_0_PCS0_PORT->PCR[SPI_0_PCS0_PIN] = PORT_PCR_MUX(SPI_0_PCS0_AF);
-            SPI_0_SCK_PORT->PCR[SPI_0_SCK_PIN] = PORT_PCR_MUX(SPI_0_SCK_AF);
-            SPI_0_SOUT_PORT->PCR[SPI_0_SOUT_PIN] = PORT_PCR_MUX(SPI_0_SOUT_AF);
-            SPI_0_SIN_PORT->PCR[SPI_0_SIN_PIN] = PORT_PCR_MUX(SPI_0_SIN_AF);
-            break;
-#endif /* SPI_0_EN */
+    assert(out_buf || in_buf);
 
-        default:
-            return -1;
+    /* handle chip select */
+    if (cs != SPI_CS_UNDEF) {
+        if (cs & SWCS_MASK) {
+            gpio_clear((gpio_t)cs);
+        }
+        else {
+            flags |= (uint32_t)(1 << (cs + SPI_PUSHR_PCS_SHIFT));
+        }
     }
 
-    /* set frame size, slave mode always uses CTAR0 */
-    spi_dev->CTAR[0] = SPI_CTAR_SLAVE_FMSZ(7);
-
-    /* Set clock polarity and phase. */
-    switch (conf) {
-        case SPI_CONF_FIRST_RISING:
-            spi_dev->CTAR[0] &= ~(SPI_CTAR_CPHA_MASK | SPI_CTAR_CPOL_MASK);
-            break;
-
-        case SPI_CONF_SECOND_RISING:
-            spi_dev->CTAR[0] &= ~(SPI_CTAR_CPOL_MASK);
-            spi_dev->CTAR[0] |= SPI_CTAR_CPHA_MASK;
-            break;
-
-        case SPI_CONF_FIRST_FALLING:
-            spi_dev->CTAR[0] &= ~(SPI_CTAR_CPHA_MASK);
-            spi_dev->CTAR[0] |= SPI_CTAR_CPOL_MASK;
-            break;
+    for (size_t i = 0; i < len; i++) {
+        uint8_t tmp = (out_buf) ? out_buf[i] : 0;
+        if ((i == (len - 1)) && (!cont)) {
+            flags &= ~(SPI_PUSHR_CONT_MASK);
+        }
 
-        case SPI_CONF_SECOND_FALLING:
-            spi_dev->CTAR[0] |= SPI_CTAR_CPHA_MASK | SPI_CTAR_CPOL_MASK;
-            break;
+        while (!(dev(bus)->SR & SPI_SR_TFFF_MASK)) {}
+        dev(bus)->PUSHR = (tmp | flags);
 
-        default:
-            return -2;
+        while (!(dev(bus)->SR & SPI_SR_RXCTR_MASK)) {}
+        tmp = dev(bus)->POPR;
+        if (in_buf) {
+            in_buf[i] = tmp;
+        }
     }
 
-    /* enable SPI */
-    spi_dev->MCR = SPI_MCR_DOZE_MASK
-                   | SPI_MCR_PCSIS(SPI_0_PCS0_ACTIVE_LOW << 0)
-                   | SPI_MCR_CLR_TXF_MASK
-                   | SPI_MCR_CLR_RXF_MASK;
-
-    spi_dev->RSER = (uint32_t)0;
-
-    /* set callback */
-    spi_config[dev].cb = cb;
-
-    return 0;
-}
-
-int spi_acquire(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
+    if ((!cont) && (cs != SPI_CS_UNDEF) && (cs & SWCS_MASK)) {
+        gpio_set((gpio_t)cs);
     }
-
-    mutex_lock(locks_map[dev]);
-    return 0;
-}
-
-int spi_release(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-
-    mutex_unlock(locks_map[dev]);
-    return 0;
-}
-
-static inline uint8_t spi_transfer_internal(SPI_Type *spi_dev, uint32_t flags, uint8_t byte_out)
-{
-    /* Wait until there is space in the TXFIFO */
-    while (!(spi_dev->SR & SPI_SR_TFFF_MASK));
-
-#if KINETIS_SPI_USE_HW_CS
-    spi_dev->PUSHR = flags | SPI_PUSHR_TXDATA(byte_out) | SPI_PUSHR_PCS(1);
-#else
-    spi_dev->PUSHR = flags | SPI_PUSHR_TXDATA(byte_out);
-#endif
-
-    /* Wait until we have received a byte */
-    while (!(spi_dev->SR & SPI_SR_RXCTR_MASK));
-
-    return (uint8_t)spi_dev->POPR;
-}
-
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    SPI_Type *spi_dev;
-    uint8_t byte_in;
-    uint32_t flags;
-
-    /* The chip select lines are expected to be controlled via software in RIOT.
-     * Don't set PCS bits in flags. */
-    switch (dev) {
-#if SPI_0_EN
-
-        case SPI_0:
-            spi_dev = SPI_0_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_0_CTAS) | SPI_PUSHR_EOQ_MASK);
-            break;
-#endif
-
-#if SPI_1_EN
-
-        case SPI_1:
-            spi_dev = SPI_1_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_1_CTAS) | SPI_PUSHR_EOQ_MASK);
-            break;
-#endif
-
-#if SPI_2_EN
-
-        case SPI_2:
-            spi_dev = SPI_2_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_2_CTAS) | SPI_PUSHR_EOQ_MASK);
-            break;
-#endif
-
-#if SPI_3_EN
-
-        case SPI_3:
-            spi_dev = SPI_3_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_3_CTAS) | SPI_PUSHR_EOQ_MASK);
-            break;
-#endif
-
-#if SPI_4_EN
-
-        case SPI_4:
-            spi_dev = SPI_4_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_4_CTAS) | SPI_PUSHR_EOQ_MASK);
-            break;
-#endif
-
-#if SPI_5_EN
-
-        case SPI_5:
-            spi_dev = SPI_5_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_5_CTAS) | SPI_PUSHR_EOQ_MASK);
-            break;
-#endif
-
-#if SPI_6_EN
-
-        case SPI_6:
-            spi_dev = SPI_6_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_6_CTAS) | SPI_PUSHR_EOQ_MASK);
-            break;
-#endif
-
-#if SPI_7_EN
-
-        case SPI_7:
-            spi_dev = SPI_7_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_7_CTAS) | SPI_PUSHR_EOQ_MASK);
-            break;
-#endif
-
-        default:
-            return -1;
-    }
-
-    byte_in = spi_transfer_internal(spi_dev, flags, out);
-
-    /* Clear End-of-Queue status flag */
-    spi_dev->SR = SPI_SR_EOQF_MASK;
-
-    if (in != NULL) {
-        *in = (char)byte_in;
-    }
-
-    return 1;
-}
-
-int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length)
-{
-    SPI_Type *spi_dev;
-    uint8_t byte_in;
-    uint8_t byte_out;
-    uint32_t flags;
-    int i;
-
-    switch (dev) {
-#if SPI_0_EN
-
-        case SPI_0:
-            spi_dev = SPI_0_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_0_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_1_EN
-
-        case SPI_1:
-            spi_dev = SPI_1_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_1_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_2_EN
-
-        case SPI_2:
-            spi_dev = SPI_2_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_2_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_3_EN
-
-        case SPI_3:
-            spi_dev = SPI_3_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_3_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_4_EN
-
-        case SPI_4:
-            spi_dev = SPI_4_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_4_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_5_EN
-
-        case SPI_5:
-            spi_dev = SPI_5_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_5_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_6_EN
-
-        case SPI_6:
-            spi_dev = SPI_6_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_6_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_7_EN
-
-        case SPI_7:
-            spi_dev = SPI_7_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_7_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-        default:
-            return -1;
-    }
-
-    /* Default: send idle data */
-    byte_out = (uint8_t)SPI_IDLE_DATA;
-
-    for (i = 0; i < (int)length; i++) {
-        if (out != NULL) {
-            /* Send given out data */
-            byte_out = (uint8_t)out[i];
-        }
-
-        if (i >= (int)length - 1) {
-            /* Last byte, set End-of-Queue flag, clear Continue flag. */
-            flags &= ~(SPI_PUSHR_CONT_MASK);
-            flags |= SPI_PUSHR_EOQ_MASK;
-        }
-
-        byte_in = spi_transfer_internal(spi_dev, flags, byte_out);
-
-        if (in != NULL) {
-            /* Save input byte to buffer */
-            in[i] = (char)byte_in;
-        }
-    }
-
-    /* Clear End-of-Queue status flag */
-    spi_dev->SR = SPI_SR_EOQF_MASK;
-
-    return i;
 }
-
-int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in)
-{
-    SPI_Type *spi_dev;
-    uint8_t byte_in;
-    uint32_t flags;
-
-    switch (dev) {
-#if SPI_0_EN
-
-        case SPI_0:
-            spi_dev = SPI_0_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_0_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_1_EN
-
-        case SPI_1:
-            spi_dev = SPI_1_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_1_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_2_EN
-
-        case SPI_2:
-            spi_dev = SPI_2_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_2_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_3_EN
-
-        case SPI_3:
-            spi_dev = SPI_3_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_3_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_4_EN
-
-        case SPI_4:
-            spi_dev = SPI_4_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_4_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_5_EN
-
-        case SPI_5:
-            spi_dev = SPI_5_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_5_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_6_EN
-
-        case SPI_6:
-            spi_dev = SPI_6_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_6_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_7_EN
-
-        case SPI_7:
-            spi_dev = SPI_7_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_7_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-        default:
-            return -1;
-    }
-
-    /* Transfer the register address first. */
-    spi_transfer_internal(spi_dev, flags, reg);
-
-    /* Last byte, set End-of-Queue flag, clear Continue flag. */
-    flags &= ~(SPI_PUSHR_CONT_MASK);
-    flags |= SPI_PUSHR_EOQ_MASK;
-
-    /* Transfer the value. */
-    byte_in = spi_transfer_internal(spi_dev, flags, out);
-
-    if (in != NULL) {
-        /* Save input byte to buffer */
-        *in = (char)byte_in;
-    }
-
-    /* Clear End-of-Queue status flag */
-    spi_dev->SR = SPI_SR_EOQF_MASK;
-
-    return 2;
-}
-
-int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length)
-{
-    SPI_Type *spi_dev;
-    uint8_t byte_in;
-    uint8_t byte_out;
-    uint32_t flags;
-    int i;
-
-    switch (dev) {
-#if SPI_0_EN
-
-        case SPI_0:
-            spi_dev = SPI_0_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_0_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_1_EN
-
-        case SPI_1:
-            spi_dev = SPI_1_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_1_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_2_EN
-
-        case SPI_2:
-            spi_dev = SPI_2_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_2_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_3_EN
-
-        case SPI_3:
-            spi_dev = SPI_3_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_3_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_4_EN
-
-        case SPI_4:
-            spi_dev = SPI_4_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_4_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_5_EN
-
-        case SPI_5:
-            spi_dev = SPI_5_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_5_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_6_EN
-
-        case SPI_6:
-            spi_dev = SPI_6_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_6_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-#if SPI_7_EN
-
-        case SPI_7:
-            spi_dev = SPI_7_DEV;
-            flags = (SPI_PUSHR_CTAS(SPI_7_CTAS) | SPI_PUSHR_CONT_MASK);
-            break;
-#endif
-
-        default:
-            return -1;
-    }
-
-    byte_out = reg;
-
-    /* Send register address */
-    spi_transfer_internal(spi_dev, flags, byte_out);
-
-    /* Default: send idle data */
-    byte_out = (uint8_t)SPI_IDLE_DATA;
-
-    for (i = 0; i < (int)length; i++) {
-        if (out != NULL) {
-            /* Send given out data */
-            byte_out = (uint8_t)out[i];
-        }
-
-        if (i >= (int)length - 1) {
-            /* Last byte, set End-of-Queue flag, clear Continue flag. */
-            flags &= ~(SPI_PUSHR_CONT_MASK);
-            flags |= SPI_PUSHR_EOQ_MASK;
-        }
-
-        byte_in = spi_transfer_internal(spi_dev, flags, byte_out);
-
-        if (in != NULL) {
-            /* Save input byte to buffer */
-            in[i] = (char)byte_in;
-        }
-    }
-
-    /* Clear End-of-Queue status flag */
-    spi_dev->SR = SPI_SR_EOQF_MASK;
-
-    return i;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-
-    switch (dev) {
-#if SPI_0_EN
-
-        case SPI_0:
-            SPI_0_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_0_CTAS)
-                               | SPI_PUSHR_EOQ_MASK
-                               | SPI_PUSHR_TXDATA(reset_val);
-            break;
-#endif
-#if SPI_1_EN
-
-        case SPI_1:
-            SPI_1_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_1_CTAS)
-                               | SPI_PUSHR_EOQ_MASK
-                               | SPI_PUSHR_TXDATA(reset_val);
-            break;
-#endif
-#if SPI_2_EN
-
-        case SPI_2:
-            SPI_2_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_2_CTAS)
-                               | SPI_PUSHR_EOQ_MASK
-                               | SPI_PUSHR_TXDATA(reset_val);
-            break;
-#endif
-#if SPI_3_EN
-
-        case SPI_3:
-            SPI_3_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_3_CTAS)
-                               | SPI_PUSHR_EOQ_MASK
-                               | SPI_PUSHR_TXDATA(reset_val);
-            break;
-#endif
-#if SPI_4_EN
-
-        case SPI_4:
-            SPI_4_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_4_CTAS)
-                               | SPI_PUSHR_EOQ_MASK
-                               | SPI_PUSHR_TXDATA(reset_val);
-            break;
-#endif
-#if SPI_5_EN
-
-        case SPI_5:
-            SPI_5_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_5_CTAS)
-                               | SPI_PUSHR_EOQ_MASK
-                               | SPI_PUSHR_TXDATA(reset_val);
-            break;
-#endif
-#if SPI_6_EN
-
-        case SPI_6:
-            SPI_6_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_6_CTAS)
-                               | SPI_PUSHR_EOQ_MASK
-                               | SPI_PUSHR_TXDATA(reset_val);
-            break;
-#endif
-#if SPI_7_EN
-
-        case SPI_7:
-            SPI_7_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_7_CTAS)
-                               | SPI_PUSHR_EOQ_MASK
-                               | SPI_PUSHR_TXDATA(reset_val);
-            break;
-#endif
-    }
-}
-
-void spi_poweron(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-
-        case SPI_0:
-            SPI_0_CLKEN();
-            break;
-#endif
-#if SPI_1_EN
-
-        case SPI_1:
-            SPI_1_CLKEN();
-            break;
-#endif
-#if SPI_2_EN
-
-        case SPI_2:
-            SPI_2_CLKEN();
-            break;
-#endif
-#if SPI_3_EN
-
-        case SPI_3:
-            SPI_3_CLKEN();
-            break;
-#endif
-#if SPI_4_EN
-
-        case SPI_4:
-            SPI_4_CLKEN();
-            break;
-#endif
-#if SPI_5_EN
-
-        case SPI_5:
-            SPI_5_CLKEN();
-            break;
-#endif
-#if SPI_6_EN
-
-        case SPI_6:
-            SPI_6_CLKEN();
-            break;
-#endif
-#if SPI_7_EN
-
-        case SPI_7:
-            SPI_7_CLKEN();
-            break;
-#endif
-    }
-}
-
-void spi_poweroff(spi_t dev)
-{
-    /* Wait until the last byte has been transmitted before turning off
-     * the clock. */
-    switch (dev) {
-#if SPI_0_EN
-
-        case SPI_0:
-            while ((SPI_0_DEV->SR & SPI_SR_TXCTR_MASK) != 0);
-
-            SPI_0_CLKDIS();
-            break;
-#endif
-#if SPI_1_EN
-
-        case SPI_1:
-            while ((SPI_1_DEV->SR & SPI_SR_TXCTR_MASK) != 0);
-
-            SPI_1_CLKDIS();
-            break;
-#endif
-#if SPI_2_EN
-
-        case SPI_2:
-            while ((SPI_2_DEV->SR & SPI_SR_TXCTR_MASK) != 0);
-
-            SPI_2_CLKDIS();
-            break;
-#endif
-#if SPI_3_EN
-
-        case SPI_3:
-            while ((SPI_3_DEV->SR & SPI_SR_TXCTR_MASK) != 0);
-
-            SPI_3_CLKDIS();
-            break;
-#endif
-#if SPI_4_EN
-
-        case SPI_4:
-            while ((SPI_4_DEV->SR & SPI_SR_TXCTR_MASK) != 0);
-
-            SPI_4_CLKDIS();
-            break;
-#endif
-#if SPI_5_EN
-
-        case SPI_5:
-            while ((SPI_5_DEV->SR & SPI_SR_TXCTR_MASK) != 0);
-
-            SPI_5_CLKDIS();
-            break;
-#endif
-#if SPI_6_EN
-
-        case SPI_6:
-            while ((SPI_6_DEV->SR & SPI_SR_TXCTR_MASK) != 0);
-
-            SPI_6_CLKDIS();
-            break;
-#endif
-#if SPI_7_EN
-
-        case SPI_7:
-            while ((SPI_7_DEV->SR & SPI_SR_TXCTR_MASK) != 0);
-
-            SPI_7_CLKDIS();
-            break;
-#endif
-    }
-}
-
-static inline void irq_handler_transfer(SPI_Type *spi, spi_t dev)
-{
-
-    if (spi->SR & SPI_SR_RFDF_MASK) {
-        char data;
-        data = (char)spi->POPR;
-        data = spi_config[dev].cb(data);
-        spi->PUSHR = SPI_PUSHR_CTAS(0)
-                     | SPI_PUSHR_EOQ_MASK
-                     | SPI_PUSHR_TXDATA(data);
-    }
-
-    /* see if a thread with higher priority wants to run now */
-    cortexm_isr_end();
-}
-
-#if SPI_0_EN
-#ifdef SPI_0_IRQ_HANDLER
-void SPI_0_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_0_DEV, SPI_0);
-}
-#endif
-#endif
-
-#if SPI_1_EN
-#ifdef SPI_1_IRQ_HANDLER
-void SPI_1_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_1_DEV, SPI_1);
-}
-#endif
-#endif
-
-#if SPI_2_EN
-#ifdef SPI_2_IRQ_HANDLER
-void SPI_2_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_2_DEV, SPI_2);
-}
-#endif
-#endif
-
-#if SPI_3_EN
-#ifdef SPI_3_IRQ_HANDLER
-void SPI_3_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_3_DEV, SPI_3);
-}
-#endif
-#endif
-
-#if SPI_4_EN
-#ifdef SPI_4_IRQ_HANDLER
-void SPI_4_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_4_DEV, SPI_4);
-}
-#endif
-#endif
-
-#if SPI_5_EN
-#ifdef SPI_5_IRQ_HANDLER
-void SPI_5_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_5_DEV, SPI_5);
-}
-#endif
-#endif
-
-#if SPI_6_EN
-#ifdef SPI_6_IRQ_HANDLER
-void SPI_6_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_6_DEV, SPI_6);
-}
-#endif
-#endif
-
-#if SPI_7_EN
-#ifdef SPI_7_IRQ_HANDLER
-void SPI_7_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_7_DEV, SPI_7);
-}
-#endif
-#endif
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/kw2x/cpu.c b/cpu/kw2x/cpu.c
index 41f95e6c16219b2b05ece2286198ea905e7c3e46..bcbffa75b8f34f755776244ca6d6f193f4d9cd31 100644
--- a/cpu/kw2x/cpu.c
+++ b/cpu/kw2x/cpu.c
@@ -23,6 +23,7 @@
 #include "cpu.h"
 #include "mcg.h"
 #include "cpu_conf.h"
+#include "periph/init.h"
 
 #define FLASH_BASE          (0x00000000)
 
@@ -37,6 +38,8 @@ void cpu_init(void)
     cortexm_init();
     /* initialize the clock system */
     cpu_clock_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 static inline void modem_clock_init(void)
diff --git a/cpu/lm4f120/cpu.c b/cpu/lm4f120/cpu.c
index 05ffbdaa116b14d562ec6c40a644c65c0e3911f7..a4b1598381d2e2aaf2162048322dcbfb750a484d 100644
--- a/cpu/lm4f120/cpu.c
+++ b/cpu/lm4f120/cpu.c
@@ -23,6 +23,7 @@
 #include "thread.h"
 #include "arch/thread_arch.h"
 #include "arch/irq_arch.h"
+#include "periph/init.h"
 
 /**
  * @brief Initialize the CPU, set IRQ priorities
@@ -34,6 +35,9 @@ void cpu_init(void)
 
     /* initialize the clock system */
     cpu_clock_init(CLOCK_SOURCE);
+
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 void setup_fpu(void)
diff --git a/cpu/lpc11u34/cpu.c b/cpu/lpc11u34/cpu.c
index a41832e254688a1284ddd497ba20a330f29b14ff..561aefd2bba479e928bb404fb96004b18aea8979 100644
--- a/cpu/lpc11u34/cpu.c
+++ b/cpu/lpc11u34/cpu.c
@@ -18,6 +18,7 @@
  */
 
 #include "cpu.h"
+#include "periph/init.h"
 
 
 #define SYSOSCCTRL_Val    0x00000000 /* Reset: 0x000 */
@@ -111,4 +112,6 @@ void cpu_init(void)
     cortexm_init();
     /* initialize the clock */
     clk_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
diff --git a/cpu/lpc11u34/include/periph_cpu.h b/cpu/lpc11u34/include/periph_cpu.h
index c288c49370264288b715493e62af8e80786ef6bd..0c791c3c68e59909a7f1095b76277f71741d0e98 100644
--- a/cpu/lpc11u34/include/periph_cpu.h
+++ b/cpu/lpc11u34/include/periph_cpu.h
@@ -31,7 +31,8 @@ extern "C" {
  * @brief declare needed generic SPI functions
  * @{
  */
-#define PERIPH_SPI_NEEDS_TRANSFER_BYTES
+#define PERIPH_SPI_NEEDS_INIT_CS
+#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
 #define PERIPH_SPI_NEEDS_TRANSFER_REG
 #define PERIPH_SPI_NEEDS_TRANSFER_REGS
 /** @} */
@@ -105,19 +106,41 @@ typedef enum {
 #endif /* ndef DOXYGEN */
 
 /**
- * @brief   PWM channel configuration
+ * @brief   PWM configuration
  */
+typedef struct {
+    LPC_CTxxBx_Type *dev;                   /**< PWM device */
+    __IO uint32_t *pins[PWM_CHAN_NUMOF];    /**< set to NULL if channel is not used */
+    uint16_t clk_bit;                       /**< clock enable bit */
+    uint8_t af;                             /**< alternate pin function */
+} pwm_conf_t;
 
+/**
+ * @brief   Override SPI clock speed values
+ *
+ * @note    The values expect the CPU to run at 12MHz
+ * @todo    Generalize the SPI driver
+ *
+ * @{
+ */
+#define HAVE_SPI_CLK_T
+typedef enum {
+    SPI_CLK_100KHZ = 119,       /**< drive the SPI bus with 100KHz */
+    SPI_CLK_400KHZ =  29,       /**< drive the SPI bus with 400KHz */
+    SPI_CLK_1MHZ   =  11,       /**< drive the SPI bus with 1MHz */
+    SPI_CLK_5MHZ   =   2,       /**< drive the SPI bus with 5MHz */
+    SPI_CLK_10MHZ  =   0        /**< actual: 12 MHz */
+} spi_clk_t;
+/** @} */
 
 /**
- * @brief   PWM configuration
+ * @brief   SPI configuration data
  */
 typedef struct {
-    LPC_CTxxBx_Type *dev;
-    __IO uint32_t *pins[PWM_CHAN_NUMOF];     /**< set to NULL if channel is not used */
-    uint16_t clk_bit;
-    uint8_t af;
-} pwm_conf_t;
+    LPC_SSPx_Type *dev;     /**< SPI device to configure */
+    uint32_t preset_bit;    /**< mask of the corresponding preset bit */
+    uint32_t ahb_bit;       /**< mask of the corresponding AHB bit */
+} spi_conf_t;
 
 #ifdef __cplusplus
 }
diff --git a/cpu/lpc11u34/periph/spi.c b/cpu/lpc11u34/periph/spi.c
index 325d73fbc363148b20d8d2b1f1f0e37374b4ea63..53672526b9e13cff9a18e947efff3d7d3c8d332f 100644
--- a/cpu/lpc11u34/periph/spi.c
+++ b/cpu/lpc11u34/periph/spi.c
@@ -1,118 +1,86 @@
 /*
- * Copyright (C) 2015 Freie Universität Berlin
+ * Copyright (C) 2015-2016 Freie Universität Berlin
  *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
  */
 
+
 /**
  * @ingroup     cpu_lpc11u34
  * @{
  *
  * @file
- * @brief       Low-level GPIO driver implementation
+ * @brief       Low-level SPI driver implementation
+ *
+ * @todo        this implementation needs to be generalized in some aspects,
+ *              e.g. clock configuration
  *
  * @author      Paul RATHGEB <paul.rathgeb@skynet.be>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  *
  * @}
  */
 
 #include "cpu.h"
-#include "board.h"
 #include "mutex.h"
+#include "assert.h"
 #include "periph/spi.h"
-#include "periph_conf.h"
-#include "thread.h"
-#include "sched.h"
-
-/* guard file in case no SPI device is defined */
-#if SPI_NUMOF
 
 /**
  * @brief Array holding one pre-initialized mutex for each SPI device
  */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
-{
-    LPC_SSPx_Type *spi;
-    /* power on the SPI device */
-    spi_poweron(dev);
-
-    /* configure SCK, MISO and MOSI pin */
-    spi_conf_pins(dev);
+static mutex_t locks[SPI_NUMOF];
 
-    switch(dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi = LPC_SSP0;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            spi = LPC_SSP1;
-            break;
-#endif
-        default:
-            return -1;
-    }
+static inline LPC_SSPx_Type *dev(spi_t bus)
+{
+    return spi_config[bus].dev;
+}
 
-    /* Master mode, SPI disabled */
-    spi->CR1 = 0;
-    /* Base clock frequency : 12MHz */
-    spi->CPSR = 4;
-    /* configure bus clock speed */
-    switch (speed) {
-        case SPI_SPEED_100KHZ:
-            spi->CR0 |= (119 << 8);
-            break;
-        case SPI_SPEED_400KHZ:
-            spi->CR0 |= (29 << 8);
-            break;
-        case SPI_SPEED_1MHZ:
-            spi->CR0 |= (11 << 8);
-            break;
-        case SPI_SPEED_5MHZ:
-            spi->CR0 |= (2 << 8); /* Actual : 4MHz */
-            break;
-        case SPI_SPEED_10MHZ:
-            spi->CR0 |= (0 << 8); /* Actual : 12MHz */
-            break;
-    }
-    /* Set mode and 8-bit transfer */
-    spi->CR0 |= 0x07 | (conf << 6);
-    /* Enable SPI */
-    spi->CR1 |= (1 << 1);
-
-    /* Wait while the BUSY flag is set */
-    while(spi->SR & (1 << 4)) {}
-    /* Clear the RX FIFO */
-    while(spi->SR & (1 << 2)) {
-        spi->DR;
-    }
+static inline void poweron(spi_t bus)
+{
+    /* de-assert SPIx, enable clock and set clock div */
+    LPC_SYSCON->PRESETCTRL |= (spi_config[bus].preset_bit);
+    LPC_SYSCON->SYSAHBCLKCTRL |= (spi_config[bus].ahb_bit);
+}
 
-    return 0;
+static inline void poweroff(spi_t bus)
+{
+    LPC_SYSCON->SYSAHBCLKCTRL &= ~(spi_config[bus].ahb_bit);
+    LPC_SYSCON->PRESETCTRL &= ~(spi_config[bus].preset_bit);
 }
 
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data))
+void spi_init(spi_t bus)
 {
-    /* Slave mode not supported */
-    return -1;
+    /* check device */
+    assert(bus <= SPI_NUMOF);
+
+    /* initialize device lock */
+    mutex_init(&locks[bus]);
+
+    /* set clock div for all SPI devices to 1 -> 48MHz */
+    LPC_SYSCON->SSP0CLKDIV = 1;
+    LPC_SYSCON->SSP1CLKDIV = 1;
+
+    /* trigger the pin configuration */
+    spi_init_pins(bus);
+
+    /* power on the bus for the duration of initialization */
+    poweron(bus);
+    /* reset configuration */
+    dev(bus)->CR1 = 0;
+    /* configure base clock frequency to 12 MHz CLOCK_CORECLOCK / 4 */
+    dev(bus)->CPSR = 4;
+    /* and power off the bus again */
+    poweroff(bus);
 }
 
-int spi_conf_pins(spi_t dev)
+void spi_init_pins(spi_t bus)
 {
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
+    /* this is hacky as hell -> integrate this into the GPIO module */
+    switch (bus) {
+        case SPI_DEV(0):
             /* SPI0 : MISO */
             LPC_IOCON->PIO0_8 |= 1;
             /* SPI0 : MOSI */
@@ -120,128 +88,69 @@ int spi_conf_pins(spi_t dev)
             /* SPI0 : SCK */
             LPC_IOCON->SWCLK_PIO0_10 |= 2;
             break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
+        case SPI_DEV(1):
             /* SPI1 : MISO */
             LPC_IOCON->PIO1_21 |= 2;
             /* SPI1 : MOSI */
             LPC_IOCON->PIO0_21 |= 2;
             /* SPI1 : SCK */
             LPC_IOCON->PIO1_20 |= 2;
-#endif
         default:
-            return -1;
+            break;
     }
-
-    return 0;
 }
 
-int spi_acquire(spi_t dev)
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
 {
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
+    /* lock an power on the bus */
+    mutex_lock(&locks[bus]);
+    poweron(bus);
+
+    /* configure bus clock and mode and set to 8-bit transfer */
+    dev(bus)->CR0 = ((clk << 8) | (mode << 6) | 0x07);
+    /* enable the bus */
+    dev(bus)->CR1 = (1 << 1);
+    /* wait until ready and flush RX FIFO */
+    while(dev(bus)->SR & (1 << 4)) {}
+    while(dev(bus)->SR & (1 << 2)) {
+        dev(bus)->DR;
     }
-    mutex_lock(&locks[dev]);
-    return 0;
+
+    return SPI_OK;
 }
 
-int spi_release(spi_t dev)
+void spi_release(spi_t bus)
 {
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
+    /* disable device, power off and release lock */
+    dev(bus)->CR1 = 0;
+    poweroff(bus);
+    mutex_unlock(&locks[bus]);
 }
 
-int spi_transfer_byte(spi_t dev, char out, char *in)
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
 {
-    char tmp;
-    LPC_SSPx_Type *spi;
+    uint8_t *out_buf = (uint8_t *)out;
+    uint8_t *in_buf = (uint8_t *)in;
 
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi = LPC_SSP0;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            spi = LPC_SSP1;
-            break;
-#endif
-        default:
-            return 0;
-    }
+    assert(out_buf || in_buf);
 
-    /* Wait while the BUSY flag is set */
-    while(spi->SR & (1 << 4)) {}
-    /* Put byte in the TX Fifo */
-    *((volatile uint8_t *)(&spi->DR)) = (uint8_t)out;
-    /* Wait until the current byte is transfered */
-    while(!(spi->SR & (1 << 2)) ) {}
-    /* Read the returned byte */
-    tmp = *((volatile uint8_t *)(&spi->DR));
-    /* 'return' response byte if wished for */
-    if (in) {
-        *in = tmp;
+    if (cs != SPI_CS_UNDEF) {
+        gpio_clear((gpio_t)cs);
     }
 
-    return 1;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    /* Slave mode not supported */
-}
-
-void spi_poweron(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            /* De-assert SPI0 */
-            LPC_SYSCON->PRESETCTRL |= (1 << 0);
-            /* Enable SPI0 clock */
-            LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 11);
-            /* Clock div : 48MHz */
-            LPC_SYSCON->SSP0CLKDIV = 1;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            /* De-assert SPI1 */
-            LPC_SYSCON->PRESETCTRL |= (1 << 2);
-            /* Enable SPI1 clock */
-            LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 18);
-            /* Clock div : 48MHz */
-            LPC_SYSCON->SSP1CLKDIV = 1;
-            break;
-#endif
+    for (size_t i = 0; i < len; i++) {
+        uint8_t tmp = (out_buf) ? out_buf[i] : 0;
+        while(dev(bus)->SR & (1 << 4)) {}       /* wait for BUSY clear */
+        *((volatile uint8_t *)(&dev(bus)->DR)) = tmp;
+        while(!(dev(bus)->SR & (1 << 2))) {}    /* wait RXNE */
+        tmp = *((volatile uint8_t *)(&dev(bus)->DR));
+        if (in_buf) {
+            in_buf[i] = tmp;
+        }
     }
-}
 
-void spi_poweroff(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            /* Assert SPI0 */
-            LPC_SYSCON->PRESETCTRL &= ~(1 << 0);
-            /* Disable SPI0 clock */
-            LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 11);
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            /* Assert SPI1 */
-            LPC_SYSCON->PRESETCTRL &= ~(1 << 2);
-            /* Disable SPI1 clock */
-            LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 18);
-            break;
-#endif
+    if ((!cont) && (cs != SPI_CS_UNDEF)) {
+        gpio_set((gpio_t)cs);
     }
 }
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/lpc1768/cpu.c b/cpu/lpc1768/cpu.c
index 69b856f611c6bfad8257e26a8d301a0f2cd2e664..9018d8b7567fd0704bcc86a066d528d255a4edba 100644
--- a/cpu/lpc1768/cpu.c
+++ b/cpu/lpc1768/cpu.c
@@ -18,6 +18,7 @@
  */
 
 #include "cpu.h"
+#include "periph/init.h"
 
 /**
  * @brief Initialize the CPU, set IRQ priorities
@@ -26,4 +27,6 @@ void cpu_init(void)
 {
     /* initialize the Cortex-M core */
     cortexm_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
diff --git a/cpu/lpc2387/include/periph_cpu.h b/cpu/lpc2387/include/periph_cpu.h
index dbb757ffdb31f2adf11b13ab773832af021cf6ae..841b63bbf355d4b751f49cdde1845755eb933123 100644
--- a/cpu/lpc2387/include/periph_cpu.h
+++ b/cpu/lpc2387/include/periph_cpu.h
@@ -74,11 +74,26 @@ typedef enum {
  * @brief   Declare needed generic SPI functions
  * @{
  */
-#define PERIPH_SPI_NEEDS_TRANSFER_BYTES
+#define PERIPH_SPI_NEEDS_INIT_CS
+#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
 #define PERIPH_SPI_NEEDS_TRANSFER_REG
 #define PERIPH_SPI_NEEDS_TRANSFER_REGS
 /* @} */
 
+/**
+ * @brief   Override SPI clock speed values
+ * @{
+ */
+#define HAVE_SPI_CLK_T
+typedef enum {
+    SPI_CLK_100KHZ = 100,   /**< drive the SPI bus with 100KHz */
+    SPI_CLK_400KHZ = 400,   /**< drive the SPI bus with 400KHz */
+    SPI_CLK_1MHZ   = 1000,  /**< drive the SPI bus with 1MHz */
+    SPI_CLK_5MHZ   = 5000,  /**< drive the SPI bus with 5MHz */
+    SPI_CLK_10MHZ  = 10000  /**< drive the SPI bus with 10MHz */
+} spi_clk_t;
+/** @} */
+
 /* @} */
 #ifdef __cplusplus
 }
diff --git a/cpu/lpc2387/periph/spi.c b/cpu/lpc2387/periph/spi.c
index fef1b277dfe6f479b02203cc994bf8a6102a0431..60a3a7785b5d3ed50503778daa0af4b27b54b9d0 100644
--- a/cpu/lpc2387/periph/spi.c
+++ b/cpu/lpc2387/periph/spi.c
@@ -1,9 +1,10 @@
 /*
  * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
+ *               2016 Freie Universität Berlin
  *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
  */
 
 /**
@@ -13,22 +14,25 @@
  * @file
  * @brief       Low-level SPI driver implementation
  *
+ * This implementation is very basic and only supports a single SPI device with
+ * limited configuration options.
+ *
+ * @todo        This implementation needs a major rework
+ *
  * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  *
  * @}
  */
 
 #include "cpu.h"
 #include "mutex.h"
-#include "periph/gpio.h"
+#include "assert.h"
 #include "periph/spi.h"
-#include "periph_conf.h"
-#include "board.h"
+
 #define ENABLE_DEBUG (0)
 #include "debug.h"
 
-#if SPI_0_EN
-
 #define SPI_TX_EMPTY                (SSP0SR & SSPSR_TFE)
 #define SPI_BUSY                    (SSP0SR & SSPSR_BSY)
 #define SPI_RX_AVAIL                (SSP0SR & SSPSR_RNE)
@@ -36,178 +40,94 @@
 /**
  * @brief Array holding one pre-initialized mutex for each SPI device
  */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-#if SPI_2_EN
-    [SPI_2] = MUTEX_INIT
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
+static mutex_t lock = MUTEX_INIT;
+
+void spi_init(spi_t bus)
 {
-    (void ) conf;
-    if (dev) {
-        return -1;
-    }
+    assert(bus == SPI_DEV(0));
 
-    uint32_t   f_baud = 0;
-    switch(speed)
-    {
-    case SPI_SPEED_100KHZ:
-        f_baud = 100;
-        break;
-    case SPI_SPEED_400KHZ:
-        f_baud = 400;
-        break;
-    case SPI_SPEED_1MHZ:
-        f_baud = 1000;
-        break;
-    case SPI_SPEED_5MHZ:
-        f_baud = 5000;
-        break;
-    case SPI_SPEED_10MHZ:
-        f_baud = 10000;
-        break;
-    }
+    /* interface setup */
+    SSP0CR0 = 7;
+    /* configure pins */
+    spi_init_pins(bus);
+    /*  power off the bus (default is on) */
+    PCONP &= ~(PCSSP0);
+}
 
-#if 0
-    /* TODO */
-    switch(conf)
-    {
-    case SPI_CONF_FIRST_RISING:
-        /**< first data bit is transacted on the first rising SCK edge */
-        cpha = 0;
-        cpol = 0;
-        break;
-    case SPI_CONF_SECOND_RISING:
-        /**< first data bit is transacted on the second rising SCK edge */
-        cpha = 1;
-        cpol = 0;
-        break;
-    case SPI_CONF_FIRST_FALLING:
-        /**< first data bit is transacted on the first falling SCK edge */
-        cpha = 0;
-        cpol = 1;
-        break;
-    case SPI_CONF_SECOND_FALLING:
-        /**< first data bit is transacted on the second falling SCK edge */
-        cpha = 1;
-        cpol = 1;
-        break;
-    }
-#endif
+void spi_init_pins(spi_t bus)
+{
+    PINSEL3 |= (BIT8 | BIT9);     /* SCLK */
+    PINSEL3 |= (BIT14 | BIT15);   /* MISO */
+    PINSEL3 |= (BIT16 | BIT17);   /* MOSI */
+}
 
-    /* Power*/
-    PCONP |= PCSSP0;                /* Enable power for SSP0 (default is on)*/
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    uint32_t pclksel;
+    uint32_t cpsr;
 
-    /* PIN Setup*/
-    spi_conf_pins(dev);
+    /* only support for mode 0 at the moment */
+    if (mode != SPI_MODE_0) {
+        return SPI_NOMODE;
+    }
 
-    /* Interface Setup*/
-    SSP0CR0 = 7;
+    /* lock bus */
+    mutex_lock(&lock);
+    /*  power on */
+    PCONP |= (PCSSP0);
 
-    /* Clock Setup*/
-    uint32_t pclksel;
-    uint32_t cpsr;
-    lpc2387_pclk_scale(CLOCK_CORECLOCK / 1000, f_baud, &pclksel, &cpsr);
+    /* configure bus clock */
+    lpc2387_pclk_scale(CLOCK_CORECLOCK / 1000, (uint32_t)clk, &pclksel, &cpsr);
     PCLKSEL1 &= ~(BIT10 | BIT11);   /* CCLK to PCLK divider*/
     PCLKSEL1 |= pclksel << 10;
     SSP0CPSR = cpsr;
 
-    /* Enable*/
-    SSP0CR1 |= BIT1;                /* SSP-Enable*/
-    int dummy;
+    /* enable the bus */
+    SSP0CR1 |= BIT1;
 
-    /* Clear RxFIFO:*/
-    while (SPI_RX_AVAIL) {          /* while RNE (Receive FIFO Not Empty)...*/
-        dummy = SSP0DR;             /* read data*/
+    /* clear RxFIFO */
+    int dummy;
+    while (SPI_RX_AVAIL) {         /* while RNE (Receive FIFO Not Empty)...*/
+        dummy = SSP0DR;            /* read data*/
     }
+    (void) dummy;                  /* to suppress unused-but-set-variable */
 
-    /* to suppress unused-but-set-variable */
-    (void) dummy;
-    return 0;
+    return SPI_OK;
 }
 
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char))
+void spi_release(spi_t bus)
 {
-    (void)dev;
-    (void)conf;
-    (void)cb;
-    printf("%s:%s(): stub\n", RIOT_FILE_RELATIVE, __func__);
-    /* TODO */
-    return -1;
+    /* disable, power off, and release the bus */
+    SSP0CR1 &= ~(BIT1);
+    PCONP &= ~(PCSSP0);
+    mutex_unlock(&lock);
 }
 
-void spi_transmission_begin(spi_t dev, char reset_val)
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
 {
-    (void)dev;
-    (void)reset_val;
-    printf("%s:%s(): stub\n", RIOT_FILE_RELATIVE, __func__);
-    /* TODO*/
-}
+    uint8_t *out_buf = (uint8_t *)out;
+    uint8_t *in_buf = (uint8_t *)in;
 
-int spi_acquire(spi_t dev)
-{
-    if (dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
-}
+    assert(out_buf || in_buf);
 
-int spi_release(spi_t dev)
-{
-    if (dev >= SPI_NUMOF) {
-        return -1;
+    if (cs != SPI_CS_UNDEF) {
+        gpio_clear((gpio_t)cs);
     }
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
-
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    (void) dev;
-    while (!SPI_TX_EMPTY) {}
-    SSP0DR = out;
-    while (SPI_BUSY) {}
-    while (!SPI_RX_AVAIL) {}
-
-    char tmp = (char)SSP0DR;
 
-    if (in != NULL) {
-        *in = tmp;
+    for (size_t i = 0; i < len; i++) {
+        uint8_t tmp = (out_buf) ? out_buf[i] : 0;
+        while (!SPI_TX_EMPTY) {}
+        SSP0DR = tmp;
+        while (SPI_BUSY) {}
+        while (!SPI_RX_AVAIL) {}
+        tmp = (uint8_t)SSP0DR;
+        if (in_buf) {
+            in_buf[i] = tmp;
+        }
     }
 
-    return 1;
-}
-
-void spi_poweron(spi_t dev)
-{
-    (void) dev;
-}
-
-void spi_poweroff(spi_t dev)
-{
-    (void) dev;
-    (void) dev;
-}
-
-int spi_conf_pins(spi_t dev)
-{
-    switch (dev) {
-        case 0:
-            PINSEL3 |= BIT8 + BIT9;     /* SCLK */
-            PINSEL3 |= BIT14 + BIT15;   /* MISO */
-            PINSEL3 |= BIT16 + BIT17;   /* MOSI */
-            return 0;
-        default:
-            return -1;
+    if ((!cont) && cs != SPI_CS_UNDEF) {
+        gpio_set((gpio_t)cs);
     }
 }
-
-#endif /* SPI_0_EN */
diff --git a/cpu/msp430fxyz/include/periph_cpu.h b/cpu/msp430fxyz/include/periph_cpu.h
index f045de48fe60ea48ad8d9e8877f02cb183291883..85ab53d5fbbec2c2f9f0af4f2723623512a95bef 100644
--- a/cpu/msp430fxyz/include/periph_cpu.h
+++ b/cpu/msp430fxyz/include/periph_cpu.h
@@ -45,6 +45,11 @@ typedef uint16_t gpio_t;
  */
 #define GPIO_PIN(x, y)      ((gpio_t)(((x & 0xff) << 8) | (1 << (y & 0xff))))
 
+/**
+ * @brief   No support for HW chip select...
+ */
+#define SPI_HWCS(x)         (SPI_CS_UNDEF)
+
 #ifndef DOXYGEN
 /**
  * @brief   Override flank selection values
@@ -57,6 +62,40 @@ typedef enum {
     GPIO_BOTH    = 0xab         /**< not supported -> random value*/
 } gpio_flank_t;
 /** @} */
+
+/**
+ * @brief   Override SPI mode selection values
+ */
+#define HAVE_SPI_MODE_T
+#ifndef SPI_USE_USCI
+typedef enum {
+    SPI_MODE_0 = (USART_TCTL_CKPH),                         /**< CPOL=0, CPHA=0 */
+    SPI_MODE_1 = 0,                                         /**< CPOL=0, CPHA=1 */
+    SPI_MODE_2 = (USART_TCTL_CKPL | USART_TCTL_CKPH),       /**< CPOL=1, CPHA=0 */
+    SPI_MODE_3 = (USART_TCTL_CKPL)                          /**< CPOL=1, CPHA=1 */
+} spi_mode_t;
+#else
+typedef enum {
+    SPI_MODE_0 = (USCI_SPI_CTL0_CKPH),                      /**< CPOL=0, CPHA=0 */
+    SPI_MODE_1 = 0,                                         /**< CPOL=0, CPHA=1 */
+    SPI_MODE_2 = (USCI_SPI_CTL0_CKPL | USCI_SPI_CTL0_CKPH), /**< CPOL=1, CPHA=0 */
+    SPI_MODE_3 = (USCI_SPI_CTL0_CKPL)                       /**< CPOL=1, CPHA=1 */
+} spi_mode_t;
+#endif
+/** @} */
+
+/**
+ * @brief   Override SPI clock speed selection values
+ */
+#define HAVE_SPI_CLK_T
+typedef enum {
+    SPI_CLK_100KHZ = 100000,    /**< 100KHz */
+    SPI_CLK_400KHZ = 400000,    /**< 400KHz */
+    SPI_CLK_1MHZ   = 1000000,   /**< 1MHz */
+    SPI_CLK_5MHZ   = 5000000,   /**< 5MHz */
+    SPI_CLK_10MHZ  = 0,         /**< not supported */
+} spi_clk_t;
+/** @} */
 #endif /* ndef DOXYGEN */
 
 /**
@@ -83,6 +122,7 @@ void gpio_periph_mode(gpio_t pin, bool enable);
  * @brief declare needed generic SPI functions
  * @{
  */
+#define PERIPH_SPI_NEEDS_INIT_CS
 #define PERIPH_SPI_NEEDS_TRANSFER_BYTE
 #define PERIPH_SPI_NEEDS_TRANSFER_REG
 #define PERIPH_SPI_NEEDS_TRANSFER_REGS
diff --git a/cpu/msp430fxyz/periph/spi.c b/cpu/msp430fxyz/periph/spi.c
index e7f5fe2602dd26eb0c1ce193209396d981be27ba..76a95466ece10ac93a8571084d8bb0aabf6cd72d 100644
--- a/cpu/msp430fxyz/periph/spi.c
+++ b/cpu/msp430fxyz/periph/spi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Freie Universität Berlin
+ * Copyright (C) 2015-2016 Freie Universität Berlin
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License v2.1. See the file LICENSE in the top level
@@ -25,8 +25,6 @@
 #include "cpu.h"
 #include "mutex.h"
 #include "assert.h"
-#include "periph_cpu.h"
-#include "periph_conf.h"
 #include "periph/spi.h"
 
 /**
@@ -34,233 +32,128 @@
  */
 static mutex_t spi_lock = MUTEX_INIT;
 
-/* per default, we use the legacy MSP430 USART module for UART functionality */
-#ifndef SPI_USE_USCI
 
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
+void spi_init(spi_t bus)
 {
-    if (dev != 0) {
-        return -2;
-    }
-
-    /* reset SPI device */
-    SPI_DEV->CTL = USART_CTL_SWRST;
-    /* configure pins */
-    spi_conf_pins(dev);
-    /* configure USART to SPI mode with SMCLK driving it */
-    SPI_DEV->CTL |= (USART_CTL_CHAR | USART_CTL_SYNC | USART_CTL_MM);
-    SPI_DEV->RCTL = 0;
-    SPI_DEV->TCTL = (USART_TCTL_SSEL_SMCLK | USART_TCTL_STC);
-    /* set polarity and phase */
-    switch (conf) {
-        case SPI_CONF_FIRST_RISING:
-            SPI_DEV->TCTL |= USART_TCTL_CKPH;
-            break;
-        case SPI_CONF_SECOND_RISING:
-            /* nothing to be done here */
-            break;
-        case SPI_CONF_FIRST_FALLING:
-            SPI_DEV->TCTL |= (USART_TCTL_CKPH & USART_TCTL_CKPL);
-            break;
-        case SPI_CONF_SECOND_FALLING:
-            SPI_DEV->TCTL |= USART_TCTL_CKPL;
-            break;
-        default:
-            /* invalid clock setting */
-            return -2;
-    }
-    /* configure clock - we use no modulation for now */
-    uint32_t br = CLOCK_CMCLK;
-    switch (speed) {
-        case SPI_SPEED_100KHZ:
-            br /= 100000;
-            break;
-        case SPI_SPEED_400KHZ:
-            br /= 400000;
-            break;
-        case SPI_SPEED_1MHZ:
-            br /= 1000000;
-            break;
-        case SPI_SPEED_5MHZ:
-            br /= 5000000;
-            break;
-        default:
-            /* other clock speeds are not supported */
-            return -1;
-    }
+    assert(bus <= SPI_NUMOF);
 
-    /* make sure the is not smaller then 2 */
-    if (br < 2) {
-        br = 2;
-    }
-
-    SPI_DEV->BR0 = (uint8_t)br;
-    SPI_DEV->BR1 = (uint8_t)(br >> 8);
-    SPI_DEV->MCTL = 0;
+/* we need to differentiate between the legacy SPI device and USCI */
+#ifndef SPI_USE_USCI
+    /* put SPI device in reset state */
+    SPI_BASE->CTL = USART_CTL_SWRST;
+    SPI_BASE->CTL |= (USART_CTL_CHAR | USART_CTL_SYNC | USART_CTL_MM);
+    SPI_BASE->RCTL = 0;
+    SPI_BASE->MCTL = 0;
     /* enable SPI mode */
     SPI_ME |= SPI_ME_BIT;
-    /* release from software reset */
-    SPI_DEV->CTL &= ~(USART_CTL_SWRST);
-    return 0;
+#else
+    /* reset SPI device */
+    SPI_BASE->CTL1 = USCI_SPI_CTL1_SWRST;
+    SPI_BASE->CTL1 |= (USCI_SPI_CTL1_SSEL_SMCLK);
+#endif
+
+    /* trigger the pin configuration */
+    spi_init_pins(bus);
 }
 
-/* we use alternative SPI code in case the board used the USCI module for SPI
- * instead of the (older) USART module */
-#else   /* SPI_USE_USCI */
+void spi_init_pins(spi_t bus)
+{
+    gpio_periph_mode(SPI_PIN_MISO, true);
+    gpio_periph_mode(SPI_PIN_MOSI, true);
+    gpio_periph_mode(SPI_PIN_CLK, true);
+}
 
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
 {
-    if (dev != 0) {
-        return -2;
+    if (clk == SPI_CLK_10MHZ) {
+        return SPI_NOCLK;
     }
 
-    /* reset SPI device */
-    SPI_DEV->CTL1 |= USCI_SPI_CTL1_SWRST;
-    /* configure pins */
-    spi_conf_pins(dev);
-    /* configure USART to SPI mode with SMCLK driving it */
-    SPI_DEV->CTL0 |= (USCI_SPI_CTL0_UCSYNC | USCI_SPI_CTL0_MST
-                      | USCI_SPI_CTL0_MODE_0 | USCI_SPI_CTL0_MSB);
-    SPI_DEV->CTL1 |= (USCI_SPI_CTL1_SSEL_SMCLK);
-
-    /* set polarity and phase */
-    switch (conf) {
-        case SPI_CONF_FIRST_RISING:
-            SPI_DEV->CTL0 |= USCI_SPI_CTL0_CKPH;
-            break;
-        case SPI_CONF_SECOND_RISING:
-            /* nothing to be done here */
-            break;
-        case SPI_CONF_FIRST_FALLING:
-            SPI_DEV->CTL0 |= (USCI_SPI_CTL0_CKPH & USCI_SPI_CTL0_CKPL);
-            break;
-        case SPI_CONF_SECOND_FALLING:
-            SPI_DEV->CTL0 |= USCI_SPI_CTL0_CKPL;
-            break;
-        default:
-            /* invalid clock setting */
-            return -2;
-    }
-    /* configure clock - we use no modulation for now */
-    uint32_t br = CLOCK_CMCLK;
-    switch (speed) {
-        case SPI_SPEED_100KHZ:
-            br /= 100000;
-            break;
-        case SPI_SPEED_400KHZ:
-            br /= 400000;
-            break;
-        case SPI_SPEED_1MHZ:
-            br /= 1000000;
-            break;
-        case SPI_SPEED_5MHZ:
-            br /= 5000000;
-            break;
-        default:
-            /* other clock speeds are not supported */
-            return -1;
-    }
+    /* lock the bus */
+    mutex_lock(&spi_lock);
 
+    /* calculate baudrate */
+    uint32_t br = CLOCK_CMCLK / clk;
     /* make sure the is not smaller then 2 */
     if (br < 2) {
         br = 2;
     }
+    SPI_BASE->BR0 = (uint8_t)br;
+    SPI_BASE->BR1 = (uint8_t)(br >> 8);
 
-    SPI_DEV->BR0 = (uint8_t)br;
-    SPI_DEV->BR1 = (uint8_t)(br >> 8);
+    /* configure bus mode */
+#ifndef SPI_USE_USCI
+    /* configure mode */
+    SPI_BASE->TCTL = (USART_TCTL_SSEL_SMCLK | USART_TCTL_STC | mode);
     /* release from software reset */
-    SPI_DEV->CTL1 &= ~(USCI_SPI_CTL1_SWRST);
-    return 0;
-}
-
-#endif  /* SPI_USE_USCI */
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data))
-{
-    /* not supported so far */
-    (void)dev;
-    (void)conf;
-    (void)cb;
-    return -1;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    /* not supported so far */
-    (void)dev;
-    (void)reset_val;
-}
+    SPI_BASE->CTL &= ~(USART_CTL_SWRST);
+#else
+    /* configure mode */
+    SPI_BASE->CTL0 = (USCI_SPI_CTL0_UCSYNC | USCI_SPI_CTL0_MST|
+                     USCI_SPI_CTL0_MODE_0 | USCI_SPI_CTL0_MSB | mode);
+    /* release from software reset */
+    SPI_BASE->CTL1 &= ~(USCI_SPI_CTL1_SWRST);
+#endif
 
-int spi_conf_pins(spi_t dev)
-{
-    (void)dev;
-    gpio_periph_mode(SPI_PIN_MISO, true);
-    gpio_periph_mode(SPI_PIN_MOSI, true);
-    gpio_periph_mode(SPI_PIN_CLK, true);
-    return 0;
+    return SPI_OK;
 }
 
-int spi_acquire(spi_t dev)
+void spi_release(spi_t dev)
 {
-    (void)dev;
-    mutex_lock(&spi_lock);
-    return 0;
-}
+    /* put SPI device back in reset state */
+#ifndef SPI_USE_USCI
+    SPI_BASE->CTL |= (USART_CTL_SWRST);
+#else
+    SPI_BASE->CTL1 |= (USCI_SPI_CTL1_SWRST);
+#endif
 
-int spi_release(spi_t dev)
-{
-    (void)dev;
+    /* release the bus */
     mutex_unlock(&spi_lock);
-    return 0;
 }
 
-int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length)
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
 {
-    (void)dev;
+    uint8_t *out_buf = (uint8_t *)out;
+    uint8_t *in_buf = (uint8_t *)in;
+
+    assert(out_buf || in_buf);
 
-    assert(out || in);
+    if (cs != SPI_CS_UNDEF) {
+        gpio_clear((gpio_t)cs);
+    }
 
     /* if we only send out data, we do this the fast way... */
-    if (!in) {
-        for (unsigned i = 0; i < length; i++) {
+    if (!in_buf) {
+        for (size_t i = 0; i < len; i++) {
             while (!(SPI_IF & SPI_IE_TX_BIT)) {}
-            SPI_DEV->TXBUF = (uint8_t)out[i];
+            SPI_BASE->TXBUF = (uint8_t)out_buf[i];
         }
         /* finally we need to wait, until all transfers are complete */
 #ifndef SPI_USE_USCI
         while (!(SPI_IF & SPI_IE_TX_BIT) || !(SPI_IF & SPI_IE_RX_BIT)) {}
 #else
-        while (SPI_DEV->STAT & USCI_SPI_STAT_UCBUSY) {}
+        while (SPI_BASE->STAT & USCI_SPI_STAT_UCBUSY) {}
 #endif
-        SPI_DEV->RXBUF;
+        SPI_BASE->RXBUF;
     }
-    else if (!out) {
-        for (unsigned i = 0; i < length; i++) {
-            SPI_DEV->TXBUF = 0;
+    else if (!out_buf) {
+        for (size_t i = 0; i < len; i++) {
+            SPI_BASE->TXBUF = 0;
             while (!(SPI_IF & SPI_IE_RX_BIT)) {}
-            in[i] = (char)SPI_DEV->RXBUF;
+            in_buf[i] = (char)SPI_BASE->RXBUF;
         }
     }
     else {
-        for (unsigned i = 0; i < length; i++) {
+        for (size_t i = 0; i < len; i++) {
             while (!(SPI_IF & SPI_IE_TX_BIT)) {}
-            SPI_DEV->TXBUF = out[i];
+            SPI_BASE->TXBUF = out_buf[i];
             while (!(SPI_IF & SPI_IE_RX_BIT)) {}
-            in[i] = (char)SPI_DEV->RXBUF;
+            in_buf[i] = (char)SPI_BASE->RXBUF;
         }
     }
 
-    return length;
-}
-
-void spi_poweron(spi_t dev)
-{
-    /* not supported so far */
-    (void)dev;
-}
-
-void spi_poweroff(spi_t dev)
-{
-    /* not supported so far */
-    (void)dev;
+    if ((!cont) && (cs != SPI_CS_UNDEF)) {
+        gpio_set((gpio_t)cs);
+    }
 }
diff --git a/cpu/nrf51/cpu.c b/cpu/nrf51/cpu.c
index 1d00dc7a40d8683f66105ad69b9fcf97b774ce49..db19c2681a7b56017fa6b8cc85bbe61cc0524d36 100644
--- a/cpu/nrf51/cpu.c
+++ b/cpu/nrf51/cpu.c
@@ -19,6 +19,7 @@
 
 #include "cpu.h"
 #include "periph_conf.h"
+#include "periph/init.h"
 
 /**
  * @brief Initialize the CPU, set IRQ priorities
@@ -39,4 +40,6 @@ void cpu_init(void)
     NRF_CLOCK->TASKS_HFCLKSTART = 1;
     while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {}
 #endif
+    /* trigger static peripheral initialization */
+    periph_init();
 }
diff --git a/cpu/nrf51/include/periph_cpu.h b/cpu/nrf51/include/periph_cpu.h
index 9e69280edb750aff3bc53991d7edf5b1a4c283ac..594414a936a16971083b1fa9042bf973f78154c0 100644
--- a/cpu/nrf51/include/periph_cpu.h
+++ b/cpu/nrf51/include/periph_cpu.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2016 Freie Universität Berlin
+ * Copyright (C) 2015-2017 Freie Universität Berlin
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License v2.1. See the file LICENSE in the top level
@@ -31,6 +31,9 @@ extern "C" {
  */
 #define GPIO_BASE           (NRF_GPIO)
 #define UART_IRQN           (UART0_IRQn)
+#define SPI_SCKSEL          (dev(bus)->PSELSCK)
+#define SPI_MOSISEL         (dev(bus)->PSELMOSI)
+#define SPI_MISOSEL         (dev(bus)->PSELMISO)
 /** @} */
 
 /**
diff --git a/cpu/nrf51/periph/spi.c b/cpu/nrf51/periph/spi.c
deleted file mode 100644
index 12bdd1b3dae75cdcf4cbfc89691aec2d8788bc36..0000000000000000000000000000000000000000
--- a/cpu/nrf51/periph/spi.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2014 Freie Universität Berlin
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
- */
-
-/**
- * @ingroup     cpu_nrf51822
- * @{
- *
- * @file
- * @brief       Low-level SPI driver implementation
- *
- * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- * @author      Frank Holtz <frank-riot2015@holtznet.de>
- *
- * @}
- */
-
-#include "cpu.h"
-#include "mutex.h"
-#include "periph/spi.h"
-#include "periph_conf.h"
-
-/* guard this file in case no SPI device is defined */
-#if SPI_NUMOF
-
-/* static port mapping */
-static NRF_SPI_Type *const spi[] = {
-#if SPI_0_EN
-    SPI_0_DEV,
-#endif
-#if SPI_1_EN
-    SPI_1_DEV
-#endif
-};
-
-/**
- * @brief   array holding one pre-initialized mutex for each SPI device
- */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
-{
-    spi_poweron(dev);
-
-    /* disable the device -> nRF51822 reference 3.0 26.1.1 and 27.1*/
-    spi[dev]->ENABLE = 0;
-
-    switch(dev) {
-#if SPI_0_EN
-        case SPI_0:
-            /* disable TWI Interface */
-            NRF_TWI0->ENABLE = 0;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            /* disable SPI Slave */
-            NRF_SPIS1->ENABLE = 0;
-            /* disable TWI Interface */
-            NRF_TWI1->ENABLE = 0;
-            break;
-#endif
-        default:
-            return -1;
-    }
-
-    /* configure direction of used pins */
-    spi_conf_pins(dev);
-    /* configure SPI mode */
-    switch (conf) {
-        case SPI_CONF_FIRST_RISING:
-            spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveHigh << 2) | (SPI_CONFIG_CPHA_Leading << 1);
-            break;
-        case SPI_CONF_SECOND_RISING:
-            spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveHigh << 2) | (SPI_CONFIG_CPHA_Trailing << 1);
-            break;
-        case SPI_CONF_FIRST_FALLING:
-            spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveLow << 2) | (SPI_CONFIG_CPHA_Leading << 1);
-            break;
-        case SPI_CONF_SECOND_FALLING:
-            spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveLow << 2) | (SPI_CONFIG_CPHA_Trailing << 1);
-            break;
-    }
-
-    /* select bus speed */
-    switch (speed) {
-        case SPI_SPEED_100KHZ:          /* 125 KHz for this device */
-            spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_K125;
-            break;
-        case SPI_SPEED_400KHZ:          /* 500 KHz for this device */
-            spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_K500;
-            break;
-        case SPI_SPEED_1MHZ:            /* 1 MHz for this device */
-            spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M1;
-            break;
-        case SPI_SPEED_5MHZ:            /* 4 MHz for this device */
-            spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M4;
-            break;
-        case SPI_SPEED_10MHZ:           /* 8 MHz for this device */
-            spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M8;
-            break;
-    }
-
-    /* finally enable the device */
-    spi[dev]->ENABLE = 1;
-    return 0;
-}
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data))
-{
-    (void) dev;
-    (void) conf;
-    (void) cb;
-    /* This API is incompatible with nRF51 SPIS */
-    return -1;
-}
-
-int spi_conf_pins(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            /* set pin direction */
-            NRF_GPIO->DIRSET = (1 << SPI_0_PIN_MOSI) | (1 << SPI_0_PIN_SCK);
-            NRF_GPIO->DIRCLR = (1 << SPI_0_PIN_MISO);
-            /* select pins to be used by SPI */
-            spi[dev]->PSELMOSI = SPI_0_PIN_MOSI;
-            spi[dev]->PSELMISO = SPI_0_PIN_MISO;
-            spi[dev]->PSELSCK = SPI_0_PIN_SCK;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            /* set pin direction */
-            NRF_GPIO->DIRSET = (1 << SPI_1_PIN_MOSI) | (1 << SPI_1_PIN_SCK);
-            NRF_GPIO->DIRCLR = (1 << SPI_1_PIN_MISO);
-            /* select pins to be used by SPI */
-            spi[dev]->PSELMOSI = SPI_1_PIN_MOSI;
-            spi[dev]->PSELMISO = SPI_1_PIN_MISO;
-            spi[dev]->PSELSCK = SPI_1_PIN_SCK;
-            break;
-#endif
-        default:
-            return -1;
-    }
-    return 0;
-}
-
-int spi_acquire(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
-}
-
-int spi_release(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
-
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    return spi_transfer_bytes(dev, &out, in, 1);
-}
-
-int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-
-    for (unsigned i = 0; i < length; i++) {
-        char tmp = (out) ? out[i] : 0;
-        spi[dev]->EVENTS_READY = 0;
-        spi[dev]->TXD = (uint8_t)tmp;
-        while (spi[dev]->EVENTS_READY != 1) {}
-        tmp = (char)spi[dev]->RXD;
-        if (in) {
-            in[i] = tmp;
-        }
-    }
-
-    return length;
-}
-
-int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in)
-{
-    spi_transfer_byte(dev, reg, 0);
-    return spi_transfer_byte(dev, out, in);
-}
-
-int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length)
-{
-    spi_transfer_byte(dev, reg, 0);
-    return spi_transfer_bytes(dev, out, in, length);
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    (void) dev;
-    (void) reset_val;
-    /* spi slave is not implemented */
-}
-
-void spi_poweron(spi_t dev)
-{
-    if ((unsigned int)dev < SPI_NUMOF) {
-        spi[dev]->POWER = 1;
-    }
-}
-
-void spi_poweroff(spi_t dev)
-{
-    if ((unsigned int)dev < SPI_NUMOF) {
-        spi[dev]->POWER = 0;
-    }
-}
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/nrf52/cpu.c b/cpu/nrf52/cpu.c
index 173531915d3cd0c881da5311905abeea1bd05cb9..85687fb9d8fac9dc15c54ce11cac363b84dad5b5 100644
--- a/cpu/nrf52/cpu.c
+++ b/cpu/nrf52/cpu.c
@@ -24,6 +24,7 @@
 
 #include "cpu.h"
 #include "periph_conf.h"
+#include "periph/init.h"
 
 /* FTPAN helper functions */
 static bool ftpan_32(void);
@@ -82,6 +83,9 @@ void cpu_init(void)
     NVIC_EnableIRQ(SWI0_EGU0_IRQn);
     NVIC_SetPriority(SWI0_EGU0_IRQn, 6);
 #endif
+
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 /**
diff --git a/cpu/nrf52/include/periph_cpu.h b/cpu/nrf52/include/periph_cpu.h
index c263b3dead13c3d002b8dc3ee84d0182a1c02250..e315106e648ed8bcdd473eee5482008ee2998a33 100644
--- a/cpu/nrf52/include/periph_cpu.h
+++ b/cpu/nrf52/include/periph_cpu.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2016 Freie Universität Berlin
+ * Copyright (C) 2015-2017 Freie Universität Berlin
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License v2.1. See the file LICENSE in the top level
@@ -31,6 +31,9 @@ extern "C" {
  */
 #define GPIO_BASE           (NRF_P0)
 #define UART_IRQN           (UARTE0_UART0_IRQn)
+#define SPI_SCKSEL          (dev(bus)->PSEL.SCK)
+#define SPI_MOSISEL         (dev(bus)->PSEL.MOSI)
+#define SPI_MISOSEL         (dev(bus)->PSEL.MISO)
 /** @} */
 
 #ifdef __cplusplus
diff --git a/cpu/nrf52/periph/spi.c b/cpu/nrf52/periph/spi.c
deleted file mode 100644
index bd7012a82af4943140019fa898e779f0314ef56a..0000000000000000000000000000000000000000
--- a/cpu/nrf52/periph/spi.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2015 Jan Wagner <mail@jwagner.eu>
- *               2016 Freie Universität Berlin
- *
- * This file is subject to the terms and conditions of the GNU Lesser
- * General Public License v2.1. See the file LICENSE in the top level
- * directory for more details.
- */
-
-/**
- * @ingroup     cpu_nrf52
- * @{
- *
- * @file
- * @brief       Implementation of the peripheral SPI interface
- *
- * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- * @author      Frank Holtz <frank-riot2015@holtznet.de>
- * @author      Jan Wagner <mail@jwagner.eu>
- *
- * @}
- */
-
-#include "cpu.h"
-#include "mutex.h"
-#include "periph/spi.h"
-#include "periph_conf.h"
-
-/* guard this file in case no SPI device is defined */
-#if SPI_NUMOF
-
-/* static port mapping */
-static NRF_SPI_Type *const spi[] = {
-#if SPI_0_EN
-    SPI_0_DEV,
-#endif
-#if SPI_1_EN
-    SPI_1_DEV
-#endif
-};
-
-/**
- * @brief   array holding one pre-initialized mutex for each SPI device
- */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
-{
-    if (dev >= SPI_NUMOF) {
-        return -1;
-    }
-
-    spi_poweron(dev);
-
-    /* disable the device -> nRF51822 reference 3.0 26.1.1 and 27.1*/
-    spi[dev]->ENABLE = 0;
-
-    switch (dev) {
-#if SPI_0_EN
-
-        case SPI_0:
-            /* disable TWI Interface */
-            NRF_TWI0->ENABLE = 0;
-            break;
-#endif
-#if SPI_1_EN
-
-        case SPI_1:
-            /* disable SPI Slave */
-            NRF_SPIS1->ENABLE = 0;
-            /* disable TWI Interface */
-            NRF_TWI1->ENABLE = 0;
-            break;
-#endif
-
-        default:
-            return -1;
-    }
-
-    /* configure direction of used pins */
-    spi_conf_pins(dev);
-
-    /* configure SPI mode */
-    switch (conf) {
-        case SPI_CONF_FIRST_RISING:
-            spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveHigh << 2) | (SPI_CONFIG_CPHA_Leading << 1);
-            break;
-
-        case SPI_CONF_SECOND_RISING:
-            spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveHigh << 2) | (SPI_CONFIG_CPHA_Trailing << 1);
-            break;
-
-        case SPI_CONF_FIRST_FALLING:
-            spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveLow << 2) | (SPI_CONFIG_CPHA_Leading << 1);
-            break;
-
-        case SPI_CONF_SECOND_FALLING:
-            spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveLow << 2) | (SPI_CONFIG_CPHA_Trailing << 1);
-            break;
-    }
-
-    /* select bus speed */
-    switch (speed) {
-        case SPI_SPEED_100KHZ:          /* 125 KHz for this device */
-            spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_K125;
-            break;
-
-        case SPI_SPEED_400KHZ:          /* 500 KHz for this device */
-            spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_K500;
-            break;
-
-        case SPI_SPEED_1MHZ:            /* 1 MHz for this device */
-            spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M1;
-            break;
-
-        case SPI_SPEED_5MHZ:            /* 4 MHz for this device */
-            spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M4;
-            break;
-
-        case SPI_SPEED_10MHZ:           /* 8 MHz for this device */
-            spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M8;
-            break;
-    }
-
-    /* finally enable the device */
-    spi[dev]->ENABLE = 1;
-    return 0;
-}
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data))
-{
-    /* This API is incompatible with nRF51 SPIS */
-    return -1;
-}
-
-int spi_conf_pins(spi_t dev)
-{
-    if (dev >= SPI_NUMOF) {
-        return -1;
-    }
-
-    switch (dev) {
-#if SPI_0_EN
-
-        case SPI_0:
-            /* set pin direction */
-            NRF_P0->DIRSET = (1 << SPI_0_PIN_MOSI) | (1 << SPI_0_PIN_SCK);
-            NRF_P0->DIRCLR = (1 << SPI_0_PIN_MISO);
-            /* select pins to be used by SPI */
-            spi[dev]->PSELMOSI = SPI_0_PIN_MOSI;
-            spi[dev]->PSELMISO = SPI_0_PIN_MISO;
-            spi[dev]->PSELSCK = SPI_0_PIN_SCK;
-            break;
-#endif
-#if SPI_1_EN
-
-        case SPI_1:
-            /* set pin direction */
-            NRF_P0->DIRSET = (1 << SPI_1_PIN_MOSI) | (1 << SPI_1_PIN_SCK);
-            NRF_P0->DIRCLR = (1 << SPI_1_PIN_MISO);
-            /* select pins to be used by SPI */
-            spi[dev]->PSELMOSI = SPI_1_PIN_MOSI;
-            spi[dev]->PSELMISO = SPI_1_PIN_MISO;
-            spi[dev]->PSELSCK = SPI_1_PIN_SCK;
-            break;
-#endif
-    }
-
-    return 0;
-}
-
-int spi_acquire(spi_t dev)
-{
-    if (dev >= SPI_NUMOF) {
-        return -1;
-    }
-
-    mutex_lock(&locks[dev]);
-    return 0;
-}
-
-int spi_release(spi_t dev)
-{
-    if (dev >= SPI_NUMOF) {
-        return -1;
-    }
-
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
-
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    return spi_transfer_bytes(dev, &out, in, 1);
-}
-
-int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length)
-{
-    if (dev >= SPI_NUMOF) {
-        return -1;
-    }
-
-    for (int i = 0; i < length; i++) {
-        char tmp = (out) ? out[i] : 0;
-        spi[dev]->EVENTS_READY = 0;
-        spi[dev]->TXD = (uint8_t)tmp;
-
-        while (spi[dev]->EVENTS_READY != 1);
-
-        tmp = (char)spi[dev]->RXD;
-
-        if (in) {
-            in[i] = tmp;
-        }
-    }
-
-    return length;
-}
-
-int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in)
-{
-    spi_transfer_byte(dev, reg, 0);
-    return spi_transfer_byte(dev, out, in);
-}
-
-int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length)
-{
-    spi_transfer_byte(dev, reg, 0);
-    return spi_transfer_bytes(dev, out, in, length);
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    /* spi slave is not implemented */
-}
-
-void spi_poweron(spi_t dev)
-{
-    if (dev < SPI_NUMOF) {
-        spi[dev]->POWER = 1;
-    }
-}
-
-void spi_poweroff(spi_t dev)
-{
-    if (dev < SPI_NUMOF) {
-        spi[dev]->POWER = 0;
-    }
-}
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/nrf5x_common/include/periph_cpu_common.h b/cpu/nrf5x_common/include/periph_cpu_common.h
index b22de8f0636ff0591452c0afe6b30e7dbb15ebac..dbb681aa8fc6b0ff507ea53de48783ee67042afe 100644
--- a/cpu/nrf5x_common/include/periph_cpu_common.h
+++ b/cpu/nrf5x_common/include/periph_cpu_common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2016 Freie Universität Berlin
+ * Copyright (C) 2015-2017 Freie Universität Berlin
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License v2.1. See the file LICENSE in the top level
@@ -47,6 +47,21 @@ extern "C" {
  */
 #define GPIO_MODE(oe, ic, pr)   (oe | (ic << 1) | (pr << 2))
 
+/**
+ * @brief   No support for HW chip select...
+ */
+#define SPI_HWCS(x)         (SPI_CS_UNDEF)
+
+/**
+ * @brief   Declare needed shared SPI functions
+ * @{
+ */
+#define PERIPH_SPI_NEEDS_INIT_CS
+#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
+#define PERIPH_SPI_NEEDS_TRANSFER_REG
+#define PERIPH_SPI_NEEDS_TRANSFER_REGS
+/** @} */
+
 #ifndef DOXYGEN
 /**
  * @brief   Override GPIO modes
@@ -106,6 +121,43 @@ typedef struct {
     uint8_t irqn;           /**< IRQ number of the timer device */
 } timer_conf_t;
 
+/**
+ * @brief   Override SPI mode values
+ * @{
+ */
+#define HAVE_SPI_MODE_T
+typedef enum {
+    SPI_MODE_0 = 0,                                             /**< CPOL=0, CPHA=0 */
+    SPI_MODE_1 = SPI_CONFIG_CPHA_Msk,                           /**< CPOL=0, CPHA=1 */
+    SPI_MODE_2 = SPI_CONFIG_CPOL_Msk,                           /**< CPOL=1, CPHA=0 */
+    SPI_MODE_3 = (SPI_CONFIG_CPOL_Msk | SPI_CONFIG_CPHA_Msk)    /**< CPOL=1, CPHA=1 */
+} spi_mode_t;
+/** @} */
+
+/**
+ * @brief   Override SPI clock values
+ * @{
+ */
+#define HAVE_SPI_CLK_T
+typedef enum {
+    SPI_CLK_100KHZ = SPI_FREQUENCY_FREQUENCY_K125,  /**< 100KHz */
+    SPI_CLK_400KHZ = SPI_FREQUENCY_FREQUENCY_K500,  /**< 400KHz */
+    SPI_CLK_1MHZ   = SPI_FREQUENCY_FREQUENCY_M1,    /**< 1MHz */
+    SPI_CLK_5MHZ   = SPI_FREQUENCY_FREQUENCY_M4,    /**< 5MHz */
+    SPI_CLK_10MHZ  = SPI_FREQUENCY_FREQUENCY_M8     /**< 10MHz */
+} spi_clk_t;
+/** @} */
+
+/**
+ * @brief  SPI configuration values
+ */
+typedef struct {
+    NRF_SPI_Type *dev;  /**< SPI device used */
+    uint8_t sclk;       /**< CLK pin */
+    uint8_t mosi;       /**< MOSI pin */
+    uint8_t miso;       /**< MISO pin */
+} spi_conf_t;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/cpu/nrf5x_common/periph/spi.c b/cpu/nrf5x_common/periph/spi.c
new file mode 100644
index 0000000000000000000000000000000000000000..913f56e957d74e8516ee21c695ae5be5654374bd
--- /dev/null
+++ b/cpu/nrf5x_common/periph/spi.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2014-2016 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_nrf5x_common
+ * @{
+ *
+ * @file
+ * @brief       Low-level SPI driver implementation
+ *
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ * @author      Frank Holtz <frank-riot2015@holtznet.de>
+ * @author      Jan Wagner <mail@jwagner.eu>
+ *
+ * @}
+ */
+
+#include "cpu.h"
+#include "mutex.h"
+#include "assert.h"
+#include "periph/spi.h"
+
+#ifdef SPI_NUMOF
+
+/**
+ * @brief   array holding one pre-initialized mutex for each SPI device
+ */
+static mutex_t locks[SPI_NUMOF];
+
+static inline NRF_SPI_Type *dev(spi_t bus)
+{
+    return spi_config[bus].dev;
+}
+
+void spi_init(spi_t bus)
+{
+    assert(bus < SPI_NUMOF);
+
+    /* initialize mutex */
+    mutex_init(&locks[bus]);
+    /* initialize pins */
+    spi_init_pins(bus);
+}
+
+void spi_init_pins(spi_t bus)
+{
+    /* set pin direction */
+    GPIO_BASE->DIRSET = ((1 << spi_config[bus].sclk) |
+                        (1 << spi_config[bus].mosi));
+    GPIO_BASE->DIRCLR =  (1 << spi_config[bus].miso);
+    /* select pins for the SPI device */
+    SPI_SCKSEL  = spi_config[bus].sclk;
+    SPI_MOSISEL = spi_config[bus].mosi;
+    SPI_MISOSEL = spi_config[bus].miso;
+}
+
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    mutex_lock(&locks[bus]);
+#ifdef CPU_FAM_NRF51
+    /* power on the bus (NRF51 only) */
+    dev(bus)->POWER = 1;
+#endif
+    /* configure bus */
+    dev(bus)->CONFIG = mode;
+    dev(bus)->FREQUENCY = clk;
+    /* enable the bus */
+    dev(bus)->ENABLE = 1;
+
+    return SPI_OK;
+}
+
+void spi_release(spi_t bus)
+{
+    /* power off everything */
+    dev(bus)->ENABLE = 0;
+#ifdef CPU_FAM_NRF51
+    dev(bus)->POWER = 0;
+#endif
+    mutex_unlock(&locks[bus]);
+}
+
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
+{
+    uint8_t *in_buf = (uint8_t *)in;
+    uint8_t *out_buf = (uint8_t *)out;
+
+    assert(out_buf || in_buf);
+
+    if (cs != SPI_CS_UNDEF) {
+        gpio_clear((gpio_t)cs);
+    }
+
+    for (int i = 0; i < (int)len; i++) {
+        uint8_t tmp = (out_buf) ? out_buf[i] : 0;
+
+        dev(bus)->EVENTS_READY = 0;
+        dev(bus)->TXD = (uint8_t)tmp;
+        while (dev(bus)->EVENTS_READY != 1);
+        tmp = (uint8_t)dev(bus)->RXD;
+
+        if (in_buf) {
+            in_buf[i] = tmp;
+        }
+    }
+
+    if ((cs != SPI_CS_UNDEF) && (!cont)) {
+        gpio_set((gpio_t)cs);
+    }
+}
+
+#endif /* SPI_NUMOF */
diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h
index 721ca0da1ff75c9a9179fa0eec60b5f8e36a15ba..954877d0b985174c9e2b974da22952a0ae276396 100644
--- a/cpu/sam0_common/include/periph_cpu_common.h
+++ b/cpu/sam0_common/include/periph_cpu_common.h
@@ -34,7 +34,8 @@ extern "C" {
  * @brief   Use shared SPI functions
  * @{
  */
-#define PERIPH_SPI_NEEDS_TRANSFER_BYTES
+#define PERIPH_SPI_NEEDS_INIT_CS
+#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
 #define PERIPH_SPI_NEEDS_TRANSFER_REG
 #define PERIPH_SPI_NEEDS_TRANSFER_REGS
 /** @} */
@@ -127,15 +128,46 @@ typedef enum {
 } spi_mosipad_t;
 
 /**
- * @brief   Possible selections for SERCOM SPI clock mode (inspired by Arduino)
+ * @brief   Override SPI modes
+ * @{
  */
-typedef enum
-{
-    SERCOM_SPI_MODE_0 = 0,      // CPOL : 0  | CPHA : 0
-    SERCOM_SPI_MODE_1 = 1,      // CPOL : 0  | CPHA : 1
-    SERCOM_SPI_MODE_2 = 2,      // CPOL : 1  | CPHA : 0
-    SERCOM_SPI_MODE_3 = 3,      // CPOL : 1  | CPHA : 1
-} sercom_spi_clockmode_t;
+#define HAVE_SPI_MODE_T
+typedef enum {
+    SPI_MODE_0 = 0x0,       /**< CPOL=0, CPHA=0 */
+    SPI_MODE_1 = 0x1,       /**< CPOL=0, CPHA=1 */
+    SPI_MODE_2 = 0x2,       /**< CPOL=1, CPHA=0 */
+    SPI_MODE_3 = 0x3        /**< CPOL=1, CPHA=1 */
+} spi_mode_t;
+/** @} */
+
+/**
+ * @brief   Override SPI clock speed values
+ * @{
+ */
+#define HAVE_SPI_CLK_T
+typedef enum {
+    SPI_CLK_100KHZ =   100000U, /**< drive the SPI bus with 100KHz */
+    SPI_CLK_400KHZ =   400000U, /**< drive the SPI bus with 400KHz */
+    SPI_CLK_1MHZ   =  1000000U, /**< drive the SPI bus with 1MHz */
+    SPI_CLK_5MHZ   =  5000000U, /**< drive the SPI bus with 5MHz */
+    SPI_CLK_10MHZ  = 10000000U  /**< drive the SPI bus with 10MHz */
+} spi_clk_t;
+/** @} */
+
+/**
+ * @brief   SPI device configuration
+ */
+typedef struct {
+    SercomSpi *dev;         /**< pointer to the used SPI device */
+    gpio_t miso_pin;        /**< used MISO pin */
+    gpio_t mosi_pin;        /**< used MOSI pin */
+    gpio_t clk_pin;         /**< used CLK pin */
+    gpio_mux_t miso_mux;    /**< alternate function for MISO pin (mux) */
+    gpio_mux_t mosi_mux;    /**< alternate function for MOSI pin (mux) */
+    gpio_mux_t clk_mux;     /**< alternate function for CLK pin (mux) */
+    spi_misopad_t miso_pad; /**< pad to use for MISO line */
+    spi_mosipad_t mosi_pad; /**< pad to use for MOSI and CLK line */
+} spi_conf_t;
 
 /**
  * @brief   Set up alternate function (PMUX setting) for a PORT pin
@@ -145,6 +177,18 @@ typedef enum
  */
 void gpio_init_mux(gpio_t pin, gpio_mux_t mux);
 
+/**
+ * @brief   Return the numeric id of a SERCOM device derived from its address
+ *
+ * @param[in] sercom    SERCOM device
+ *
+ * @return              numeric id of the given SERCOM device
+ */
+static inline int sercom_id(void *sercom)
+{
+    return ((((uint32_t)sercom) >> 10) & 0x7) - 2;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/cpu/sam0_common/periph/spi.c b/cpu/sam0_common/periph/spi.c
new file mode 100644
index 0000000000000000000000000000000000000000..65b78e78c3eec6b9854f0c0a3f6c9178e1f9cc51
--- /dev/null
+++ b/cpu/sam0_common/periph/spi.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2014-2016 Freie Universität Berlin
+ *               2015 Kaspar Schleiser <kaspar@schleiser.de>
+ *               2015 FreshTemp, LLC.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_samd21
+ * @{
+ *
+ * @file
+ * @brief       Low-level SPI driver implementation
+ *
+ * @author      Thomas Eichinger <thomas.eichinger@fu-berlin.de>
+ * @author      Troels Hoffmeyer <troels.d.hoffmeyer@gmail.com>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * @}
+ */
+
+#include "cpu.h"
+#include "mutex.h"
+#include "assert.h"
+#include "periph/spi.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+/**
+ * @brief Array holding one pre-initialized mutex for each SPI device
+ */
+static mutex_t locks[SPI_NUMOF];
+
+/**
+ * @brief   Shortcut for accessing the used SPI SERCOM device
+ */
+static inline SercomSpi *dev(spi_t bus)
+{
+    return spi_config[bus].dev;
+}
+
+static inline void poweron(spi_t bus)
+{
+#if defined(CPU_FAM_SAMD21)
+    PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << sercom_id(dev(bus)));
+#elif defined(CPU_FAM_SAML21)
+    MCLK->APBCMASK.reg |= (MCLK_APBCMASK_SERCOM0 << sercom_id(dev(bus)));
+#endif
+}
+
+static inline void poweroff(spi_t bus)
+{
+#if defined(CPU_FAM_SAMD21)
+    PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << sercom_id(dev(bus)));
+#elif defined(CPU_FAM_SAML21)
+    MCLK->APBCMASK.reg &= ~(MCLK_APBCMASK_SERCOM0 << sercom_id(dev(bus)));
+#endif
+}
+
+void spi_init(spi_t bus)
+{
+    /* make sure given bus is good */
+    assert(bus < SPI_NUMOF);
+
+    /* initialize the device lock */
+    mutex_init(&locks[bus]);
+
+    /* configure pins and their muxes */
+    spi_init_pins(bus);
+
+    /* wake up device */
+    poweron(bus);
+
+    /* reset all device configuration */
+    dev(bus)->CTRLA.reg |= SERCOM_SPI_CTRLA_SWRST;
+    while ((dev(bus)->CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) ||
+           (dev(bus)->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_SWRST));
+
+    /* configure base clock: using GLK GEN 0 */
+#if defined(CPU_FAM_SAMD21)
+    GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 |
+                         (SERCOM0_GCLK_ID_CORE + sercom_id(dev(bus))));
+    while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
+#elif defined(CPU_FAM_SAML21)
+    GCLK->PCHCTRL[SERCOM0_GCLK_ID_CORE + sercom_id(dev(bus))].reg =
+                                (GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0);
+#endif
+
+    /* enable receiver and configure character size to 8-bit
+     * no synchronization needed, as SERCOM device is not enabled */
+    dev(bus)->CTRLB.reg = (SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN);
+
+    /* put device back to sleep */
+    poweroff(bus);
+}
+
+void spi_init_pins(spi_t bus)
+{
+    gpio_init(spi_config[bus].miso_pin, GPIO_IN);
+    gpio_init(spi_config[bus].mosi_pin, GPIO_OUT);
+    gpio_init(spi_config[bus].clk_pin, GPIO_OUT);
+    gpio_init_mux(spi_config[bus].miso_pin, spi_config[bus].miso_mux);
+    gpio_init_mux(spi_config[bus].mosi_pin, spi_config[bus].mosi_mux);
+    gpio_init_mux(spi_config[bus].clk_pin, spi_config[bus].clk_mux);
+}
+
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    /* get exclusive access to the device */
+    mutex_lock(&locks[bus]);
+    /* power on the device */
+    poweron(bus);
+
+    /* configure bus clock, in synchronous mode its calculated from
+     * BAUD.reg = (f_ref / (2 * f_bus) - 1)
+     * with f_ref := CLOCK_CORECLOCK as defined by the board */
+    dev(bus)->BAUD.reg = (uint8_t)(((uint32_t)CLOCK_CORECLOCK) / (2 * clk) - 1);
+
+    /* configure device to be master and set mode and pads,
+     *
+     * NOTE: we could configure the pads already during spi_init, but for
+     * efficiency reason we do that here, so we can do all in one single write
+     * to the CTRLA register */
+    dev(bus)->CTRLA.reg = (SERCOM_SPI_CTRLA_MODE(0x3) |     /* 0x3 -> master */
+                           SERCOM_SPI_CTRLA_DOPO(spi_config[bus].mosi_pad) |
+                           SERCOM_SPI_CTRLA_DIPO(spi_config[bus].miso_pad) |
+                           (mode <<  SERCOM_SPI_CTRLA_CPOL_Pos));
+    /* also no synchronization needed here, as CTRLA is write-synchronized */
+
+    /* finally enable the device */
+    dev(bus)->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE;
+    while (dev(bus)->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_ENABLE) {}
+
+    return SPI_OK;
+}
+
+void spi_release(spi_t bus)
+{
+    /* disable device and put it back to sleep */
+    dev(bus)->CTRLA.reg &= ~(SERCOM_SPI_CTRLA_ENABLE);
+    while (dev(bus)->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_ENABLE) {}
+    poweroff(bus);
+    /* release access to the device */
+    mutex_unlock(&locks[bus]);
+}
+
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
+{
+    uint8_t *out_buf = (uint8_t *)out;
+    uint8_t *in_buf = (uint8_t *)in;
+
+    assert(out || in);
+
+    if (cs != SPI_CS_UNDEF) {
+        gpio_clear((gpio_t)cs);
+    }
+
+    for (int i = 0; i < (int)len; i++) {
+        uint8_t tmp = (out_buf) ? out_buf[i] : 0;
+        while (!(dev(bus)->INTFLAG.reg & SERCOM_SPI_INTFLAG_DRE)) {}
+        dev(bus)->DATA.reg = tmp;
+        while (!(dev(bus)->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC)) {}
+        tmp = (uint8_t)dev(bus)->DATA.reg;
+        if (in_buf) {
+            in_buf[i] = tmp;
+        }
+    }
+
+    if ((!cont) && (cs != SPI_CS_UNDEF)) {
+        gpio_set((gpio_t)cs);
+    }
+}
diff --git a/cpu/sam3/cpu.c b/cpu/sam3/cpu.c
index aaa18578b67d79fc054a4a37c8963909b3ba3ab6..2b7ff7db4d06a048778c772a47387e153e51a0bd 100644
--- a/cpu/sam3/cpu.c
+++ b/cpu/sam3/cpu.c
@@ -19,6 +19,7 @@
 
 #include "cpu.h"
 #include "periph_conf.h"
+#include "periph/init.h"
 
 /**
  * @brief   Keys needed for editing certain PMC registers
@@ -88,4 +89,7 @@ void cpu_init(void)
     PMC->PMC_MCKR = PMC_MCKR_CSS_PLLA_CLK;
     /* wait for master clock to be ready */
     while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
+
+    /* trigger static peripheral initialization */
+    periph_init();
 }
diff --git a/cpu/sam3/include/periph_cpu.h b/cpu/sam3/include/periph_cpu.h
index 4921a1c1c77999ebac6200e396ec5bc1cf2442af..89b44b92c9a380f23b1b75afe0c81b94a5b4239a 100644
--- a/cpu/sam3/include/periph_cpu.h
+++ b/cpu/sam3/include/periph_cpu.h
@@ -24,7 +24,6 @@
 
 #include "cpu.h"
 
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -50,7 +49,8 @@ typedef uint32_t gpio_t;
  * @brief Declare needed generic SPI functions
  * @{
  */
-#define PERIPH_SPI_NEEDS_TRANSFER_BYTES
+#define PERIPH_SPI_NEEDS_INIT_CS
+#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
 #define PERIPH_SPI_NEEDS_TRANSFER_REG
 #define PERIPH_SPI_NEEDS_TRANSFER_REGS
 /** @} */
@@ -127,6 +127,33 @@ typedef enum {
     GPIO_MUX_B = 1,         /**< alternate function B */
 } gpio_mux_t;
 
+/**
+ * @brief   Override default SPI modes
+ * @{
+ */
+#define HAVE_SPI_MODE_T
+typedef enum {
+    SPI_MODE_0 = (SPI_CSR_NCPHA),                   /**< CPOL=0, CPHA=0 */
+    SPI_MODE_1 = (0),                               /**< CPOL=0, CPHA=1 */
+    SPI_MODE_2 = (SPI_CSR_CPOL | SPI_CSR_NCPHA),    /**< CPOL=1, CPHA=0 */
+    SPI_MODE_3 = (SPI_CSR_CPOL)                     /**< CPOL=1, CPHA=1 */
+} spi_mode_t;
+/** @} */
+
+/**
+ * @brief   Override default SPI clock values
+ * @{
+ */
+#define HAVE_SPI_CLK_T
+typedef enum {
+    SPI_CLK_100KHZ = (100000),                      /**< 100KHz */
+    SPI_CLK_400KHZ = (400000),                      /**< 400KHz */
+    SPI_CLK_1MHZ   = (1000000),                     /**< 1MHz */
+    SPI_CLK_5MHZ   = (5000000),                     /**< 5MHz */
+    SPI_CLK_10MHZ  = (10000000)                     /**< 10MHz */
+} spi_clk_t;
+/** @} */
+
 /**
  * @brief   Timer configuration data
  */
@@ -157,6 +184,18 @@ typedef struct {
     uint8_t hwchan;         /**< the HW channel used for a logical channel */
 } pwm_chan_conf_t;
 
+/**
+ * @brief   SPI configuration data
+ */
+typedef struct {
+    Spi *dev;               /**< SPI module to use */
+    uint8_t id;             /**< corresponding ID of that module */
+    gpio_t clk;             /**< pin mapped to the CLK line */
+    gpio_t mosi;            /**< pin mapped to the MOSI line */
+    gpio_t miso;            /**< pin mapped to the MISO line */
+    gpio_mux_t mux;         /**< pin MUX setting */
+} spi_conf_t;
+
 /**
  * @brief   Configure the given GPIO pin to be used with the given MUX setting
  *
diff --git a/cpu/sam3/periph/spi.c b/cpu/sam3/periph/spi.c
index a86f5e2fd65b1d584973353485b1193c286c5415..72f952e2aefe3aa220dd75939bd91418daf8b4dd 100644
--- a/cpu/sam3/periph/spi.c
+++ b/cpu/sam3/periph/spi.c
@@ -1,13 +1,14 @@
 /*
 * Copyright (C) 2014 Hamburg University of Applied Sciences
-*
-* This file is subject to the terms and conditions of the GNU Lesser General
-* Public License v2.1. See the file LICENSE in the top level directory for more
-* details.
+*               2016-2017 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
 */
 
 /**
- * @ingroup     cpu_sam3x8e
+ * @ingroup     cpu_sam3
  * @{
  *
  * @file
@@ -23,347 +24,103 @@
 
 #include "cpu.h"
 #include "mutex.h"
+#include "assert.h"
 #include "periph/gpio.h"
-#include "periph_conf.h"
 #include "periph/spi.h"
-#include "sam3x8e.h"
 
-/* guard this file in case no SPI device is defined */
-#if SPI_NUMOF
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
 
 /**
- * @brief Array holding one pre-initialized mutex for each SPI device
+ * @brief   Array holding one pre-initialized mutex for each SPI device
  */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-#if SPI_2_EN
-    [SPI_2] = MUTEX_INIT
-#endif
-};
-
-typedef struct {
-    char(*cb)(char data);
-} spi_state_t;
-
-static inline void irq_handler_transfer(Spi *spi, spi_t dev);
+static mutex_t locks[SPI_NUMOF];
 
-static spi_state_t spi_config[SPI_NUMOF];
-
-void spi_poweron(spi_t dev)
+static inline Spi *dev(spi_t bus)
 {
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            SPI_0_CLKEN();
-            SPI_0_MISO_PORT_CLKEN();
-            SPI_0_MOSI_PORT_CLKEN();
-            SPI_0_SCK_PORT_CLKEN();
-            break;
-#endif /* SPI_0_EN */
-    }
-}
-
-void spi_poweroff(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            while (!(SPI_0_DEV->SPI_SR & SPI_SR_SPIENS)) {} /* not busy anymore */
-            SPI_0_CLKDIS();
-            NVIC_DisableIRQ(SPI_0_IRQ);
-            break;
-#endif /* SPI_0_EN */
-    }
+    return spi_config[bus].dev;
 }
 
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
+void spi_init(spi_t bus)
 {
-    uint8_t speed_divider;
-    Spi *spi_port;
-
-    spi_poweron(dev);
-
-    switch (speed) {
-        case SPI_SPEED_400KHZ:
-            speed_divider = 210;
-            break;
-
-        case SPI_SPEED_1MHZ:
-            speed_divider = 84;
-            break;
-
-        case SPI_SPEED_5MHZ:
-            speed_divider = 17;
-            break;
-
-        case SPI_SPEED_10MHZ: /* this might be too fast */
-            speed_divider = 8;
-            break;
-
-        default:
-            return -1;
-    }
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi_port = SPI_0_DEV;
-            break;
-#endif /* SPI_0_EN */
-        default:
-            return -2;
-    }
+    assert(bus < SPI_NUMOF);
 
-    /* Configure SCK, MISO and MOSI pin */
-    spi_conf_pins(dev);
-
-    /***************** SPI-Init *****************/
-
-    /* Chip Select Register */
-    spi_port->SPI_CSR[0] = 0; /* This is index 0 since we don't use internal CS-Signals */
-
-    switch (conf) {
-        case SPI_CONF_FIRST_RISING:
-            spi_port->SPI_CSR[0] &= ~SPI_CSR_CPOL;
-            spi_port->SPI_CSR[0] |= SPI_CSR_NCPHA;
-            break;
-
-        case SPI_CONF_SECOND_RISING:
-            spi_port->SPI_CSR[0] &= ~SPI_CSR_CPOL;
-            spi_port->SPI_CSR[0] &= ~SPI_CSR_NCPHA;
-            break;
-
-        case SPI_CONF_FIRST_FALLING:
-            spi_port->SPI_CSR[0] |= SPI_CSR_CPOL;
-            spi_port->SPI_CSR[0] |= SPI_CSR_NCPHA;
-            break;
-
-        case SPI_CONF_SECOND_FALLING:
-            spi_port->SPI_CSR[0] |= SPI_CSR_CPOL;
-            spi_port->SPI_CSR[0] &= ~ SPI_CSR_NCPHA;
-            break;
-
-        default:
-            return -2;
-    }
-
-    spi_port->SPI_CSR[0] |= SPI_CSR_SCBR(speed_divider);
-    spi_port->SPI_CSR[0] |= SPI_CSR_BITS_8_BIT;
-
-    /* Control Register */
-    spi_port->SPI_CR |= SPI_CR_SPIEN;
-    /* Mode Register */
-    spi_port->SPI_MR = 0;
-    spi_port->SPI_MR |= SPI_MR_MSTR;
-    spi_port->SPI_MR |= SPI_MR_MODFDIS;
-    spi_port->SPI_MR &= ~SPI_MR_PS;
-    spi_port->SPI_MR &= ~SPI_MR_PCS(0);
-
-    return 0;
+    /* initialize device lock */
+    mutex_init(&locks[bus]);
+    /* initialize pins */
+    spi_init_pins(bus);
 }
 
-int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data))
+void spi_init_pins(spi_t bus)
 {
-    Spi *spi_port;
-
-    spi_poweron(dev);
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi_port = SPI_0_DEV;
-            NVIC_SetPriority(SPI_0_IRQ, SPI_0_IRQ_PRIO);
-            NVIC_EnableIRQ(SPI_0_IRQ);
-            /* Initialize predefined NSS pin as output so it is "disabled" */
-            PIOA->PIO_PER |= PIO_PA28A_SPI0_NPCS0;
-            PIOA->PIO_OER |= PIO_PA28A_SPI0_NPCS0;
-            break;
-#endif /* SPI_0_EN */
-        default:
-            return -1;
-    }
-
-    /* Configure SCK, MISO and MOSI pin */
-    spi_conf_pins(dev);
-
-    /***************** SPI-Init *****************/
-
-    /* Chip Select Register */
-    spi_port->SPI_CSR[0] = 0;
-
-    switch (conf) {
-        case SPI_CONF_FIRST_RISING:
-            spi_port->SPI_CSR[0] &= ~SPI_CSR_CPOL;
-            spi_port->SPI_CSR[0] |= SPI_CSR_NCPHA;
-            break;
-
-        case SPI_CONF_SECOND_RISING:
-            spi_port->SPI_CSR[0] &= ~SPI_CSR_CPOL;
-            spi_port->SPI_CSR[0] &= ~SPI_CSR_NCPHA;
-            break;
-
-        case SPI_CONF_FIRST_FALLING:
-            spi_port->SPI_CSR[0] |= SPI_CSR_CPOL;
-            spi_port->SPI_CSR[0] |= SPI_CSR_NCPHA;
-            break;
-
-        case SPI_CONF_SECOND_FALLING:
-            spi_port->SPI_CSR[0] |= SPI_CSR_CPOL;
-            spi_port->SPI_CSR[0] &= ~ SPI_CSR_NCPHA;
-            break;
-
-        default:
-            return -1;
-    }
-
-    /* Control Register */
-    spi_port->SPI_CR |= SPI_CR_SPIEN;
-    /* Mode Register */
-    spi_port->SPI_MR = 0;
-    spi_port->SPI_MR |= SPI_MR_MODFDIS;
-    /* Enable SPI interrupts */
-    spi_port->SPI_IER = 0;
-    spi_port->SPI_IDR = ~(0);
-    spi_port->SPI_IER |= 1;
-    spi_port->SPI_IDR &= ~SPI_IDR_RDRF;
-
-    /* Set callback */
-    spi_config[dev].cb = cb;
-
-    return 0;
+    gpio_init(spi_config[bus].clk, GPIO_OUT);
+    gpio_init(spi_config[bus].mosi, GPIO_OUT);
+    gpio_init(spi_config[bus].miso, GPIO_IN);
+    gpio_init_mux(spi_config[bus].clk, spi_config[bus].mux);
+    gpio_init_mux(spi_config[bus].mosi, spi_config[bus].mux);
+    gpio_init_mux(spi_config[bus].miso, spi_config[bus].mux);
 }
 
-int spi_conf_pins(spi_t dev)
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
 {
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            /***************** PIO-Init *****************/
-            /* Push-pull configuration */
-            SPI_0_MISO_PORT->PIO_MDER &= ~SPI_0_MISO_PIN;
-            SPI_0_MISO_PORT->PIO_MDDR |= SPI_0_MISO_PIN;
-            SPI_0_MOSI_PORT->PIO_MDER &= ~SPI_0_MOSI_PIN;
-            SPI_0_MOSI_PORT->PIO_MDDR |= SPI_0_MOSI_PIN;
-            SPI_0_SCK_PORT->PIO_MDER &= ~SPI_0_SCK_PIN;
-            SPI_0_SCK_PORT->PIO_MDDR |= SPI_0_SCK_PIN;
-
-            /* With pull-up resistors */
-            SPI_0_MISO_PORT->PIO_PUDR &= ~SPI_0_MISO_PIN;
-            SPI_0_MISO_PORT->PIO_PUER |= SPI_0_MISO_PIN;
-            SPI_0_MOSI_PORT->PIO_PUDR &= ~SPI_0_MOSI_PIN;
-            SPI_0_MOSI_PORT->PIO_PUER |= SPI_0_MOSI_PIN;
-            SPI_0_SCK_PORT->PIO_PUDR &= ~SPI_0_SCK_PIN;
-            SPI_0_SCK_PORT->PIO_PUER |= SPI_0_SCK_PIN;
-
-            /* Clear output */
-            SPI_0_MISO_PORT->PIO_SODR &= ~SPI_0_MISO_PIN;
-            SPI_0_MISO_PORT->PIO_CODR |= SPI_0_MISO_PIN;
-            SPI_0_MOSI_PORT->PIO_SODR &= ~SPI_0_MOSI_PIN;
-            SPI_0_MOSI_PORT->PIO_CODR |= SPI_0_MOSI_PIN;
-            SPI_0_SCK_PORT->PIO_SODR &= ~SPI_0_SCK_PIN;
-            SPI_0_SCK_PORT->PIO_CODR |= SPI_0_SCK_PIN;
-
-            /* Peripheral Function Selection */
-            SPI_0_MISO_PORT->PIO_PER &= ~SPI_0_MISO_PIN;
-            SPI_0_MISO_PORT->PIO_PDR |= SPI_0_MISO_PIN;
-            SPI_0_MOSI_PORT->PIO_PER &= ~SPI_0_MOSI_PIN;
-            SPI_0_MOSI_PORT->PIO_PDR |= SPI_0_MOSI_PIN;
-            SPI_0_SCK_PORT->PIO_PER &= ~SPI_0_SCK_PIN;
-            SPI_0_SCK_PORT->PIO_PDR |= SPI_0_SCK_PIN;
-
-            /* Peripheral A */
-            SPI_0_MISO_PORT->PIO_ABSR &= ~SPI_0_MISO_PIN;
-            SPI_0_MOSI_PORT->PIO_ABSR &= ~SPI_0_MOSI_PIN;
-            SPI_0_SCK_PORT->PIO_ABSR &= ~SPI_0_SCK_PIN;
-
-            break;
-#endif /* SPI_0_EN */
-        default:
-            return -1;
-    }
-
-    return 0;
+    /* lock bus */
+    mutex_lock(&locks[bus]);
+    /* enable SPI device clock */
+    PMC->PMC_PCER0 |= (1 << spi_config[bus].id);
+    /* set mode and speed */
+    dev(bus)->SPI_CSR[0] = (SPI_CSR_SCBR(CLOCK_CORECLOCK / clk) | mode);
+    dev(bus)->SPI_MR = (SPI_MR_MSTR | SPI_MR_MODFDIS);
+    dev(bus)->SPI_CR = SPI_CR_SPIEN;
+
+    return SPI_OK;
 }
 
-int spi_acquire(spi_t dev)
+void spi_release(spi_t bus)
 {
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
+    /* disable device and turn off clock signal */
+    dev(bus)->SPI_CR = 0;
+    PMC->PMC_PCER0 &= ~(1 << spi_config[bus].id);
+    /* release device lock */
+    mutex_unlock(&locks[bus]);
 }
 
-int spi_release(spi_t dev)
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
 {
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
+    uint8_t *out_buf = (uint8_t *)out;
+    uint8_t *in_buf = (uint8_t *)in;
 
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    Spi *spi_port;
+    assert(in_buf || out_buf);
 
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi_port = SPI_0_DEV;
-            break;
-#endif /* SPI_0_EN */
-        default:
-            return -1;
+    if (cs != SPI_CS_UNDEF) {
+        gpio_clear((gpio_t)cs);
     }
 
-    while (!(spi_port->SPI_SR & SPI_SR_TDRE)) {}
-
-    spi_port->SPI_TDR = SPI_TDR_TD(out);
-
-    while (!(spi_port->SPI_SR & SPI_SR_RDRF)) {}
-
-    *in = spi_port->SPI_RDR & SPI_RDR_RD_Msk;
-
-    return 1;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            SPI_0_DEV->SPI_TDR = SPI_TDR_TD(reset_val);
-            break;
-#endif /* SPI_0_EN */
+    if (!in_buf) {
+        for (size_t i = 0; i < len; i++) {
+            while(!(dev(bus)->SPI_SR & SPI_SR_TDRE)) {}
+            dev(bus)->SPI_TDR = out_buf[i];
+        }
+        while (!(dev(bus)->SPI_SR & SPI_SR_RDRF)) {}
+        dev(bus)->SPI_RDR;
     }
-}
-
-static inline void irq_handler_transfer(Spi *spi, spi_t dev)
-{
-    if (spi->SPI_SR & SPI_SR_RDRF) {
-        char data;
-        data = spi->SPI_RDR & SPI_RDR_RD_Msk;
-        data = spi_config[dev].cb(data);
-        spi->SPI_TDR = SPI_TDR_TD(data);
+    else if (!out_buf) {
+        for (size_t i = 0; i < len; i++) {
+            dev(bus)->SPI_TDR = 0;
+            while (!(dev(bus)->SPI_SR & SPI_SR_RDRF)) {}
+            in_buf[i] = dev(bus)->SPI_RDR;
+        }
+    }
+    else {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SPI_SR & SPI_SR_TDRE));
+            dev(bus)->SPI_TDR = out_buf[i];
+            while (!(dev(bus)->SPI_SR & SPI_SR_RDRF));
+            in_buf[i] = dev(bus)->SPI_RDR;
+        }
     }
 
-    /* See if a thread with higher priority wants to run now */
-    cortexm_isr_end();
-}
-
-#if SPI_0_EN
-void SPI_0_IRQ_HANDLER(void)
-{
-    if (SPI_0_DEV->SPI_SR & SPI_SR_RDRF) {
-        irq_handler_transfer(SPI_0_DEV, SPI_0);
+    if ((!cont) && (cs != SPI_CS_UNDEF)) {
+        gpio_set((gpio_t)cs);
     }
 }
-#endif
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/samd21/cpu.c b/cpu/samd21/cpu.c
index cef8383a01368e39a324a78bfa52aad5c5c9a917..a4a80864c7f7ca18ff6c5e59b2c7d9c15b52e5b2 100644
--- a/cpu/samd21/cpu.c
+++ b/cpu/samd21/cpu.c
@@ -20,6 +20,7 @@
 
 #include "cpu.h"
 #include "periph_conf.h"
+#include "periph/init.h"
 
 /**
  * @brief   Configure clock sources and the cpu frequency
@@ -107,4 +108,6 @@ void cpu_init(void)
     cortexm_init();
     /* Initialise clock sources and generic clocks */
     clk_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
diff --git a/cpu/samd21/include/periph_cpu.h b/cpu/samd21/include/periph_cpu.h
index 14ad374ebe158f92d0ea3b86d72fd5a21a8c1ee7..97dc3a21407c7fe5045337845e62abdd49f1a51f 100644
--- a/cpu/samd21/include/periph_cpu.h
+++ b/cpu/samd21/include/periph_cpu.h
@@ -19,6 +19,8 @@
 #ifndef CPU_PERIPH_H
 #define CPU_PERIPH_H
 
+#include <limits.h>
+
 #include "periph_cpu_common.h"
 
 #ifdef __cplusplus
@@ -44,6 +46,13 @@ enum {
  */
 #define GPIO_MODE(pr, ie, pe)   (pr | (ie << 1) | (pe << 2))
 
+/**
+ * @brief   Override SPI hardware chip select macro
+ *
+ * As of now, we do not support HW CS, so we always set it to a fixed value
+ */
+#define SPI_HWCS(x)     (UINT_MAX - 1)
+
 #ifndef DOXYGEN
 /**
  * @brief   Override GPIO modes
diff --git a/cpu/samd21/periph/spi.c b/cpu/samd21/periph/spi.c
deleted file mode 100644
index f7eef079f6777b999694bd2da53201945e8dde44..0000000000000000000000000000000000000000
--- a/cpu/samd21/periph/spi.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (C) 2014 Freie Universität Berlin
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
- */
-
-/**
- * @ingroup     cpu_samd21
- * @{
- *
- * @file
- * @brief       Low-level SPI driver implementation
- *
- * @author      Thomas Eichinger <thomas.eichinger@fu-berlin.de>
- * @author      Troels Hoffmeyer <troels.d.hoffmeyer@gmail.com>
- * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
- *
- * @}
- */
-
-#include "cpu.h"
-#include "mutex.h"
-#include "periph/gpio.h"
-#include "periph/spi.h"
-#include "periph_conf.h"
-#include "board.h"
-#define ENABLE_DEBUG (0)
-#include "debug.h"
-
-#if SPI_0_EN  || SPI_1_EN
-
-/**
- * @brief Internal helper function to do the actual work for spi_poweroff
- */
-static void _spi_poweroff(SercomSpi* spi_dev);
-
-/**
- * @brief Internal helper function to do the actual work for spi_poweron
- */
-static void _spi_poweron(SercomSpi* spi_dev);
-
-/**
- * @brief Array holding one pre-initialized mutex for each SPI device
- */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-#if SPI_2_EN
-    [SPI_2] = MUTEX_INIT
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
-{
-    SercomSpi* spi_dev = 0;
-    uint8_t sercom_gclk_id = 0;
-    gpio_t pin_sclk = 0;
-    gpio_t pin_miso = 0;
-    gpio_t pin_mosi = 0;
-    gpio_mux_t mux_sclk = 0;
-    gpio_mux_t mux_miso = 0;
-    gpio_mux_t mux_mosi = 0;
-    spi_mosipad_t mosi_pad = 0;
-    spi_misopad_t miso_pad = 0;
-    uint32_t   cpha = 0;
-    uint32_t   cpol = 0;
-    uint32_t   f_baud = 0;
-    switch (speed)
-    {
-    case SPI_SPEED_100KHZ:
-        f_baud = 100000;
-        break;
-    case SPI_SPEED_400KHZ:
-        f_baud = 400000;
-        break;
-    case SPI_SPEED_1MHZ:
-        f_baud = 1000000;
-        break;
-    case SPI_SPEED_5MHZ:
-#if CLOCK_CORECLOCK >= 5000000
-        f_baud = 5000000;
-        break;
-#else
-        return -1;
-#endif
-    case SPI_SPEED_10MHZ:
-#if CLOCK_CORECLOCK >= 10000000
-        f_baud = 10000000;
-        break;
-#else
-        return -1;
-#endif
-    }
-    switch (conf)
-    {
-    case SPI_CONF_FIRST_RISING:         /**< first data bit is transacted on the first rising SCK edge */
-        cpha = 0;
-        cpol = 0;
-        break;
-    case SPI_CONF_SECOND_RISING:        /**< first data bit is transacted on the second rising SCK edge */
-        cpha = SERCOM_SPI_CTRLA_CPHA;
-        cpol = 0;
-        break;
-    case SPI_CONF_FIRST_FALLING:        /**< first data bit is transacted on the first falling SCK edge */
-        cpha = 0;
-        cpol = SERCOM_SPI_CTRLA_CPOL;
-        break;
-    case SPI_CONF_SECOND_FALLING:       /**< first data bit is transacted on the second falling SCK edge */
-        cpha = SERCOM_SPI_CTRLA_CPHA;
-        cpol = SERCOM_SPI_CTRLA_CPOL;
-        break;
-    }
-    switch (dev)
-    {
-#if SPI_0_EN
-    case SPI_0:
-        spi_dev = &SPI_0_DEV;
-        sercom_gclk_id = SPI_0_GCLK_ID;
-        pin_sclk = SPI_0_SCLK;
-        mux_sclk = SPI_0_SCLK_MUX;
-        pin_miso = SPI_0_MISO;
-        mux_miso = SPI_0_MISO_MUX;
-        pin_mosi = SPI_0_MOSI;
-        mux_mosi = SPI_0_MOSI_MUX;
-        mosi_pad = SPI_0_MOSI_PAD;
-        miso_pad = SPI_0_MISO_PAD;
-        break;
-#endif
-#if SPI_1_EN
-    case SPI_1:
-        spi_dev = &SPI_1_DEV;
-        sercom_gclk_id = SPI_1_GCLK_ID;
-        pin_sclk = SPI_1_SCLK;
-        mux_sclk = SPI_1_SCLK_MUX;
-        pin_miso = SPI_1_MISO;
-        mux_miso = SPI_1_MISO_MUX;
-        pin_mosi = SPI_1_MOSI;
-        mux_mosi = SPI_1_MOSI_MUX;
-        mosi_pad = SPI_1_MOSI_PAD;
-        miso_pad = SPI_1_MISO_PAD;
-        break;
-#endif
-    default:
-        return -1;
-    }
-
-    /* Use the same sequence as ArduinoCore
-     *  - setup pins
-     *  - disable SPI
-     *  - init SPI (reset, init clock NVIC, CTRLA, CTRLB)
-     *  - init cpha/cpol, BAUD.reg
-     *  - enable SPI
-     */
-    gpio_init(pin_miso, GPIO_IN_PD);
-    gpio_init_mux(pin_sclk, mux_sclk);
-    gpio_init_mux(pin_miso, mux_miso);
-    gpio_init_mux(pin_mosi, mux_mosi);
-
-    /* Disable spi to write confs */
-    _spi_poweroff(spi_dev);
-
-    /* reset */
-    // Setting the Software Reset bit to 1
-    spi_dev->CTRLA.bit.SWRST = 1;
-
-    // Wait both bits Software Reset from CTRLA and SYNCBUSY are equal to 0
-    while (spi_dev->CTRLA.bit.SWRST || spi_dev->SYNCBUSY.bit.SWRST) {}
-
-    /* Turn on power manager for sercom */
-    PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << (sercom_gclk_id - GCLK_CLKCTRL_ID_SERCOM0_CORE_Val));
-
-    /* Setup clock */
-    /* SPI using CLK GEN 0 */
-    GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN |
-                         GCLK_CLKCTRL_GEN_GCLK0 |
-                         GCLK_CLKCTRL_ID(sercom_gclk_id));
-    while (GCLK->STATUS.bit.SYNCBUSY) {}
-
-    /* ???? init NVIC. Maybe not needed in master mode. */
-
-    /* Master mode */
-    spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE_SPI_MASTER;
-    while (spi_dev->SYNCBUSY.reg) {}// ???? not needed
-
-    spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t)CLOCK_CORECLOCK) / (2 * f_baud) - 1); /* Synchronous mode*/
-
-    spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_DOPO(mosi_pad)
-                       |  SERCOM_SPI_CTRLA_DIPO(miso_pad)
-                       |  cpha
-                       |  cpol;
-    while (spi_dev->SYNCBUSY.reg) {}	// ???? not needed
-
-    /* datasize 0 => 8 bits */
-    spi_dev->CTRLB.reg = (SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN);
-    while (spi_dev->SYNCBUSY.reg) {}	// ???? Only wait for clear of spi_dev->SYNCBUSY.bit.CTRLB
-
-    /* enable */
-    _spi_poweron(spi_dev);
-    return 0;
-}
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char))
-{
-    (void)dev;
-    (void)conf;
-    (void)cb;
-    /* TODO */
-    assert(false);
-    return -1;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    (void)dev;
-    (void)reset_val;
-    /* TODO */
-    assert(false);
-}
-
-int spi_acquire(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
-}
-
-int spi_release(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
-
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    SercomSpi* spi_dev = 0;
-    char tmp;
-
-    switch(dev)
-    {
-#if SPI_0_EN
-    case SPI_0:
-        spi_dev = &(SPI_0_DEV);
-        break;
-#endif
-#if SPI_1_EN
-    case SPI_1:
-        spi_dev = &(SPI_1_DEV);
-        break;
-#endif
-    }
-
-    while (!spi_dev->INTFLAG.bit.DRE) {} /* while data register is not empty*/
-    spi_dev->DATA.bit.DATA = out;
-
-    while (!spi_dev->INTFLAG.bit.DRE || !spi_dev->INTFLAG.bit.RXC) {} /* while receive is not complete*/
-    tmp = (char)spi_dev->DATA.bit.DATA;
-
-    if (in != NULL)
-    {
-        in[0] = tmp;
-    }
-    return 1;
-}
-
-static void _spi_poweron(SercomSpi* spi_dev)
-{
-    if (spi_dev == NULL) {
-        return;
-    }
-    spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE;
-    while (spi_dev->SYNCBUSY.bit.ENABLE) {}
-}
-
-void spi_poweron(spi_t dev)
-{
-    switch(dev) {
-#if SPI_0_EN
-    case SPI_0:
-        _spi_poweron(&SPI_0_DEV);
-        break;
-#endif
-#if SPI_1_EN
-    case SPI_1:
-        _spi_poweron(&SPI_1_DEV);
-        break;
-#endif
-    }
-}
-
-static void _spi_poweroff(SercomSpi* spi_dev)
-{
-    if (spi_dev == NULL) {
-        return;
-    }
-    spi_dev->CTRLA.bit.ENABLE = 0; /* Disable spi */
-    while (spi_dev->SYNCBUSY.bit.ENABLE) {}
-}
-
-void spi_poweroff(spi_t dev)
-{
-    switch(dev) {
-#if SPI_0_EN
-    case SPI_0:
-        _spi_poweroff(&SPI_0_DEV);
-        break;
-#endif
-#if SPI_1_EN
-    case SPI_1:
-        _spi_poweroff(&SPI_1_DEV);
-        break;
-#endif
-    }
-}
-
-#endif /* SPI_0_EN || SPI_1_EN */
diff --git a/cpu/samd21/periph/uart.c b/cpu/samd21/periph/uart.c
index a325b2e9e7764d1adba2f1de85cfe57ebcd37958..2d17cde605252fd00f25859d63a492eb2030e4e8 100644
--- a/cpu/samd21/periph/uart.c
+++ b/cpu/samd21/periph/uart.c
@@ -57,7 +57,7 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
     uart_ctx[uart].arg = arg;
     /* configure interrupts and enable RX interrupt */
     _uart(uart)->INTENSET.reg = SERCOM_USART_INTENSET_RXC;
-    NVIC_EnableIRQ(SERCOM0_IRQn + _sercom_id(_uart(uart)));
+    NVIC_EnableIRQ(SERCOM0_IRQn + sercom_id(_uart(uart)));
     return UART_OK;
 }
 
@@ -112,18 +112,18 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len)
 
 void uart_poweron(uart_t uart)
 {
-    PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << _sercom_id(_uart(uart)));
+    PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << sercom_id(_uart(uart)));
     GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN |
                          GCLK_CLKCTRL_GEN_GCLK0 |
-                         (SERCOM0_GCLK_ID_CORE + _sercom_id(_uart(uart))) <<
+                         (SERCOM0_GCLK_ID_CORE + sercom_id(_uart(uart))) <<
                           GCLK_CLKCTRL_ID_Pos);
     while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
 }
 
 void uart_poweroff(uart_t uart)
 {
-    PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << _sercom_id(_uart(uart)));
-    GCLK->CLKCTRL.reg = ((SERCOM0_GCLK_ID_CORE + _sercom_id(_uart(uart))) <<
+    PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << sercom_id(_uart(uart)));
+    GCLK->CLKCTRL.reg = ((SERCOM0_GCLK_ID_CORE + sercom_id(_uart(uart))) <<
                           GCLK_CLKCTRL_ID_Pos);
     while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
 }
diff --git a/cpu/saml21/cpu.c b/cpu/saml21/cpu.c
index 75a945165fff7bb6fcec62cce7d65c0f0440192b..e5ea27fa2c9fde81aac5049bd98511c8dbbd7c17 100644
--- a/cpu/saml21/cpu.c
+++ b/cpu/saml21/cpu.c
@@ -19,6 +19,7 @@
  */
 
 #include "cpu.h"
+#include "periph/init.h"
 
 static void _gclk_setup(int gclk, uint32_t reg)
 {
@@ -77,4 +78,7 @@ void cpu_init(void)
      */
     SUPC->BOD33.bit.ENABLE=0;
 #endif
+
+    /* trigger static peripheral initialization */
+    periph_init();
 }
diff --git a/cpu/saml21/periph/spi.c b/cpu/saml21/periph/spi.c
deleted file mode 100644
index 56ed843df8364e228af038f561805d6378482479..0000000000000000000000000000000000000000
--- a/cpu/saml21/periph/spi.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2014 Freie Universität Berlin
- *               2015 Kaspar Schleiser <kaspar@schleiser.de>
- *               FreshTemp, LLC.
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
- */
-
-/**
- * @ingroup     cpu_samd21
- * @{
- *
- * @file        spi.c
- * @brief       Low-level SPI driver implementation
- *
- * @author      Thomas Eichinger <thomas.eichinger@fu-berlin.de>
- * @author      Troels Hoffmeyer <troels.d.hoffmeyer@gmail.com>
- * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
- * @author      Kaspar Schleiser <kaspar@schleiser.de>
- *
- * @}
- */
-
-#include "cpu.h"
-#include "mutex.h"
-#include "periph/gpio.h"
-#include "periph/spi.h"
-
-#define ENABLE_DEBUG (0)
-#include "debug.h"
-
-#if SPI_0_EN  || SPI_1_EN
-
-/**
- * @brief Array holding one pre-initialized mutex for each SPI device
- */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-#if SPI_2_EN
-    [SPI_2] = MUTEX_INIT
-#endif
-};
-
-typedef struct spi_saml21_pin {
-    uint32_t pin;
-    uint32_t pmux;
-} spi_saml21_pin_t;
-
-typedef struct spi_saml21 {
-    SercomSpi* dev;
-    uint32_t mclk;
-    uint32_t gclk_id;
-
-    spi_saml21_pin_t sclk;
-    spi_saml21_pin_t miso;
-    spi_saml21_pin_t mosi;
-
-    int dipo;
-    int dopo;
-} spi_saml21_t;
-
-static const spi_saml21_t spi[] = {
-#if SPI_0_EN
-    /* SPI device */   /* MCLK flag */        /* GLCK id */         /* SCLK */  /* MISO */  /* MOSI */ /* dipo+dopo */
-    { &(SERCOM0->SPI), MCLK_APBCMASK_SERCOM0, SERCOM0_GCLK_ID_CORE, { GPIO_PIN(PA,7), 3 }, { GPIO_PIN(PA,4), 3 }, { GPIO_PIN(PA,6), 3 }, 0, 1 }
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
-{
-    SercomSpi* spi_dev = spi[dev].dev;
-
-    uint8_t   dopo = 0;
-    uint8_t   dipo = 0;
-    uint8_t   cpha = 0;
-    uint8_t   cpol = 0;
-    uint32_t  f_baud = 0;
-
-    switch(speed)
-    {
-        case SPI_SPEED_100KHZ:
-            f_baud = 100000;
-            break;
-        case SPI_SPEED_400KHZ:
-            f_baud = 400000;
-            break;
-        case SPI_SPEED_1MHZ:
-            f_baud = 1000000;
-            break;
-        case SPI_SPEED_5MHZ:
-            return -1;
-        case SPI_SPEED_10MHZ:
-            return -1;
-    }
-
-    switch(conf)
-    {
-        case SPI_CONF_FIRST_RISING: /**< first data bit is transacted on the first rising SCK edge */
-            cpha = 0;
-            cpol = 0;
-            break;
-        case SPI_CONF_SECOND_RISING:/**< first data bit is transacted on the second rising SCK edge */
-            cpha = 1;
-            cpol = 0;
-            break;
-        case SPI_CONF_FIRST_FALLING:/**< first data bit is transacted on the first falling SCK edge */
-            cpha = 0;
-            cpol = 1;
-            break;
-        case SPI_CONF_SECOND_FALLING:/**< first data bit is transacted on the second falling SCK edge */
-            cpha = 1;
-            cpol = 1;
-            break;
-    }
-
-    /* Enable sercom4 in power manager */
-    MCLK->APBCMASK.reg |= spi[dev].mclk;
-
-    /* Setup clock */
-    GCLK->PCHCTRL[ spi[dev].gclk_id ].reg =
-        GCLK_PCHCTRL_CHEN |
-        GCLK_PCHCTRL_GEN_GCLK0;
-
-    while (!(GCLK->PCHCTRL[spi[dev].gclk_id].reg & GCLK_PCHCTRL_CHEN)) {}
-
-    /* SCLK+MOSI = output */
-    gpio_init(spi[dev].sclk.pin, GPIO_OUT);
-    gpio_init(spi[dev].mosi.pin, GPIO_OUT);
-    /* MISO = input */
-    gpio_init(spi[dev].miso.pin, GPIO_IN);
-
-    /*
-     * Set alternate funcion (PMUX) for our ports.
-     */
-    gpio_init_mux(spi[dev].sclk.pin, spi[dev].sclk.pmux);
-    gpio_init_mux(spi[dev].miso.pin, spi[dev].miso.pmux);
-    gpio_init_mux(spi[dev].mosi.pin, spi[dev].mosi.pmux);
-
-    /* pin pad mapping */
-    dipo = spi[dev].dipo;
-    dopo = spi[dev].dopo;
-
-    /* Disable spi to write config */
-    spi_dev->CTRLA.bit.ENABLE = 0;
-    while (spi_dev->SYNCBUSY.reg) {}
-
-    /* setup baud */
-    spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t) GCLK_REF) / (2 * f_baud) - 1); /* Syncronous mode*/
-
-    spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3) /* 0x2 = slave 0x3 = master */
-                          |  (SERCOM_SPI_CTRLA_DOPO(dopo))
-                          |  (SERCOM_SPI_CTRLA_DIPO(dipo))
-                          |  (cpha << SERCOM_SPI_CTRLA_CPHA_Pos)
-                          |  (cpol << SERCOM_SPI_CTRLA_CPOL_Pos);
-
-    while (spi_dev->SYNCBUSY.reg) {}
-    spi_dev->CTRLB.reg = (SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN);
-    while(spi_dev->SYNCBUSY.reg) {}
-    spi_poweron(dev);
-    return 0;
-}
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char))
-{
-    /* TODO */
-    return -1;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    /* TODO*/
-}
-
-int spi_acquire(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
-}
-
-int spi_release(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
-
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    SercomSpi* spi_dev = spi[dev].dev;
-
-    while (!spi_dev->INTFLAG.bit.DRE) {} /* while data register is not empty */
-    spi_dev->DATA.bit.DATA = out;
-
-    if (in)
-    {
-        while (!spi_dev->INTFLAG.bit.RXC) {} /* while receive is not complete */
-        *in = spi_dev->DATA.bit.DATA;
-    }
-    else
-    {
-        /* clear input byte even if we're not interested */
-        spi_dev->DATA.bit.DATA;
-    }
-    return 1;
-}
-
-void spi_poweron(spi_t dev)
-{
-    SercomSpi* spi_dev = spi[dev].dev;
-    spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE;
-    while(spi_dev->SYNCBUSY.bit.ENABLE) {}
-}
-
-void spi_poweroff(spi_t dev)
-{
-    SercomSpi* spi_dev = spi[dev].dev;
-    spi_dev->CTRLA.bit.ENABLE = 0;
-    while(spi_dev->SYNCBUSY.bit.ENABLE) {}
-}
-
-#endif /* SPI_0_EN || SPI_1_EN */
diff --git a/cpu/stm32_common/dist/spi_divtable/Makefile b/cpu/stm32_common/dist/spi_divtable/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..e5b5461972923e0eb1cc150f0890d99d4ca170fb
--- /dev/null
+++ b/cpu/stm32_common/dist/spi_divtable/Makefile
@@ -0,0 +1,12 @@
+NAME        = spi_divtable
+CC          = gcc
+CFLAGS      = -std=c99 -Wall
+SRC         = $(wildcard *.c)
+
+.PHONY: all clean
+
+all:
+	$(CC) $(CFLAGS) -o $(NAME) $(SRC)
+
+clean:
+	rm -f $(NAME)
diff --git a/cpu/stm32_common/dist/spi_divtable/spi_divtable.c b/cpu/stm32_common/dist/spi_divtable/spi_divtable.c
new file mode 100644
index 0000000000000000000000000000000000000000..70eed10901c52bfbf295424b621c543f59b2d35f
--- /dev/null
+++ b/cpu/stm32_common/dist/spi_divtable/spi_divtable.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @brief       Compute SPI clock scaler values for STM32x CPUs
+ *
+ * This helper tool calculates the needed SPI scaler values for the APBx buses.
+ * It outputs the values for the possible SPI clock speeds based on the clock
+ * speeds of the APB1 and the APB2 bus.
+ *
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+static int targets[] = { 100000, 400000, 1000000, 5000000, 10000000 };
+
+/**
+ * @brief   Find the best fitting divisor value base on target and APB clock
+ *
+ * The SPI bus clock speed is calculated as follows:
+ *
+ * clk_bus = clk_apb / 2 ^ (x + 1)
+ *
+ * In this function we will try to find the x-value, that brings clk_bus as
+ * close as possible to the value given in @p target.
+ *
+ * @param[in] bus       clock speed of the given APB bus
+ * @param[in] target    targeted SPI clock speed
+ *
+ * @return  the closes divisor value to be used in the clock config register
+ */
+static int find_best(int bus, int target)
+{
+    int br = -1;
+    int tmp = bus;
+
+    do {
+        // printf("b: x: %i - tmp: %i\n", br, tmp);
+        ++br;
+        tmp /= 2;
+        if (tmp == target) {
+            return br;
+        }
+        // printf("a: x: %i - tmp: %i\n", br, tmp);
+        // printf("  (tmp - target):%i\n", (tmp - target));
+    } while ((tmp - target > 0) && (br < 7));
+
+    int old = tmp * 2;
+    // printf("(target - tmp):%i, (old - target): %i\n", (target - tmp), (old - target));
+
+    if ((target - tmp) > (old - target)) {
+        return (br - 1);
+    }
+    return br;
+}
+
+static int real_clk(int bus, int br)
+{
+    return bus / (2 << br);
+}
+
+int main(int argc, char **argv)
+{
+    int tnum = sizeof(targets) / sizeof(targets[0]);
+    int apb[2];
+
+    if (argc != 3) {
+        printf("usage: %s <APB1 clk> <APB2 clk> (in Hz)\n", argv[0]);
+        return 1;
+    }
+
+    apb[0] = atoi(argv[1]); /* APB1 */
+    apb[1] = atoi(argv[2]); /* APB2 */
+
+    if ((apb[0] <= 0) || (apb[1] <= 0)) {
+        puts("error: invalid APB clock speed values");
+        return 1;
+    }
+
+    printf("static const uint8_t spi_divtable[2][%i] = {\n", tnum);
+
+    for (int bus = 0; bus < (sizeof(apb) / sizeof(apb[0])); bus ++) {
+        printf("    {       /* for APB%i @ %iHz */\n", (bus + 1), apb[bus]);
+        for (int t = 0; t < tnum; t++) {
+            int br = find_best(apb[bus], targets[t]);
+            printf("        %i%c  /* -> %iHz */\n",
+                   br, ((t < (tnum - 1)) ? ',' : ' '), real_clk(apb[bus], br));
+        }
+        printf("    }%c\n", ((bus == 0) ? ',' : ' '));
+    }
+    puts("};");
+
+    return 0;
+}
diff --git a/cpu/stm32_common/include/periph_cpu_common.h b/cpu/stm32_common/include/periph_cpu_common.h
index c2040ad6b765f34f3324ee8fbf2d5e331435447a..2422473b037945d0478aedec23836e11ad9d0804 100644
--- a/cpu/stm32_common/include/periph_cpu_common.h
+++ b/cpu/stm32_common/include/periph_cpu_common.h
@@ -39,7 +39,7 @@ extern "C" {
  * @brief   Use the shared SPI functions
  * @{
  */
-#define PERIPH_SPI_NEEDS_TRANSFER_BYTES
+#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
 #define PERIPH_SPI_NEEDS_TRANSFER_REG
 #define PERIPH_SPI_NEEDS_TRANSFER_REGS
 /** @} */
@@ -89,6 +89,22 @@ typedef uint32_t gpio_t;
  */
 #define GPIO_PIN(x, y)      ((GPIOA_BASE + (x << 10)) | y)
 
+/**
+ * @brief   Define a magic number that tells us to use hardware chip select
+ *
+ * We use a random value here, that does clearly differentiate from any possible
+ * GPIO_PIN(x) value.
+ */
+#define SPI_HWCS_MASK       (0xffffff00)
+
+/**
+ * @brief   Override the default SPI hardware chip select access macro
+ *
+ * Since the CPU does only support one single hardware chip select line, we can
+ * detect the usage of non-valid lines by comparing to SPI_HWCS_VALID.
+ */
+#define SPI_HWCS(x)         (SPI_HWCS_MASK | x)
+
 /**
  * @brief   Available MUX values for configuring a pin's alternate function
  */
@@ -169,6 +185,22 @@ typedef struct {
 #endif
 } uart_conf_t;
 
+/**
+ * @brief   Structure for SPI configuration data
+ */
+typedef struct {
+    SPI_TypeDef *dev;       /**< SPI device base register address */
+    gpio_t mosi_pin;        /**< MOSI pin */
+    gpio_t miso_pin;        /**< MISO pin */
+    gpio_t sclk_pin;        /**< SCLK pin */
+    gpio_t cs_pin;          /**< HWCS pin, set to GPIO_UNDEF if not mapped */
+#ifndef CPU_FAM_STM32F1
+    gpio_af_t af;           /**< pin alternate function */
+#endif
+    uint32_t rccmask;       /**< bit in the RCC peripheral enable register */
+    uint8_t apbbus;         /**< APBx bus the device is connected to */
+} spi_conf_t;
+
 /**
  * @brief   Get the actual bus clock frequency for the APB buses
  *
diff --git a/cpu/stm32_common/periph/spi.c b/cpu/stm32_common/periph/spi.c
new file mode 100644
index 0000000000000000000000000000000000000000..60f0a859245496b43665191730b5d3a3c06c1209
--- /dev/null
+++ b/cpu/stm32_common/periph/spi.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2014 Hamburg University of Applied Sciences
+ *               2014-2017 Freie Universität Berlin
+ *               2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_stm32_common
+ * @{
+ *
+ * @file
+ * @brief       Low-level SPI driver implementation
+ *
+ * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
+ * @author      Fabian Nack <nack@inf.fu-berlin.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
+ * @author      Thomas Eichinger <thomas.eichinger@fu-berlin.de>
+ *
+ * @}
+ */
+
+#include "cpu.h"
+#include "mutex.h"
+#include "assert.h"
+#include "periph/spi.h"
+
+/* Remove this ugly guard once we selectively build the periph drivers */
+#ifdef SPI_NUMOF
+
+/**
+ * @brief   Number of bits to shift the BR value in the CR1 register
+ */
+#define BR_SHIFT            (3U)
+
+/**
+ * @brief   Allocate one lock per SPI device
+ */
+static mutex_t locks[SPI_NUMOF];
+
+static inline SPI_TypeDef *dev(spi_t bus)
+{
+    return spi_config[bus].dev;
+}
+
+void spi_init(spi_t bus)
+{
+    assert(bus < SPI_NUMOF);
+
+    /* initialize device lock */
+    mutex_init(&locks[bus]);
+    /* trigger pin initialization */
+    spi_init_pins(bus);
+
+    periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    /* reset configuration */
+    dev(bus)->CR1 = 0;
+#ifdef SPI_I2SCFGR_I2SE
+    dev(bus)->I2SCFGR = 0;
+#endif
+    /* configure SPI for 8-bit data width */
+#ifdef SPI_CR2_FRXTH
+    dev(bus)->CR2 = (SPI_CR2_FRXTH | SPI_CR2_DS_0 | SPI_CR2_DS_1 | SPI_CR2_DS_2);
+#else
+    dev(bus)->CR2 = 0;
+#endif
+    periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask);
+}
+
+void spi_init_pins(spi_t bus)
+{
+#ifdef CPU_FAM_STM32F1
+    gpio_init_af(spi_config[bus].sclk_pin, GPIO_AF_OUT_PP);
+    gpio_init_af(spi_config[bus].mosi_pin, GPIO_AF_OUT_PP);
+    gpio_init(spi_config[bus].miso_pin, GPIO_IN);
+#else
+    gpio_init(spi_config[bus].mosi_pin, GPIO_OUT);
+    gpio_init(spi_config[bus].miso_pin, GPIO_IN);
+    gpio_init(spi_config[bus].sclk_pin, GPIO_OUT);
+    gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af);
+    gpio_init_af(spi_config[bus].miso_pin, spi_config[bus].af);
+    gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].af);
+#endif
+}
+
+int spi_init_cs(spi_t bus, spi_cs_t cs)
+{
+    if (bus >= SPI_NUMOF) {
+        return SPI_NODEV;
+    }
+    if (cs == SPI_CS_UNDEF ||
+        (((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) {
+        return SPI_NOCS;
+    }
+
+    if (cs == SPI_HWCS_MASK) {
+        if (spi_config[bus].cs_pin == GPIO_UNDEF) {
+            return SPI_NOCS;
+        }
+#ifdef CPU_FAM_STM32F1
+        gpio_init_af(spi_config[bus].cs_pin, GPIO_AF_OUT_PP);
+#else
+        gpio_init(spi_config[bus].cs_pin, GPIO_OUT);
+        gpio_init_af(spi_config[bus].cs_pin, spi_config[bus].af);
+#endif
+    }
+    else {
+        gpio_init((gpio_t)cs, GPIO_OUT);
+        gpio_set((gpio_t)cs);
+    }
+
+    return SPI_OK;
+}
+
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    assert((clk >= SPI_CLK_100KHZ) && (clk <= SPI_CLK_10MHZ));
+
+    /* lock bus */
+    mutex_lock(&locks[bus]);
+    /* enable SPI device clock */
+    periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    /* enable device */
+    uint8_t br = spi_divtable[spi_config[bus].apbbus][clk];
+    dev(bus)->CR1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR);
+    if (cs != SPI_HWCS_MASK) {
+        dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI);
+    }
+    else {
+        dev(bus)->CR2 |= (SPI_CR2_SSOE);
+    }
+
+    return SPI_OK;
+}
+
+void spi_release(spi_t bus)
+{
+    /* disable device and release lock */
+    dev(bus)->CR1 = 0;
+    dev(bus)->CR2 &= ~(SPI_CR2_SSOE);
+    periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    mutex_unlock(&locks[bus]);
+}
+
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
+{
+    uint8_t *inbuf = (uint8_t *)in;
+    uint8_t *outbuf = (uint8_t *)out;
+
+    /* make sure at least one input or one output buffer is given */
+    assert(outbuf || inbuf);
+
+    /* we need to recast the data register to uint_8 to force 8-bit access */
+    volatile uint8_t *DR = (volatile uint8_t*)&(dev(bus)->DR);
+
+    /* active the given chip select line */
+    dev(bus)->CR1 |= (SPI_CR1_SPE);     /* this pulls the HW CS line low */
+    if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) {
+        gpio_clear((gpio_t)cs);
+    }
+
+    /* transfer data, use shortpath if only sending data */
+    if (!inbuf) {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SPI_SR_TXE));
+            *DR = outbuf[i];
+        }
+        /* wait until everything is finished and empty the receive buffer */
+        while (dev(bus)->SR & SPI_SR_BSY) {}
+        while (dev(bus)->SR & SPI_SR_RXNE) {
+            dev(bus)->DR;       /* we might just read 2 bytes at once here */
+        }
+    }
+    else if (!outbuf) {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SPI_SR_TXE));
+            *DR = 0;
+            while (!(dev(bus)->SR & SPI_SR_RXNE));
+            inbuf[i] = *DR;
+        }
+    }
+    else {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SPI_SR_TXE));
+            *DR = outbuf[i];
+            while (!(dev(bus)->SR & SPI_SR_RXNE));
+            inbuf[i] = *DR;
+        }
+    }
+
+    /* make sure the transfer is completed before continuing, see reference
+     * manual(s) -> section 'Disabling the SPI' */
+    while (!(dev(bus)->SR & SPI_SR_TXE)) {}
+    while (dev(bus)->SR & SPI_SR_BSY) {}
+
+    /* release the chip select if not specified differently */
+    if ((!cont) && (cs != SPI_CS_UNDEF)) {
+        dev(bus)->CR1 &= ~(SPI_CR1_SPE);    /* pull HW CS line high */
+        if (cs != SPI_HWCS_MASK) {
+            gpio_set((gpio_t)cs);
+        }
+    }
+}
+
+#endif /* SPI_NUMOF */
diff --git a/cpu/stm32f0/cpu.c b/cpu/stm32f0/cpu.c
index 557176afa50a3050399e100195a05dfb8015bcd0..88884d123cbf5aa495a379f1568c2764c0b7404a 100644
--- a/cpu/stm32f0/cpu.c
+++ b/cpu/stm32f0/cpu.c
@@ -19,6 +19,7 @@
 
 #include "cpu.h"
 #include "periph_conf.h"
+#include "periph/init.h"
 
 /* Check the source to be used for the PLL */
 #if defined(CLOCK_HSI) && defined(CLOCK_HSE)
@@ -54,6 +55,8 @@ void cpu_init(void)
     cortexm_init();
     /* initialize the clock system */
     clock_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 /**
diff --git a/cpu/stm32f0/periph/spi.c b/cpu/stm32f0/periph/spi.c
deleted file mode 100644
index 4bfce9ba455f729b8474e7f40c8b20073708ff5c..0000000000000000000000000000000000000000
--- a/cpu/stm32f0/periph/spi.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (C) 2014 Freie Universität Berlin
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
- */
-
-/**
- * @ingroup     cpu_stm32f0
- * @{
- *
- * @file
- * @brief       Low-level GPIO driver implementation
- *
- * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
- * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- * @author      Fabian Nack <nack@inf.fu-berlin.de>
- * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
- *
- * @}
- */
-
-#include "cpu.h"
-#include "board.h"
-#include "mutex.h"
-#include "periph/spi.h"
-#include "periph_conf.h"
-#include "thread.h"
-#include "sched.h"
-
-/* guard file in case no SPI device is defined */
-#if SPI_NUMOF
-
-/**
- * @brief Array holding one pre-initialized mutex for each SPI device
- */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-#if SPI_2_EN
-    [SPI_2] = MUTEX_INIT
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
-{
-    SPI_TypeDef *spi;
-
-    /* power on the SPI device */
-    spi_poweron(dev);
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi = SPI_0_DEV;
-            SPI_0_PORT_CLKEN();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            spi = SPI_1_DEV;
-            SPI_1_PORT_CLKEN();
-            break;
-#endif
-        default:
-            return -1;
-    }
-
-    /* configure SCK, MISO and MOSI pin */
-    spi_conf_pins(dev);
-
-    /* reset SPI configuration registers */
-    spi->CR1 = 0;
-    spi->CR2 = 0;
-    spi->I2SCFGR = 0;       /* this makes sure SPI mode is selected */
-
-    /* configure bus clock speed */
-    switch (speed) {
-        case SPI_SPEED_100KHZ:
-            spi->CR1 |= (7 << 3);       /* actual clock: 187.5KHz (lowest possible) */
-            break;
-        case SPI_SPEED_400KHZ:
-            spi->CR1 |= (6 << 3);       /* actual clock: 375KHz */
-            break;
-        case SPI_SPEED_1MHZ:
-            spi->CR1 |= (4 << 3);       /* actual clock: 1.5MHz */
-            break;
-        case SPI_SPEED_5MHZ:
-            spi->CR1 |= (2 << 3);       /* actual clock: 6MHz */
-            break;
-        case SPI_SPEED_10MHZ:
-            spi->CR1 |= (1 << 3);       /* actual clock 12MHz */
-    }
-
-    /* select clock polarity and clock phase */
-    spi->CR1 |= conf;
-    /* select master mode */
-    spi->CR1 |= SPI_CR1_MSTR;
-    /* the NSS (chip select) is managed purely by software */
-    spi->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI;
-    /* set data-size to 8-bit */
-    spi->CR2 |= (0x7 << 8);
-    /* set FIFO threshold to set RXNE when 8 bit are received */
-    spi->CR2 |= SPI_CR2_FRXTH;
-    /* enable the SPI device */
-    spi->CR1 |= SPI_CR1_SPE;
-    return 0;
-}
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data))
-{
-    /* due to issues with the send buffer, the master mode is not (yet) supported */
-    return -1;
-}
-
-int spi_conf_pins(spi_t dev)
-{
-    GPIO_TypeDef *port;
-    int pin[3];        /* 3 pins: sck, miso, mosi */
-    int af = 0;
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            port = SPI_0_PORT;
-            pin[0] = SPI_0_PIN_SCK;
-            pin[1] = SPI_0_PIN_MISO;
-            pin[2] = SPI_0_PIN_MOSI;
-            af = SPI_0_PIN_AF;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            port = SPI_1_PORT;
-            pin[0] = SPI_1_PIN_SCK;
-            pin[1] = SPI_1_PIN_MISO;
-            pin[2] = SPI_1_PIN_MOSI;
-            af = SPI_1_PIN_AF;
-            break;
-#endif
-        default:
-            return -1;
-    }
-
-    /* configure pins for their correct alternate function */
-    for (int i = 0; i < 3; i++) {
-        port->MODER &= ~(3 << (pin[i] * 2));
-        port->MODER |= (2 << (pin[i] * 2));
-        port->OSPEEDR |= (3 << (pin[i] * 2));
-        int hl = (pin[i] < 8) ? 0 : 1;
-        port->AFR[hl] &= ~(0xf << ((pin[i] - (hl * 8)) * 4));
-        port->AFR[hl] |= (af << ((pin[i] - (hl * 8)) * 4));
-    }
-
-    return 0;
-}
-
-int spi_acquire(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
-}
-
-int spi_release(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
-
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    char tmp;
-    SPI_TypeDef *spi = 0;
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi = SPI_0_DEV;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            spi = SPI_1_DEV;
-            break;
-#endif
-        default:
-            return 0;
-    }
-
-    /* wait for an eventually previous byte to be readily transferred */
-    while(!(spi->SR & SPI_SR_TXE)) {}
-    /* put next byte into the output register */
-    *((volatile uint8_t *)(&spi->DR)) = (uint8_t)out;
-    /* wait until the current byte was successfully transferred */
-    while(!(spi->SR & SPI_SR_RXNE)) {}
-    /* read response byte to reset flags */
-    tmp = *((volatile uint8_t *)(&spi->DR));
-    /* 'return' response byte if wished for */
-    if (in) {
-        *in = tmp;
-    }
-
-    return 1;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    /* slave mode is not (yet) supported */
-}
-
-void spi_poweron(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            SPI_0_CLKEN();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            SPI_1_CLKEN();
-            break;
-#endif
-    }
-}
-
-void spi_poweroff(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            while (SPI_0_DEV->SR & SPI_SR_BSY) {}
-            SPI_0_CLKDIS();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            while (SPI_1_DEV->SR & SPI_SR_BSY) {}
-            SPI_1_CLKDIS();
-            break;
-#endif
-    }
-}
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/stm32f0/periph/spi.cold b/cpu/stm32f0/periph/spi.cold
new file mode 100644
index 0000000000000000000000000000000000000000..894e4603ff266541b108d3b8678ebbb0ee2b865e
--- /dev/null
+++ b/cpu/stm32f0/periph/spi.cold
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2014-2016 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_stm32f0
+ * @{
+ *
+ * @file
+ * @brief       Low-level GPIO driver implementation
+ *
+ * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ * @author      Fabian Nack <nack@inf.fu-berlin.de>
+ * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
+ *
+ * @}
+ */
+
+#include "cpu.h"
+#include "mutex.h"
+#include "assert.h"
+#include "periph/spi.h"
+
+#define ENABLE_DEBUG        (0)
+#include "debug.h"
+
+/* Remove this ugly guard once we selectively build the periph drivers */
+#ifdef SPI_NUMOF
+
+/**
+ * @brief   Number of bits to shift the BR value in the CR1 register
+ */
+#define BR_SHIFT            (3U)
+
+/**
+ * @brief Array holding one pre-initialized mutex for each SPI device
+ */
+static mutex_t locks[SPI_NUMOF];
+
+static inline SPI_TypeDef *dev(spi_t bus)
+{
+    return spi_config[bus].dev;
+}
+
+void spi_init(spi_t bus)
+{
+    assert(bus < SPI_NUMOF);
+
+    /* initialize device lock */
+    mutex_lock(&locks[bus]);
+    /* trigger pin initialization */
+    spi_init_pins(bus);
+}
+
+void spi_init_pins(spi_t bus)
+{
+    gpio_init(spi_config[bus].mosi_pin, GPIO_OUT);
+    gpio_init(spi_config[bus].miso_pin, GPIO_IN);
+    gpio_init(spi_config[bus].sclk_pin, GPIO_OUT);
+    gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af);
+    gpio_init_af(spi_config[bus].miso_pin, spi_config[bus].af);
+    gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].af);
+}
+
+int spi_init_cs(spi_t bus, spi_cs_t cs)
+{
+    if (bus >= SPI_NUMOF) {
+        return SPI_NODEV;
+    }
+    if (cs == SPI_CS_UNDEF ||
+        (((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) {
+        return SPI_NOCS;
+    }
+
+    if (cs == SPI_HWCS_MASK) {
+        if (spi_config[bus].cs_pin == GPIO_UNDEF) {
+            return SPI_NOCS;
+        }
+        gpio_init(spi_config[bus].cs_pin, GPIO_OUT);
+        gpio_init_af(spi_config[bus].cs_pin, spi_config[bus].af);
+    }
+    else {
+        gpio_init((gpio_t)cs, GPIO_OUT);
+        gpio_set((gpio_t)cs);
+    }
+
+    return SPI_OK;
+}
+
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    assert((clk >= SPI_CLK_100KHZ) && (clk <= SPI_CLK_10MHZ));
+
+    /* lock bus */
+    mutex_lock(&locks[bus]);
+    /* enable SPI device clock */
+    periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    /* enable device */
+    uint8_t br = spi_divtable[spi_config[bus].apbbus][clk];
+    dev(bus)->CR1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR);
+    if (cs != SPI_HWCS_MASK) {
+        dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI);
+    }
+
+    return SPI_OK;
+}
+
+void spi_release(spi_t bus)
+{
+    /* disable device and release lock */
+    dev(bus)->CR1 = 0;
+    periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    mutex_unlock(&locks[bus]);
+}
+
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
+{
+    uint8_t *inbuf = (uint8_t *)in;
+    uint8_t *outbuf = (uint8_t *)out;
+
+    /* make sure at least one input or one output buffer is given */
+    assert(outbuf || inbuf);
+
+    /* active the given chip select line */
+    dev(bus)->CR1 |= (SPI_CR1_SPE);     /* this pulls the HW CS line low */
+    if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) {
+        gpio_clear((gpio_t)cs);
+    }
+
+    /* transfer data, use shortpath if only sending data */
+    if (!inbuf) {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SPI_SR_TXE));
+            dev(bus)->DR = outbuf[i];
+        }
+        /* wait until everything is finished and empty the receive buffer */
+        while (dev(bus)->SR & SPI_SR_BSY) {}
+        dev(bus)->DR;
+    }
+    else {
+        for (size_t i = 0; i < len; i++) {
+            uint8_t tmp = (outbuf) ? outbuf[i] : 0;
+            while (!(dev(bus)->SR & SPI_SR_TXE));
+            dev(bus)->DR = tmp;
+            while (!(dev(bus)->SR & SPI_SR_RXNE));
+            inbuf[i] = dev(bus)->DR;
+        }
+    }
+
+    /* release the chip select if not specified differently */
+    if ((!cont) && (cs != SPI_CS_UNDEF)) {
+        dev(bus)->CR1 &= ~(SPI_CR1_SPE);    /* pull HW CS line high */
+        if (cs != SPI_HWCS_MASK) {
+            gpio_set((gpio_t)cs);
+        }
+    }
+}
+
+#endif /* SPI_NUMOF */
diff --git a/cpu/stm32f1/cpu.c b/cpu/stm32f1/cpu.c
index b611b228cf295eb65c57ff80a22f8707fd321057..c2d465a640540182f789c656cad92384dd170593 100644
--- a/cpu/stm32f1/cpu.c
+++ b/cpu/stm32f1/cpu.c
@@ -27,6 +27,7 @@
 
 #include "cpu.h"
 #include "periph_conf.h"
+#include "periph/init.h"
 
 /* Configuration of flash access cycles */
 #if CLOCK_CORECLOCK <= 24000000
@@ -103,6 +104,8 @@ void cpu_init(void)
     cortexm_init();
     /* initialize system clocks */
     clk_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 /**
diff --git a/cpu/stm32f1/include/periph_cpu.h b/cpu/stm32f1/include/periph_cpu.h
index 035eec70f4a4aa50b2ec8b0a724c7a777d9d7df3..b1e7f364229623a33c5c4be6cb4fb47bf332c47d 100644
--- a/cpu/stm32f1/include/periph_cpu.h
+++ b/cpu/stm32f1/include/periph_cpu.h
@@ -31,11 +31,14 @@ extern "C" {
 #define ADC_DEVS            (2U)
 
 /**
- * @brief declare needed generic SPI functions
- * @{
+ * @brief   All timers for the STM32F1 have 4 CC channels
  */
-#undef PERIPH_SPI_NEEDS_TRANSFER_BYTES
-#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
+#define TIMER_CHANNELS      (4U)
+
+/**
+ * @brief   All timers have a width of 16-bit
+ */
+#define TIMER_MAXVAL        (0xffff)
 
 /**
  * @brief   Generate GPIO mode bitfields
@@ -48,6 +51,11 @@ extern "C" {
  */
 #define GPIO_MODE(mode, cnf, odr)       (mode | (cnf << 2) | (odr << 4))
 
+/**
+ * @brief   Define the number of available PM modes
+ */
+#define PM_NUM_MODES    (2U)
+
 #ifndef DOXYGEN
 /**
  * @brief   Override GPIO mode options
@@ -123,8 +131,6 @@ typedef struct {
     uint8_t chan;           /**< DAC device used for this line */
 } dac_conf_t;
 
-#define PM_NUM_MODES    (2U)
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/cpu/stm32f1/periph/spi.c b/cpu/stm32f1/periph/spi.c
deleted file mode 100644
index 005e547dadc666a862b838836c9d010cac5e0ace..0000000000000000000000000000000000000000
--- a/cpu/stm32f1/periph/spi.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2014 Freie Universität Berlin
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
- */
-
-/**
- * @ingroup     cpu_stm32f1
- * @{
- *
- * @file
- * @brief       Low-level SPI driver implementation
- *
- * @author      Thomas Eichinger <thomas.eichinger@fu-berlin.de>
- * @author      Fabian Nack <nack@inf.fu-berlin.de>
- * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
- *
- * @}
- */
-
-#include "cpu.h"
-#include "mutex.h"
-#include "periph/gpio.h"
-#include "periph/spi.h"
-#include "periph_conf.h"
-#include "board.h"
-
-#define ENABLE_DEBUG (0)
-#include "debug.h"
-
-/* guard file in case no SPI device is defined */
-#if SPI_0_EN || SPI_1_EN || SPI_2_EN
-
-/**
- * @brief Array holding one pre-initialized mutex for each SPI device
- */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-#if SPI_2_EN
-    [SPI_2] = MUTEX_INIT
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
-{
-    SPI_TypeDef *spi;
-    uint16_t br_div;
-    uint8_t bus_div;
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi = SPI_0_DEV;
-            bus_div = SPI_0_BUS_DIV;
-            SPI_0_CLKEN();
-            break;
-#endif
-
-#if SPI_1_EN
-        case SPI_1:
-            spi = SPI_1_DEV;
-            bus_div = SPI_1_BUS_DIV;
-            SPI_1_CLKEN();
-            break;
-#endif
-
-#if SPI_2_EN
-        case SPI_2:
-            spi = SPI_2_DEV;
-            bus_div = SPI_2_BUS_DIV;
-            SPI_2_CLKEN();
-            break;
-#endif
-        default:
-            return -1;
-    }
-
-    /* configure SCK, MISO and MOSI pin */
-    spi_conf_pins(dev);
-
-    /* configure SPI bus speed */
-    switch (speed) {
-        case SPI_SPEED_10MHZ:
-            br_div = 0x01 + bus_div;      /* actual speed: 9MHz   */
-            break;
-        case SPI_SPEED_5MHZ:
-            br_div = 0x02 + bus_div;     /* actual speed: 4.5MHz */
-            break;
-        case SPI_SPEED_1MHZ:
-            br_div = 0x04 + bus_div;     /* actual speed: 1.1MHz */
-            break;
-        case SPI_SPEED_400KHZ:
-            br_div = 0x05 + bus_div;    /* actual speed: 560kHz */
-            break;
-        case SPI_SPEED_100KHZ:
-            br_div = 0x07;              /* actual speed: 280kHz on APB2, 140KHz on APB1 */
-            break;
-        default:
-            return -2;
-    }
-
-    /* set up SPI */
-    spi->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_MSTR | (conf & 0x3) | (br_div << 3);
-    spi->I2SCFGR &= 0xF7FF;     /* select SPI mode */
-    spi->CRCPR = 0x7;           /* reset CRC polynomial */
-    /* enable the SPI device */
-    spi->CR1 |= SPI_CR1_SPE;
-
-    return 0;
-}
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char))
-{
-    (void) dev;
-    (void) conf;
-    (void) cb;
-    /* TODO */
-    return -1;
-}
-
-int spi_conf_pins(spi_t dev)
-{
-    gpio_t mosi, miso, clk;
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            clk = SPI_0_CLK_PIN;
-            mosi = SPI_0_MOSI_PIN;
-            miso = SPI_0_MISO_PIN;
-            break;
-#endif
-
-#if SPI_1_EN
-        case SPI_1:
-            clk = SPI_1_CLK_PIN;
-            mosi = SPI_1_MOSI_PIN;
-            miso = SPI_1_MISO_PIN;
-            break;
-#endif
-
-#if SPI_2_EN
-        case SPI_2:
-            clk = SPI_2_CLK_PIN;
-            mosi = SPI_2_MOSI_PIN;
-            miso = SPI_2_MISO_PIN;
-            break;
-#endif
-        default:
-            return -1;
-    }
-
-    /* configure pins for alternate function input (MISO) or output (MOSI, CLK) */
-    gpio_init_af(clk, GPIO_AF_OUT_PP);
-    gpio_init_af(mosi, GPIO_AF_OUT_PP);
-    gpio_init(miso, GPIO_IN);
-    return 0;
-}
-
-int spi_acquire(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
-}
-
-int spi_release(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
-
-int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length)
-{
-
-    SPI_TypeDef *spi;
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi = SPI_0_DEV;
-            break;
-#endif
-
-#if SPI_1_EN
-        case SPI_1:
-            spi = SPI_1_DEV;
-            break;
-#endif
-
-#if SPI_2_EN
-        case SPI_2:
-            spi = SPI_2_DEV;
-            break;
-#endif
-        default:
-            return -1;
-    }
-
-    if(!in){
-        for (unsigned i = 0; i < length; i++) {
-            while (!(spi->SR & SPI_SR_TXE)) {}
-            spi->DR = (uint8_t)out[i];
-        }
-        /* SPI busy */
-        while ((spi->SR & SPI_SR_BSY)) {}
-        spi->DR;
-    }
-    else if(!out) {
-        for (unsigned i = 0; i < length; i++) {
-            spi->DR = 0;
-            while (!(spi->SR & SPI_SR_RXNE)) {}
-            in[i] = (char)spi->DR;
-        }
-    }
-    else {
-        for (unsigned i = 0; i < length; i++) {
-            while (!(spi->SR & SPI_SR_TXE)) {}
-            spi->DR = out[i];
-            while (!(spi->SR & SPI_SR_RXNE)) {}
-            in[i] = (char)spi->DR;
-        }
-    }
-
-#if ENABLE_DEBUG
-    if (in != NULL) {
-        DEBUG("\nSPI: transferred %i Bytes\n", length);
-    }
-#endif /*ENABLE_DEBUG */
-
-    return length;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    (void) dev;
-    (void) reset_val;
-    /* slave mode not implemented, yet */
-}
-
-void spi_poweron(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            SPI_0_CLKEN();
-            SPI_0_DEV->CR1 |= SPI_CR1_SPE;   /* turn SPI peripheral on */
-            break;
-#endif
-
-#if SPI_1_EN
-        case SPI_1:
-            SPI_1_CLKEN();
-            SPI_1_DEV->CR1 |= SPI_CR1_SPE;   /* turn SPI peripheral on */
-            break;
-#endif
-
-#if SPI_2_EN
-        case SPI_2:
-            SPI_2_CLKEN();
-            SPI_2_DEV->CR1 |= SPI_CR1_SPE;   /* turn SPI peripheral on */
-            break;
-#endif
-    }
-}
-
-void spi_poweroff(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            while ((SPI_0_DEV->SR & SPI_SR_BSY)) {}
-            SPI_0_DEV->CR1 &= ~(SPI_CR1_SPE);   /* turn SPI peripheral off */
-            SPI_0_CLKDIS();
-            break;
-#endif
-
-#if SPI_1_EN
-        case SPI_1:
-            while ((SPI_1_DEV->SR & SPI_SR_BSY)) {}
-            SPI_1_DEV->CR1 &= ~(SPI_CR1_SPE);   /* turn SPI peripheral off */
-            SPI_1_CLKDIS();
-            break;
-#endif
-
-#if SPI_2_EN
-        case SPI_2:
-            while ((SPI_2_DEV->SR & SPI_SR_BSY)) {}
-            SPI_2_DEV->CR1 &= ~(SPI_CR1_SPE);   /* turn SPI peripheral off */
-            SPI_2_CLKDIS();
-            break;
-#endif
-    }
-}
-
-#endif /* SPI_0_EN */
diff --git a/cpu/stm32f1/periph/spi.cold b/cpu/stm32f1/periph/spi.cold
new file mode 100644
index 0000000000000000000000000000000000000000..9fb51dabe8a8ff48b1f794b581ce03d0596de6cd
--- /dev/null
+++ b/cpu/stm32f1/periph/spi.cold
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014-2016 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_stm32f1
+ * @{
+ *
+ * @file
+ * @brief       Low-level SPI driver implementation
+ *
+ * @author      Thomas Eichinger <thomas.eichinger@fu-berlin.de>
+ * @author      Fabian Nack <nack@inf.fu-berlin.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
+ *
+ * @}
+ */
+
+#include "cpu.h"
+#include "mutex.h"
+#include "assert.h"
+#include "periph/spi.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+/* Remove this ugly guard once we selectively build the periph drivers */
+#ifdef SPI_NUMOF
+
+/**
+ * @brief   Number of bits to shift the BR value in the CR1 register
+ */
+#define BR_SHIFT            (3U)
+
+/**
+ * @brief Array holding one pre-initialized mutex for each SPI device
+ */
+static mutex_t locks[SPI_NUMOF];
+
+static inline SPI_TypeDef *dev(spi_t bus)
+{
+    return spi_config[bus].dev;
+}
+
+void spi_init(spi_t bus)
+{
+    /* make sure given bus is valid */
+    assert(bus <= SPI_NUMOF);
+    /* initialize the bus lock */
+    mutex_init(&locks[bus]);
+    /* trigger pin configuration */
+    spi_init_pins(bus);
+}
+
+void spi_init_pins(spi_t bus)
+{
+    gpio_init_af(spi_config[bus].pin_clk, GPIO_AF_OUT_PP);
+    gpio_init_af(spi_config[bus].pin_mosi, GPIO_AF_OUT_PP);
+    gpio_init(spi_config[bus].pin_miso, GPIO_IN);
+}
+
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    assert((clk >= SPI_CLK_100KHZ) && (clk <= SPI_CLK_10MHZ));
+
+    /* get exclusive bus access */
+    mutex_lock(&locks[bus]);
+    /* power on the peripheral */
+    periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
+
+
+    /* configure mode and bus clock */
+    uint8_t br = spi_divtable[spi_config[bus].apbbus][clk];
+    dev(bus)->CR1 = (SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_MSTR |
+                     (mode & 0x3) | (br << BR_SHIFT));
+    /* enable the SPI device */
+    dev(bus)->CR1 |= SPI_CR1_SPE;
+
+    return SPI_OK;
+}
+
+void spi_release(spi_t bus)
+{
+    /* disable, power off, and release the bus */
+    dev(bus)->CR1 = 0;
+    periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    mutex_unlock(&locks[bus]);
+}
+
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
+{
+    uint8_t *out_buf = (uint8_t *)out;
+    uint8_t *in_buf  = (uint8_t *)in;
+
+    assert(in || out);
+
+    /* take care of the chip select */
+    if (cs != SPI_CS_UNDEF) {
+        gpio_clear((gpio_t)cs);
+    }
+
+    if (!in_buf) {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SPI_SR_TXE)) {}
+            dev(bus)->DR = out_buf[i];
+        }
+        while ((dev(bus)->SR & SPI_SR_BSY)) {}
+        dev(bus)->DR;
+    }
+    else if (!out_buf) {
+        for (size_t i = 0; i < len; i++) {
+            dev(bus)->DR = 0;
+            while (!dev(bus)->SR & SPI_SR_RXNE) {}
+            in_buf[i] = (uint8_t)dev(bus)->DR;
+        }
+    }
+    else {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SPI_SR_TXE)) {}
+            dev(bus)->DR = out_buf[i];
+            while (!(dev(bus)->SR & SPI_SR_RXNE)) {}
+            in_buf[i] = (uint8_t)dev(bus)->DR;
+        }
+    }
+
+    /* finally release chip select line if requested */
+    if ((cs != SPI_CS_UNDEF) && (!cont)) {
+        gpio_set((gpio_t)cs);
+    }
+}
+
+#endif /* SPI_NUMOF */
diff --git a/cpu/stm32f2/cpu.c b/cpu/stm32f2/cpu.c
index 8304176755be9256316e673f432ecd3f0decd310..2437e6ddb6f2b6a176d9840f9c5514d6a626c489 100644
--- a/cpu/stm32f2/cpu.c
+++ b/cpu/stm32f2/cpu.c
@@ -19,6 +19,7 @@
 
 #include "cpu.h"
 #include "periph_conf.h"
+#include "periph/init.h"
 
 #ifdef HSI_VALUE
 # define RCC_CR_SOURCE          RCC_CR_HSION
@@ -38,6 +39,8 @@ void cpu_init(void)
     cortexm_init();
     /* initialize system clocks */
     clk_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 /**
diff --git a/cpu/stm32f2/include/periph_cpu.h b/cpu/stm32f2/include/periph_cpu.h
index d9197f38958e1287eac076481a5861fa1d0d6041..ffd10918ac4412205dfc947d2eace1dfc1cb0251 100644
--- a/cpu/stm32f2/include/periph_cpu.h
+++ b/cpu/stm32f2/include/periph_cpu.h
@@ -104,13 +104,6 @@ typedef struct {
     uint8_t chan;           /**< DAC device used for this line */
 } dac_conf_t;
 
-/**
- * @brief   Configure the given pin to be used as ADC input
- *
- * @param[in] pin       pin to configure
- */
-void gpio_init_analog(gpio_t pin);
-
 /**
  * @brief   Power on the DMA device the given stream belongs to
  *
@@ -185,6 +178,11 @@ static inline uint32_t dma_ifc(int stream)
     }
 }
 
+/**
+ * @brief   Enable DMA interrupts
+ *
+ * @param[in] stream    logical DMA stream
+ */
 static inline void dma_isr_enable(int stream)
 {
     if (stream < 7) {
diff --git a/cpu/stm32f2/periph/spi.c b/cpu/stm32f2/periph/spi.c
deleted file mode 100644
index 3da216b9445cb2133ec75a1ad8ed53bbed3f32c4..0000000000000000000000000000000000000000
--- a/cpu/stm32f2/periph/spi.c
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright (C) 2014 Hamburg University of Applied Sciences
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
- */
-
-/**
- * @ingroup     cpu_stm32f2
- * @{
- *
- * @file
- * @brief       Low-level SPI driver implementation
- *
- * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
- * @author      Fabian Nack <nack@inf.fu-berlin.de>
- * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- *
- * @}
- */
-#include <stdio.h>
-
-#include "board.h"
-#include "cpu.h"
-#include "mutex.h"
-#include "periph/spi.h"
-#include "periph_conf.h"
-
-#define ENABLE_DEBUG (0)
-#include "debug.h"
-
-/* guard this file in case no SPI device is defined */
-#if SPI_NUMOF
-
-/**
- * @brief Data-structure holding the state for a SPI device
- */
-typedef struct {
-    char(*cb)(char data);
-} spi_state_t;
-
-static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev);
-
-/**
- * @brief Reserve memory for saving the SPI device's state
- */
-static spi_state_t spi_config[SPI_NUMOF];
-
-/* static bus div mapping */
-static const uint8_t spi_bus_div_map[SPI_NUMOF] = {
-#if SPI_0_EN
-    [SPI_0] = SPI_0_BUS_DIV,
-#endif
-#if SPI_1_EN
-    [SPI_1] = SPI_1_BUS_DIV,
-#endif
-#if SPI_2_EN
-    [SPI_2] = SPI_2_BUS_DIV,
-#endif
-};
-
-/**
- * @brief Array holding one pre-initialized mutex for each SPI device
- */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-#if SPI_2_EN
-    [SPI_2] = MUTEX_INIT
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
-{
-    uint8_t speed_devider;
-    SPI_TypeDef *spi_port;
-
-    switch (speed) {
-        case SPI_SPEED_100KHZ:
-            return -2;          /* not possible for stm32f2, APB2 minimum is 328 kHz */
-            break;
-        case SPI_SPEED_400KHZ:
-            speed_devider = 0x05 + spi_bus_div_map[dev];  /* makes 656 kHz */
-            break;
-        case SPI_SPEED_1MHZ:
-            speed_devider = 0x04 + spi_bus_div_map[dev];  /* makes 1.3 MHz */
-            break;
-        case SPI_SPEED_5MHZ:
-            speed_devider = 0x02 + spi_bus_div_map[dev];  /* makes 5.3 MHz */
-            break;
-        case SPI_SPEED_10MHZ:
-            speed_devider = 0x01 + spi_bus_div_map[dev];  /* makes 10.5 MHz */
-            break;
-        default:
-            return -1;
-    }
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi_port = SPI_0_DEV;
-            /* enable clocks */
-            SPI_0_CLKEN();
-            SPI_0_SCK_PORT_CLKEN();
-            SPI_0_MISO_PORT_CLKEN();
-            SPI_0_MOSI_PORT_CLKEN();
-            break;
-#endif /* SPI_0_EN */
-#if SPI_1_EN
-        case SPI_1:
-            spi_port = SPI_1_DEV;
-            /* enable clocks */
-            SPI_1_CLKEN();
-            SPI_1_SCK_PORT_CLKEN();
-            SPI_1_MISO_PORT_CLKEN();
-            SPI_1_MOSI_PORT_CLKEN();
-            break;
-#endif /* SPI_1_EN */
-#if SPI_2_EN
-        case SPI_2:
-            spi_port = SPI_2_DEV;
-            /* enable clocks */
-            SPI_2_CLKEN();
-            SPI_2_SCK_PORT_CLKEN();
-            SPI_2_MISO_PORT_CLKEN();
-            SPI_2_MOSI_PORT_CLKEN();
-            break;
-#endif /* SPI_2_EN */
-        default:
-            return -2;
-    }
-
-    /* configure SCK, MISO and MOSI pin */
-    spi_conf_pins(dev);
-
-    /**************** SPI-Init *****************/
-    spi_port->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD);/* Activate the SPI mode (Reset I2SMOD bit in I2SCFGR register) */
-    spi_port->CR1 = 0;
-    spi_port->CR2 = 0;
-    /* the NSS (chip select) is managed purely by software */
-    spi_port->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI;
-    spi_port->CR1 |= (speed_devider << 3);  /* Define serial clock baud rate. 001 leads to f_PCLK/4 */
-    spi_port->CR1 |= (SPI_CR1_MSTR);  /* 1: master configuration */
-    spi_port->CR1 |= (conf);
-    /* enable SPI */
-    spi_port->CR1 |= (SPI_CR1_SPE);
-    return 0;
-}
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data))
-{
-    SPI_TypeDef *spi_port;
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi_port = SPI_0_DEV;
-            /* enable clocks */
-            SPI_0_CLKEN();
-            SPI_0_SCK_PORT_CLKEN();
-            SPI_0_MISO_PORT_CLKEN();
-            SPI_0_MOSI_PORT_CLKEN();
-            /* configure interrupt channel */
-            NVIC_SetPriority(SPI_0_IRQ, SPI_IRQ_PRIO); /* set SPI interrupt priority */
-            NVIC_EnableIRQ(SPI_0_IRQ); /* set SPI interrupt priority */
-            break;
-#endif /* SPI_0_EN */
-#if SPI_1_EN
-        case SPI_1:
-            spi_port = SPI_1_DEV;
-            /* enable clocks */
-            SPI_1_CLKEN();
-            SPI_1_SCK_PORT_CLKEN();
-            SPI_1_MISO_PORT_CLKEN();
-            SPI_1_MOSI_PORT_CLKEN();
-            /* configure interrupt channel */
-            NVIC_SetPriority(SPI_1_IRQ, SPI_IRQ_PRIO);
-            NVIC_EnableIRQ(SPI_1_IRQ);
-            break;
-#endif /* SPI_1_EN */
-#if SPI_2_EN
-        case SPI_2:
-            spi_port = SPI_2_DEV;
-            /* enable clocks */
-            SPI_2_CLKEN();
-            SPI_2_SCK_PORT_CLKEN();
-            SPI_2_MISO_PORT_CLKEN();
-            SPI_2_MOSI_PORT_CLKEN();
-            /* configure interrupt channel */
-            NVIC_SetPriority(SPI_2_IRQ, SPI_IRQ_PRIO);
-            NVIC_EnableIRQ(SPI_2_IRQ);
-            break;
-#endif /* SPI_2_EN */
-        default:
-            return -1;
-    }
-
-    /* configure sck, miso and mosi pin */
-    spi_conf_pins(dev);
-
-    /***************** SPI-Init *****************/
-    spi_port->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD);
-    spi_port->CR1 = 0;
-    spi_port->CR2 = 0;
-    /* enable RXNEIE flag to enable rx buffer not empty interrupt */
-    spi_port->CR2 |= (SPI_CR2_RXNEIE); /*1:not masked */
-    spi_port->CR1 |= (conf);
-     /* the NSS (chip select) is managed by software and NSS is low (slave enabled) */
-    spi_port->CR1 |= SPI_CR1_SSM;
-    /* set callback */
-    spi_config[dev].cb = cb;
-    /* enable SPI device */
-    spi_port->CR1 |= SPI_CR1_SPE;
-    return 0;
-}
-
-int spi_conf_pins(spi_t dev)
-{
-    GPIO_TypeDef *port[3];
-    int pin[3], af[3];
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            port[0] = SPI_0_SCK_PORT;
-            pin[0] = SPI_0_SCK_PIN;
-            af[0] = SPI_0_SCK_AF;
-            port[1] = SPI_0_MOSI_PORT;
-            pin[1] = SPI_0_MOSI_PIN;
-            af[1] = SPI_0_MOSI_AF;
-            port[2] = SPI_0_MISO_PORT;
-            pin[2] = SPI_0_MISO_PIN;
-            af[2] = SPI_0_MISO_AF;
-            break;
-#endif /* SPI_0_EN */
-#if SPI_1_EN
-        case SPI_1:
-            port[0] = SPI_1_SCK_PORT;
-            pin[0] = SPI_1_SCK_PIN;
-            af[0] = SPI_1_SCK_AF;
-            port[1] = SPI_1_MOSI_PORT;
-            pin[1] = SPI_1_MOSI_PIN;
-            af[1] = SPI_1_MOSI_AF;
-            port[2] = SPI_1_MISO_PORT;
-            pin[2] = SPI_1_MISO_PIN;
-            af[2] = SPI_1_MISO_AF;
-            break;
-#endif /* SPI_1_EN */
-#if SPI_2_EN
-        case SPI_2:
-            port[0] = SPI_2_SCK_PORT;
-            pin[0] = SPI_2_SCK_PIN;
-            af[0] = SPI_2_SCK_AF;
-            port[1] = SPI_2_MOSI_PORT;
-            pin[1] = SPI_2_MOSI_PIN;
-            af[1] = SPI_2_MOSI_AF;
-            port[2] = SPI_2_MISO_PORT;
-            pin[2] = SPI_2_MISO_PIN;
-            af[2] = SPI_2_MISO_AF;
-            break;
-#endif /* SPI_2_EN */
-        default:
-            return -1;
-    }
-
-    /***************** GPIO-Init *****************/
-    for (int i = 0; i < 3; i++) {
-        /* Set GPIOs to AF mode */
-        port[i]->MODER &= ~(3 << (2 * pin[i]));
-        port[i]->MODER |= (2 << (2 * pin[i]));
-        /* Set speed */
-        port[i]->OSPEEDR &= ~(3 << (2 * pin[i]));
-        port[i]->OSPEEDR |= (3 << (2 * pin[i]));
-        /* Set to push-pull configuration */
-        port[i]->OTYPER &= ~(1 << pin[i]);
-        /* Configure push-pull resistors */
-        port[i]->PUPDR &= ~(3 << (2 * pin[i]));
-        port[i]->PUPDR |= (2 << (2 * pin[i]));
-        /* Configure GPIOs for the SPI alternate function */
-        int hl = (pin[i] < 8) ? 0 : 1;
-        port[i]->AFR[hl] &= ~(0xf << ((pin[i] - (hl * 8)) * 4));
-        port[i]->AFR[hl] |= (af[i] << ((pin[i] - (hl * 8)) * 4));
-    }
-
-    return 0;
-}
-
-int spi_acquire(spi_t dev)
-{
-    if (dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
-}
-
-int spi_release(spi_t dev)
-{
-    if (dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
-
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    SPI_TypeDef *spi_port;
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi_port = SPI_0_DEV;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            spi_port = SPI_1_DEV;
-            break;
-#endif
-#if SPI_2_EN
-        case SPI_2:
-            spi_port = SPI_2_DEV;
-            break;
-#endif
-        default:
-            return -1;
-    }
-
-    while (!(spi_port->SR & SPI_SR_TXE));
-    spi_port->DR = out;
-
-    while (!(spi_port->SR & SPI_SR_RXNE));
-
-    if (in != NULL) {
-        *in = spi_port->DR;
-    }
-    else {
-        spi_port->DR;
-    }
-
-    return 1;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            SPI_0_DEV->DR = reset_val;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            SPI_1_DEV->DR = reset_val;
-            break;
-#endif
-#if SPI_2_EN
-        case SPI_2:
-            SPI_2_DEV->DR = reset_val;
-            break;
-#endif
-    }
-}
-
-void spi_poweron(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            SPI_0_CLKEN();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            SPI_1_CLKEN();
-            break;
-#endif
-#if SPI_2_EN
-        case SPI_2:
-            SPI_2_CLKEN();
-            break;
-#endif
-    }
-}
-
-void spi_poweroff(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            while (SPI_0_DEV->SR & SPI_SR_BSY);
-            SPI_0_CLKDIS();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            while (SPI_1_DEV->SR & SPI_SR_BSY);
-            SPI_1_CLKDIS();
-            break;
-#endif
-#if SPI_2_EN
-        case SPI_2:
-            while (SPI_2_DEV->SR & SPI_SR_BSY);
-            SPI_2_CLKDIS();
-            break;
-#endif
-    }
-}
-
-static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev)
-{
-
-    if (spi->SR & SPI_SR_RXNE) {
-        char data;
-        data = spi->DR;
-        data = spi_config[dev].cb(data);
-        spi->DR = data;
-    }
-    /* see if a thread with higher priority wants to run now */
-    cortexm_isr_end();
-}
-
-#if SPI_0_EN
-void SPI_0_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_0_DEV, SPI_0);
-}
-#endif
-
-#if SPI_1_EN
-void SPI_1_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_1_DEV, SPI_1);
-}
-#endif
-
-#if SPI_2_EN
-void SPI_2_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_2_DEV, SPI_2);
-}
-#endif
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/stm32f2/periph/spi.cold b/cpu/stm32f2/periph/spi.cold
new file mode 100644
index 0000000000000000000000000000000000000000..d7a9cd5bbd3b6f944ca82d264016a26909e318fb
--- /dev/null
+++ b/cpu/stm32f2/periph/spi.cold
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014 Hamburg University of Applied Sciences
+ *               2016 OTA keys S.A.
+ *               2016 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_stm32f2
+ * @{
+ *
+ * @file
+ * @brief       Low-level SPI driver implementation
+ *
+ * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
+ * @author      Fabian Nack <nack@inf.fu-berlin.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ *
+ * @}
+ */
+
+#include "cpu.h"
+#include "mutex.h"
+#include "assert.h"
+#include "periph/spi.h"
+
+#define ENABLE_DEBUG        (0)
+#include "debug.h"
+
+/* Remove this ugly guard once we selectively build the periph drivers */
+#ifdef SPI_NUMOF
+
+/**
+ * @brief   Number of bits to shift the BR value in the CR1 register
+ */
+#define BR_SHIFT            (3U)
+
+/**
+ * @brief Array holding one pre-initialized mutex for each SPI device
+ */
+static mutex_t locks[SPI_NUMOF];
+
+static inline SPI_TypeDef *dev(spi_t bus)
+{
+    return spi_config[bus].dev;
+}
+
+void spi_init(spi_t bus)
+{
+    assert(bus < SPI_NUMOF);
+
+    mutex_init(&locks[bus]);
+
+    /* trigger pin initialization */
+    spi_init_pins(bus);
+}
+
+void spi_init_pins(spi_t bus)
+{
+    gpio_init(spi_config[bus].mosi_pin, GPIO_OUT);
+    gpio_init(spi_config[bus].miso_pin, GPIO_IN);
+    gpio_init(spi_config[bus].sclk_pin, GPIO_OUT);
+    gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af);
+    gpio_init_af(spi_config[bus].miso_pin, spi_config[bus].af);
+    gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].af);
+}
+
+int spi_init_cs(spi_t bus, spi_cs_t cs)
+{
+    if (bus >= SPI_NUMOF) {
+        return SPI_NODEV;
+    }
+    if (cs == SPI_CS_UNDEF ||
+        (((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) {
+        return SPI_NOCS;
+    }
+
+    if (cs == SPI_HWCS_MASK) {
+        if (spi_config[bus].cs_pin == GPIO_UNDEF) {
+            return SPI_NOCS;
+        }
+        gpio_init(spi_config[bus].cs_pin, GPIO_OUT);
+        gpio_init_af(spi_config[bus].cs_pin, spi_config[bus].af);
+    }
+    else {
+        gpio_init((gpio_t)cs, GPIO_OUT);
+        gpio_set((gpio_t)cs);
+    }
+
+    return SPI_OK;
+}
+
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    /* check clock speed for validity */
+    if (clk >= 0x0f) {
+        return SPI_NOCLK;
+    }
+
+    /* lock bus */
+    mutex_lock(&locks[bus]);
+    /* enable SPI device clock */
+    periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    /* enable device */
+    uint8_t br = spi_divtable[spi_config[bus].apbbus][clk];
+    dev(bus)->CR1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR);
+    dev(bus)->CR2 = 0;
+    if (cs != SPI_HWCS_MASK) {
+        dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI);
+    }
+    else {
+        dev(bus)->CR2 |= (SPI_CR2_SSOE);
+    }
+
+    return SPI_OK;
+}
+
+void spi_release(spi_t bus)
+{
+    /* disable device and release lock */
+    dev(bus)->CR1 = 0;
+    periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    mutex_unlock(&locks[bus]);
+}
+
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
+{
+    uint8_t *inbuf = (uint8_t *)in;
+    uint8_t *outbuf = (uint8_t *)out;
+
+    /* make sure at least one input or one output buffer is given */
+    assert(outbuf || inbuf);
+
+    /* active the given chip select line */
+    dev(bus)->CR1 |= (SPI_CR1_SPE);     /* this pulls the HW CS line low */
+    if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) {
+        gpio_clear((gpio_t)cs);
+    }
+
+    /* transfer data, use shortpath if only sending data */
+    if (!inbuf) {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SPI_SR_TXE));
+            dev(bus)->DR = outbuf[i];
+        }
+        /* wait until everything is finished and empty the receive buffer */
+        while (dev(bus)->SR & SPI_SR_BSY) {}
+        dev(bus)->DR;
+    }
+    else {
+        for (size_t i = 0; i < len; i++) {
+            uint8_t tmp = (outbuf) ? outbuf[i] : 0;
+            while (!(dev(bus)->SR & SPI_SR_TXE));
+            dev(bus)->DR = tmp;
+            while (!(dev(bus)->SR & SPI_SR_RXNE));
+            inbuf[i] = dev(bus)->DR;
+        }
+    }
+
+    /* release the chip select if not specified differently */
+    if ((!cont) && (cs != SPI_CS_UNDEF)) {
+        dev(bus)->CR1 &= ~(SPI_CR1_SPE);    /* pull HW CS line high */
+        if (cs != SPI_HWCS_MASK) {
+            gpio_set((gpio_t)cs);
+        }
+    }
+}
+
+#endif /* SPI_NUMOF */
diff --git a/cpu/stm32f3/cpu.c b/cpu/stm32f3/cpu.c
index 969a5c5a69d8303ffb12a389786597cf2f7e2de6..66bb7763a76191bb7cb42c2db09a094eed65bc38 100644
--- a/cpu/stm32f3/cpu.c
+++ b/cpu/stm32f3/cpu.c
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include "cpu.h"
 #include "periph_conf.h"
+#include "periph/init.h"
 
 /* Check the source to be used for the PLL */
 #if defined(CLOCK_HSI) && defined(CLOCK_HSE)
@@ -57,6 +58,8 @@ void cpu_init(void)
     cortexm_init();
     /* initialize the clock system */
     cpu_clock_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 /**
diff --git a/cpu/stm32f3/periph/spi.c b/cpu/stm32f3/periph/spi.c
deleted file mode 100644
index d128a4f84c2024b47500bed3d521e255c0b82950..0000000000000000000000000000000000000000
--- a/cpu/stm32f3/periph/spi.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Copyright (C) 2014 Hamburg University of Applied Sciences
- * Copyright (C) 2014 Freie Universität Berlin
- * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
- */
-
-/**
- * @ingroup     cpu_stm32f3
- * @{
- *
- * @file
- * @brief       Low-level SPI driver implementation
- *
- * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
- * @author      Fabian Nack <nack@inf.fu-berlin.de>
- * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
- * @author      Kaspar Schleiser <kaspar@schleiser.de>
- *
- * @}
- */
-#include <stdio.h>
-
-#include "board.h"
-#include "cpu.h"
-#include "mutex.h"
-#include "periph/spi.h"
-#include "periph_conf.h"
-
-#define ENABLE_DEBUG (0)
-#include "debug.h"
-
-/* guard this file in case no SPI device is defined */
-#if SPI_NUMOF
-
-typedef struct {
-    char(*cb)(char data);
-} spi_state_t;
-
-/* static device mapping */
-static SPI_TypeDef *const spi[] = {
-#if SPI_0_EN
-    SPI_0_DEV,
-#endif
-#if SPI_1_EN
-    SPI_1_DEV,
-#endif
-#if SPI_2_EN
-    SPI_2_DEV
-#endif
-};
-
-static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev);
-
-static spi_state_t spi_config[SPI_NUMOF];
-
-/**
- * @brief Array holding one pre-initialized mutex for each SPI device
- */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-#if SPI_2_EN
-    [SPI_2] = MUTEX_INIT
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
-{
-    uint8_t speed_divider;
-
-    switch (speed) {
-        case SPI_SPEED_100KHZ:
-            return -2;          /* not possible for stm32f3 */
-            break;
-        case SPI_SPEED_400KHZ:
-            speed_divider = 7;  /* makes 656 kHz */
-            break;
-        case SPI_SPEED_1MHZ:
-            speed_divider = 6;  /* makes 1.3 MHz */
-            break;
-        case SPI_SPEED_5MHZ:
-            speed_divider = 4;  /* makes 5.3 MHz */
-            break;
-        case SPI_SPEED_10MHZ:
-            speed_divider = 3;  /* makes 10.5 MHz */
-            break;
-        default:
-            return -1;
-    }
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            /* enable clocks */
-            SPI_0_CLKEN();
-            SPI_0_SCK_PORT_CLKEN();
-            SPI_0_MISO_PORT_CLKEN();
-            SPI_0_MOSI_PORT_CLKEN();
-            break;
-#endif /* SPI_0_EN */
-#if SPI_1_EN
-        case SPI_1:
-            /* enable clocks */
-            SPI_1_CLKEN();
-            SPI_1_SCK_PORT_CLKEN();
-            SPI_1_MISO_PORT_CLKEN();
-            SPI_1_MOSI_PORT_CLKEN();
-            break;
-#endif /* SPI_1_EN */
-#if SPI_2_EN
-        case SPI_2:
-            /* enable clocks */
-            SPI_2_CLKEN();
-            SPI_2_SCK_PORT_CLKEN();
-            SPI_2_MISO_PORT_CLKEN();
-            SPI_2_MOSI_PORT_CLKEN();
-            break;
-#endif /* SPI_2_EN */
-        default:
-            return -2;
-    }
-
-    /* configure SCK, MISO and MOSI pin */
-    spi_conf_pins(dev);
-
-    /**************** SPI-Init *****************/
-#ifdef CPU_MODEL_STM32F303VC
-    spi[dev]->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD);/* Activate the SPI mode (Reset I2SMOD bit in I2SCFGR register) */
-#endif
-    spi[dev]->CR1 = 0;
-    spi[dev]->CR2 = 0;
-    /* the NSS (chip select) is managed purely by software */
-    spi[dev]->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI;
-    spi[dev]->CR1 |= (speed_divider << 3);  /* Define serial clock baud rate. 001 leads to f_PCLK/4 */
-    spi[dev]->CR1 |= (SPI_CR1_MSTR);  /* 1: master configuration */
-    spi[dev]->CR1 |= (conf);
-
-    spi[dev]->CR2 |= SPI_CR2_FRXTH; /* set FIFO reception threshold to 8bit (default: 16bit) */
-
-    /* enable SPI */
-    spi[dev]->CR1 |= (SPI_CR1_SPE);
-
-    return 0;
-}
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data))
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            /* enable clocks */
-            SPI_0_CLKEN();
-            SPI_0_SCK_PORT_CLKEN();
-            SPI_0_MISO_PORT_CLKEN();
-            SPI_0_MOSI_PORT_CLKEN();
-            /* configure interrupt channel */
-            NVIC_SetPriority(SPI_0_IRQ, SPI_IRQ_PRIO); /* set SPI interrupt priority */
-            NVIC_EnableIRQ(SPI_0_IRQ); /* set SPI interrupt priority */
-            break;
-#endif /* SPI_0_EN */
-#if SPI_1_EN
-        case SPI_1:
-            /* enable clocks */
-            SPI_1_CLKEN();
-            SPI_1_SCK_PORT_CLKEN();
-            SPI_1_MISO_PORT_CLKEN();
-            SPI_1_MOSI_PORT_CLKEN();
-            /* configure interrupt channel */
-            NVIC_SetPriority(SPI_1_IRQ, SPI_IRQ_PRIO);
-            NVIC_EnableIRQ(SPI_1_IRQ);
-            break;
-#endif /* SPI_1_EN */
-#if SPI_2_EN
-        case SPI_2:
-            /* enable clocks */
-            SPI_2_CLKEN();
-            SPI_2_SCK_PORT_CLKEN();
-            SPI_2_MISO_PORT_CLKEN();
-            SPI_2_MOSI_PORT_CLKEN();
-            /* configure interrupt channel */
-            NVIC_SetPriority(SPI_2_IRQ, SPI_IRQ_PRIO);
-            NVIC_EnableIRQ(SPI_2_IRQ);
-            break;
-#endif /* SPI_2_EN */
-        default:
-            return -1;
-    }
-
-    /* configure sck, miso and mosi pin */
-    spi_conf_pins(dev);
-
-    /***************** SPI-Init *****************/
-#ifdef CPU_MODEL_STM32F303VC
-    spi[dev]->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD);
-#endif
-    spi[dev]->CR1 = 0;
-    spi[dev]->CR2 = 0;
-    /* enable RXNEIE flag to enable rx buffer not empty interrupt */
-    spi[dev]->CR2 |= (SPI_CR2_RXNEIE); /*1:not masked */
-    spi[dev]->CR1 |= (conf);
-     /* the NSS (chip select) is managed by software and NSS is low (slave enabled) */
-    spi[dev]->CR1 |= SPI_CR1_SSM;
-    /* set callback */
-    spi_config[dev].cb = cb;
-    /* enable SPI device */
-    spi[dev]->CR1 |= SPI_CR1_SPE;
-    return 0;
-}
-
-int spi_conf_pins(spi_t dev)
-{
-    GPIO_TypeDef *port[3];
-    int pin[3], af[3];
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            port[0] = SPI_0_SCK_PORT;
-            pin[0] = SPI_0_SCK_PIN;
-            af[0] = SPI_0_SCK_AF;
-            port[1] = SPI_0_MOSI_PORT;
-            pin[1] = SPI_0_MOSI_PIN;
-            af[1] = SPI_0_MOSI_AF;
-            port[2] = SPI_0_MISO_PORT;
-            pin[2] = SPI_0_MISO_PIN;
-            af[2] = SPI_0_MISO_AF;
-            break;
-#endif /* SPI_0_EN */
-#if SPI_1_EN
-        case SPI_1:
-            port[0] = SPI_1_SCK_PORT;
-            pin[0] = SPI_1_SCK_PIN;
-            af[0] = SPI_1_SCK_AF;
-            port[1] = SPI_1_MOSI_PORT;
-            pin[1] = SPI_1_MOSI_PIN;
-            af[1] = SPI_1_MOSI_AF;
-            port[2] = SPI_1_MISO_PORT;
-            pin[2] = SPI_1_MISO_PIN;
-            af[2] = SPI_1_MISO_AF;
-            break;
-#endif /* SPI_1_EN */
-#if SPI_2_EN
-        case SPI_2:
-            port[0] = SPI_2_SCK_PORT;
-            pin[0] = SPI_2_SCK_PIN;
-            af[0] = SPI_2_SCK_AF;
-            port[1] = SPI_2_MOSI_PORT;
-            pin[1] = SPI_2_MOSI_PIN;
-            af[1] = SPI_2_MOSI_AF;
-            port[2] = SPI_2_MISO_PORT;
-            pin[2] = SPI_2_MISO_PIN;
-            af[2] = SPI_2_MISO_AF;
-            break;
-#endif /* SPI_2_EN */
-        default:
-            return -1;
-    }
-
-    for (int i = 0; i < 3; i++) {
-        /* Set GPIOs to AF mode */
-        port[i]->MODER &= ~(3 << (2 * pin[i]));
-        port[i]->MODER |= (2 << (2 * pin[i]));
-        /* Set speed */
-        port[i]->OSPEEDR &= ~(3 << (2 * pin[i]));
-        port[i]->OSPEEDR |= (3 << (2 * pin[i]));
-        /* Set to push-pull configuration */
-        port[i]->OTYPER &= ~(1 << pin[i]);
-        /* Configure push-pull resistors */
-        port[i]->PUPDR &= ~(3 << (2 * pin[i]));
-        port[i]->PUPDR |= (2 << (2 * pin[i]));
-        /* Configure GPIOs for the SPI alternate function */
-        int hl = (pin[i] < 8) ? 0 : 1;
-        port[i]->AFR[hl] &= ~(0xf << ((pin[i] - (hl * 8)) * 4));
-        port[i]->AFR[hl] |= (af[i] << ((pin[i] - (hl * 8)) * 4));
-    }
-
-    return 0;
-}
-
-int spi_acquire(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
-}
-
-int spi_release(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
-
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    char tmp;
-
-    /* recast to uint_8 to force 8bit access */
-    volatile uint8_t *DR = (volatile uint8_t*) &spi[dev]->DR;
-
-    /* wait for an eventually previous byte to be readily transferred */
-    while(!(spi[dev]->SR & SPI_SR_TXE)) {}
-
-    /* put next byte into the output register */
-    *DR = out;
-
-    /* wait until the current byte was successfully transferred */
-    while(!(spi[dev]->SR & SPI_SR_RXNE)) {}
-
-    /* read response byte to reset flags */
-    tmp = *DR;
-
-    /* 'return' response byte if wished for */
-    if (in) {
-        *in = tmp;
-    }
-
-    return 1;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    if ((unsigned int)dev < SPI_NUMOF) {
-        spi[dev]->DR = reset_val;
-    }
-}
-
-void spi_poweron(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            SPI_0_CLKEN();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            SPI_1_CLKEN();
-            break;
-#endif
-#if SPI_2_EN
-        case SPI_2:
-            SPI_2_CLKEN();
-            break;
-#endif
-    }
-}
-
-void spi_poweroff(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            while (SPI_0_DEV->SR & SPI_SR_BSY) {}
-            SPI_0_CLKDIS();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            while (SPI_1_DEV->SR & SPI_SR_BSY) {}
-            SPI_1_CLKDIS();
-            break;
-#endif
-#if SPI_2_EN
-        case SPI_2:
-            while (SPI_2_DEV->SR & SPI_SR_BSY) {}
-            SPI_2_CLKDIS();
-            break;
-#endif
-    }
-}
-
-static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev)
-{
-
-    if (spi->SR & SPI_SR_RXNE) {
-        char data;
-        data = spi->DR;
-        data = spi_config[dev].cb(data);
-        spi->DR = data;
-    }
-    /* see if a thread with higher priority wants to run now */
-    cortexm_isr_end();
-}
-
-#if SPI_0_EN
-void SPI_0_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_0_DEV, SPI_0);
-}
-#endif
-
-#if SPI_1_EN
-void SPI_1_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_1_DEV, SPI_1);
-}
-#endif
-
-#if SPI_2_EN
-void SPI_2_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_2_DEV, SPI_2);
-}
-#endif
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/stm32f3/periph/spi.cold b/cpu/stm32f3/periph/spi.cold
new file mode 100644
index 0000000000000000000000000000000000000000..1f12f893b9f62f6855e758c7ed8bce32b573de75
--- /dev/null
+++ b/cpu/stm32f3/periph/spi.cold
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2014 Hamburg University of Applied Sciences
+ *               2016 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_stm32f4
+ * @{
+ *
+ * @file
+ * @brief       Low-level SPI driver implementation
+ *
+ * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
+ * @author      Fabian Nack <nack@inf.fu-berlin.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ *
+ * @}
+ */
+
+#include "cpu.h"
+#include "mutex.h"
+#include "assert.h"
+#include "periph/spi.h"
+
+#define ENABLE_DEBUG        (0)
+#include "debug.h"
+
+/* Remove this ugly guard once we selectively build the periph drivers */
+#ifdef SPI_NUMOF
+
+/**
+ * @brief   Number of bits to shift the BR value in the CR1 register
+ */
+#define BR_SHIFT            (3U)
+
+/**
+ * @brief Array holding one pre-initialized mutex for each SPI device
+ */
+static mutex_t locks[SPI_NUMOF];
+
+static inline SPI_TypeDef *dev(spi_t bus)
+{
+    return spi_config[bus].dev;
+}
+
+void spi_init(spi_t bus)
+{
+    assert(bus < SPI_NUMOF);
+
+    /* initialize device lock */
+    mutex_lock(&locks[bus]);
+    /* trigger pin initialization */
+    spi_init_pins(bus);
+}
+
+void spi_init_pins(spi_t bus)
+{
+    gpio_init(spi_config[bus].mosi_pin, GPIO_OUT);
+    gpio_init(spi_config[bus].miso_pin, GPIO_IN);
+    gpio_init(spi_config[bus].sclk_pin, GPIO_OUT);
+    gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af);
+    gpio_init_af(spi_config[bus].miso_pin, spi_config[bus].af);
+    gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].af);
+}
+
+int spi_init_cs(spi_t bus, spi_cs_t cs)
+{
+    if (bus >= SPI_NUMOF) {
+        return SPI_NODEV;
+    }
+    if (cs == SPI_CS_UNDEF ||
+        (((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) {
+        return SPI_NOCS;
+    }
+
+    if (cs == SPI_HWCS_MASK) {
+        if (spi_config[bus].cs_pin == GPIO_UNDEF) {
+            return SPI_NOCS;
+        }
+        gpio_init(spi_config[bus].cs_pin, GPIO_OUT);
+        gpio_init_af(spi_config[bus].cs_pin, spi_config[bus].af);
+    }
+    else {
+        gpio_init((gpio_t)cs, GPIO_OUT);
+        gpio_set((gpio_t)cs);
+    }
+
+    return SPI_OK;
+}
+
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    assert((clk >= SPI_CLK_100KHZ) && (clk <= SPI_CLK_10MHZ));
+
+    /* lock bus */
+    mutex_lock(&locks[bus]);
+    /* enable SPI device clock */
+    periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    /* configure clock and mode */
+    uint8_t br = spi_divtable[spi_config[bus].apbbus][clk];
+    dev(bus)->CR1 = ((br << 3) | mode | SPI_CR1_MSTR);
+    if (cs != SPI_HWCS_MASK) {
+        dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI);
+    }
+
+    return SPI_OK;
+}
+
+void spi_release(spi_t bus)
+{
+    /* disable device and release lock */
+    dev(bus)->CR1 = 0;
+    periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    mutex_unlock(&locks[bus]);
+}
+
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
+{
+    uint8_t *inbuf = (uint8_t *)in;
+    uint8_t *outbuf = (uint8_t *)out;
+
+    /* make sure at least one input or one output buffer is given */
+    assert(outbuf || inbuf);
+
+    /* active the given chip select line */
+    dev(bus)->CR1 |= (SPI_CR1_SPE);     /* this pulls the HW CS line low */
+    if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) {
+        gpio_clear((gpio_t)cs);
+    }
+
+    /* transfer data, use shortpath if only sending data */
+    if (!inbuf) {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SPI_SR_TXE));
+            dev(bus)->DR = outbuf[i];
+        }
+        /* wait until everything is finished and empty the receive buffer */
+        while (dev(bus)->SR & SPI_SR_BSY) {}
+        dev(bus)->DR;
+    }
+    else {
+        for (size_t i = 0; i < len; i++) {
+            uint8_t tmp = (outbuf) ? outbuf[i] : 0;
+            while (!(dev(bus)->SR & SPI_SR_TXE));
+            dev(bus)->DR = tmp;
+            while (!(dev(bus)->SR & SPI_SR_RXNE));
+            inbuf[i] = dev(bus)->DR;
+        }
+    }
+
+    /* release the chip select if not specified differently */
+    if ((!cont) && (cs != SPI_CS_UNDEF)) {
+        dev(bus)->CR1 &= ~(SPI_CR1_SPE);    /* pull HW CS line high */
+        if (cs != SPI_HWCS_MASK) {
+            gpio_set((gpio_t)cs);
+        }
+    }
+}
+
+#endif /* SPI_NUMOF */
diff --git a/cpu/stm32f4/Makefile.include b/cpu/stm32f4/Makefile.include
index 8d5704e1c3711ff18ca224503800d4df91d873c0..bf4156f52dce3a279d296599a0f541a2a8cb5e8f 100644
--- a/cpu/stm32f4/Makefile.include
+++ b/cpu/stm32f4/Makefile.include
@@ -4,4 +4,5 @@ export CPU_FAM  = stm32f4
 USEMODULE += pm_layered
 
 include $(RIOTCPU)/stm32_common/Makefile.include
+
 include $(RIOTCPU)/Makefile.include.cortexm_common
diff --git a/cpu/stm32f4/cpu.c b/cpu/stm32f4/cpu.c
index b2e50c6988cbc58581f1d76baa1c338e9f251408..09e2b71e1cc1f484c0e6755f3915f401b5f4e078 100644
--- a/cpu/stm32f4/cpu.c
+++ b/cpu/stm32f4/cpu.c
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include "cpu.h"
 #include "periph_conf.h"
+#include "periph/init.h"
 
 /* Check the source to be used for the PLL */
 #if defined(CLOCK_HSI) && defined(CLOCK_HSE)
@@ -50,6 +51,8 @@ void cpu_init(void)
     cortexm_init();
     /* initialize the clock system */
     cpu_clock_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 /**
diff --git a/cpu/stm32f4/include/periph_cpu.h b/cpu/stm32f4/include/periph_cpu.h
index e71b75b59cf52f6547e879d6c2782bc089724fe9..141620483de3df10e67f1e6934c42f5bef57fdff 100644
--- a/cpu/stm32f4/include/periph_cpu.h
+++ b/cpu/stm32f4/include/periph_cpu.h
@@ -34,15 +34,6 @@ extern "C" {
 #define ADC_DEVS            (3U)
 #endif
 
-/**
- * @brief declare needed generic SPI functions
- * @{
- */
-#define PERIPH_SPI_NEEDS_TRANSFER_BYTES
-#define PERIPH_SPI_NEEDS_TRANSFER_REG
-#define PERIPH_SPI_NEEDS_TRANSFER_REGS
-/** @} */
-
 #ifndef DOXYGEN
 /**
  * @brief   Override the ADC resolution configuration
diff --git a/cpu/stm32f4/periph/spi.c b/cpu/stm32f4/periph/spi.c
deleted file mode 100644
index 89809a90b791cce1ce5b7f16537c8317ccdab998..0000000000000000000000000000000000000000
--- a/cpu/stm32f4/periph/spi.c
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright (C) 2014 Hamburg University of Applied Sciences
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
- */
-
-/**
- * @ingroup     cpu_stm32f4
- * @{
- *
- * @file
- * @brief       Low-level SPI driver implementation
- *
- * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
- * @author      Fabian Nack <nack@inf.fu-berlin.de>
- * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- *
- * @}
- */
-#include <stdio.h>
-
-#include "board.h"
-#include "cpu.h"
-#include "mutex.h"
-#include "periph/spi.h"
-#include "periph_conf.h"
-
-#define ENABLE_DEBUG (0)
-#include "debug.h"
-
-/* guard this file in case no SPI device is defined */
-#if SPI_NUMOF
-
-/**
- * @brief Data-structure holding the state for a SPI device
- */
-typedef struct {
-    char(*cb)(char data);
-} spi_state_t;
-
-static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev);
-
-/**
- * @brief Reserve memory for saving the SPI device's state
- */
-static spi_state_t spi_config[SPI_NUMOF];
-
-/* static bus div mapping */
-static const uint8_t spi_bus_div_map[SPI_NUMOF] = {
-#if SPI_0_EN
-    [SPI_0] = SPI_0_BUS_DIV,
-#endif
-#if SPI_1_EN
-    [SPI_1] = SPI_1_BUS_DIV,
-#endif
-#if SPI_2_EN
-    [SPI_2] = SPI_2_BUS_DIV,
-#endif
-};
-
-/**
- * @brief Array holding one pre-initialized mutex for each SPI device
- */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-#if SPI_2_EN
-    [SPI_2] = MUTEX_INIT
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
-{
-    uint8_t speed_devider;
-    SPI_TypeDef *spi_port;
-
-    switch (speed) {
-        case SPI_SPEED_100KHZ:
-            return -2;          /* not possible for stm32f4, APB2 minimum is 328 kHz */
-            break;
-        case SPI_SPEED_400KHZ:
-            speed_devider = 0x05 + spi_bus_div_map[dev];  /* makes 656 kHz */
-            break;
-        case SPI_SPEED_1MHZ:
-            speed_devider = 0x04 + spi_bus_div_map[dev];  /* makes 1.3 MHz */
-            break;
-        case SPI_SPEED_5MHZ:
-            speed_devider = 0x02 + spi_bus_div_map[dev];  /* makes 5.3 MHz */
-            break;
-        case SPI_SPEED_10MHZ:
-            speed_devider = 0x01 + spi_bus_div_map[dev];  /* makes 10.5 MHz */
-            break;
-        default:
-            return -1;
-    }
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi_port = SPI_0_DEV;
-            /* enable clocks */
-            SPI_0_CLKEN();
-            SPI_0_SCK_PORT_CLKEN();
-            SPI_0_MISO_PORT_CLKEN();
-            SPI_0_MOSI_PORT_CLKEN();
-            break;
-#endif /* SPI_0_EN */
-#if SPI_1_EN
-        case SPI_1:
-            spi_port = SPI_1_DEV;
-            /* enable clocks */
-            SPI_1_CLKEN();
-            SPI_1_SCK_PORT_CLKEN();
-            SPI_1_MISO_PORT_CLKEN();
-            SPI_1_MOSI_PORT_CLKEN();
-            break;
-#endif /* SPI_1_EN */
-#if SPI_2_EN
-        case SPI_2:
-            spi_port = SPI_2_DEV;
-            /* enable clocks */
-            SPI_2_CLKEN();
-            SPI_2_SCK_PORT_CLKEN();
-            SPI_2_MISO_PORT_CLKEN();
-            SPI_2_MOSI_PORT_CLKEN();
-            break;
-#endif /* SPI_2_EN */
-        default:
-            return -2;
-    }
-
-    /* configure SCK, MISO and MOSI pin */
-    spi_conf_pins(dev);
-
-    /**************** SPI-Init *****************/
-    spi_port->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD);/* Activate the SPI mode (Reset I2SMOD bit in I2SCFGR register) */
-    spi_port->CR1 = 0;
-    spi_port->CR2 = 0;
-    /* the NSS (chip select) is managed purely by software */
-    spi_port->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI;
-    spi_port->CR1 |= (speed_devider << 3);  /* Define serial clock baud rate. 001 leads to f_PCLK/4 */
-    spi_port->CR1 |= (SPI_CR1_MSTR);  /* 1: master configuration */
-    spi_port->CR1 |= (conf);
-    /* enable SPI */
-    spi_port->CR1 |= (SPI_CR1_SPE);
-    return 0;
-}
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data))
-{
-    SPI_TypeDef *spi_port;
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi_port = SPI_0_DEV;
-            /* enable clocks */
-            SPI_0_CLKEN();
-            SPI_0_SCK_PORT_CLKEN();
-            SPI_0_MISO_PORT_CLKEN();
-            SPI_0_MOSI_PORT_CLKEN();
-            /* configure interrupt channel */
-            NVIC_SetPriority(SPI_0_IRQ, SPI_IRQ_PRIO); /* set SPI interrupt priority */
-            NVIC_EnableIRQ(SPI_0_IRQ); /* set SPI interrupt priority */
-            break;
-#endif /* SPI_0_EN */
-#if SPI_1_EN
-        case SPI_1:
-            spi_port = SPI_1_DEV;
-            /* enable clocks */
-            SPI_1_CLKEN();
-            SPI_1_SCK_PORT_CLKEN();
-            SPI_1_MISO_PORT_CLKEN();
-            SPI_1_MOSI_PORT_CLKEN();
-            /* configure interrupt channel */
-            NVIC_SetPriority(SPI_1_IRQ, SPI_IRQ_PRIO);
-            NVIC_EnableIRQ(SPI_1_IRQ);
-            break;
-#endif /* SPI_1_EN */
-#if SPI_2_EN
-        case SPI_2:
-            spi_port = SPI_2_DEV;
-            /* enable clocks */
-            SPI_2_CLKEN();
-            SPI_2_SCK_PORT_CLKEN();
-            SPI_2_MISO_PORT_CLKEN();
-            SPI_2_MOSI_PORT_CLKEN();
-            /* configure interrupt channel */
-            NVIC_SetPriority(SPI_2_IRQ, SPI_IRQ_PRIO);
-            NVIC_EnableIRQ(SPI_2_IRQ);
-            break;
-#endif /* SPI_2_EN */
-        default:
-            return -1;
-    }
-
-    /* configure sck, miso and mosi pin */
-    spi_conf_pins(dev);
-
-    /***************** SPI-Init *****************/
-    spi_port->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD);
-    spi_port->CR1 = 0;
-    spi_port->CR2 = 0;
-    /* enable RXNEIE flag to enable rx buffer not empty interrupt */
-    spi_port->CR2 |= (SPI_CR2_RXNEIE); /*1:not masked */
-    spi_port->CR1 |= (conf);
-     /* the NSS (chip select) is managed by software and NSS is low (slave enabled) */
-    spi_port->CR1 |= SPI_CR1_SSM;
-    /* set callback */
-    spi_config[dev].cb = cb;
-    /* enable SPI device */
-    spi_port->CR1 |= SPI_CR1_SPE;
-    return 0;
-}
-
-int spi_conf_pins(spi_t dev)
-{
-    GPIO_TypeDef *port[3];
-    int pin[3], af[3];
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            port[0] = SPI_0_SCK_PORT;
-            pin[0] = SPI_0_SCK_PIN;
-            af[0] = SPI_0_SCK_AF;
-            port[1] = SPI_0_MOSI_PORT;
-            pin[1] = SPI_0_MOSI_PIN;
-            af[1] = SPI_0_MOSI_AF;
-            port[2] = SPI_0_MISO_PORT;
-            pin[2] = SPI_0_MISO_PIN;
-            af[2] = SPI_0_MISO_AF;
-            break;
-#endif /* SPI_0_EN */
-#if SPI_1_EN
-        case SPI_1:
-            port[0] = SPI_1_SCK_PORT;
-            pin[0] = SPI_1_SCK_PIN;
-            af[0] = SPI_1_SCK_AF;
-            port[1] = SPI_1_MOSI_PORT;
-            pin[1] = SPI_1_MOSI_PIN;
-            af[1] = SPI_1_MOSI_AF;
-            port[2] = SPI_1_MISO_PORT;
-            pin[2] = SPI_1_MISO_PIN;
-            af[2] = SPI_1_MISO_AF;
-            break;
-#endif /* SPI_1_EN */
-#if SPI_2_EN
-        case SPI_2:
-            port[0] = SPI_2_SCK_PORT;
-            pin[0] = SPI_2_SCK_PIN;
-            af[0] = SPI_2_SCK_AF;
-            port[1] = SPI_2_MOSI_PORT;
-            pin[1] = SPI_2_MOSI_PIN;
-            af[1] = SPI_2_MOSI_AF;
-            port[2] = SPI_2_MISO_PORT;
-            pin[2] = SPI_2_MISO_PIN;
-            af[2] = SPI_2_MISO_AF;
-            break;
-#endif /* SPI_2_EN */
-        default:
-            return -1;
-    }
-
-    /***************** GPIO-Init *****************/
-    for (int i = 0; i < 3; i++) {
-        /* Set GPIOs to AF mode */
-        port[i]->MODER &= ~(3 << (2 * pin[i]));
-        port[i]->MODER |= (2 << (2 * pin[i]));
-        /* Set speed */
-        port[i]->OSPEEDR &= ~(3 << (2 * pin[i]));
-        port[i]->OSPEEDR |= (3 << (2 * pin[i]));
-        /* Set to push-pull configuration */
-        port[i]->OTYPER &= ~(1 << pin[i]);
-        /* Configure push-pull resistors */
-        port[i]->PUPDR &= ~(3 << (2 * pin[i]));
-        port[i]->PUPDR |= (2 << (2 * pin[i]));
-        /* Configure GPIOs for the SPI alternate function */
-        int hl = (pin[i] < 8) ? 0 : 1;
-        port[i]->AFR[hl] &= ~(0xf << ((pin[i] - (hl * 8)) * 4));
-        port[i]->AFR[hl] |= (af[i] << ((pin[i] - (hl * 8)) * 4));
-    }
-
-    return 0;
-}
-
-int spi_acquire(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
-}
-
-int spi_release(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
-
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    SPI_TypeDef *spi_port;
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi_port = SPI_0_DEV;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            spi_port = SPI_1_DEV;
-            break;
-#endif
-#if SPI_2_EN
-        case SPI_2:
-            spi_port = SPI_2_DEV;
-            break;
-#endif
-        default:
-            return -1;
-    }
-
-    while (!(spi_port->SR & SPI_SR_TXE)) {}
-    spi_port->DR = out;
-
-    while (!(spi_port->SR & SPI_SR_RXNE)) {}
-
-    if (in != NULL) {
-        *in = spi_port->DR;
-    }
-    else {
-        spi_port->DR;
-    }
-
-    return 1;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            SPI_0_DEV->DR = reset_val;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            SPI_1_DEV->DR = reset_val;
-            break;
-#endif
-#if SPI_2_EN
-        case SPI_2:
-            SPI_2_DEV->DR = reset_val;
-            break;
-#endif
-    }
-}
-
-void spi_poweron(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            SPI_0_CLKEN();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            SPI_1_CLKEN();
-            break;
-#endif
-#if SPI_2_EN
-        case SPI_2:
-            SPI_2_CLKEN();
-            break;
-#endif
-    }
-}
-
-void spi_poweroff(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            while (SPI_0_DEV->SR & SPI_SR_BSY) {}
-            SPI_0_CLKDIS();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            while (SPI_1_DEV->SR & SPI_SR_BSY) {}
-            SPI_1_CLKDIS();
-            break;
-#endif
-#if SPI_2_EN
-        case SPI_2:
-            while (SPI_2_DEV->SR & SPI_SR_BSY) {}
-            SPI_2_CLKDIS();
-            break;
-#endif
-    }
-}
-
-static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev)
-{
-
-    if (spi->SR & SPI_SR_RXNE) {
-        char data;
-        data = spi->DR;
-        data = spi_config[dev].cb(data);
-        spi->DR = data;
-    }
-    /* see if a thread with higher priority wants to run now */
-    cortexm_isr_end();
-}
-
-#if SPI_0_EN
-void SPI_0_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_0_DEV, SPI_0);
-}
-#endif
-
-#if SPI_1_EN
-void SPI_1_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_1_DEV, SPI_1);
-}
-#endif
-
-#if SPI_2_EN
-void SPI_2_IRQ_HANDLER(void)
-{
-    irq_handler_transfer(SPI_2_DEV, SPI_2);
-}
-#endif
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/stm32l1/cpu.c b/cpu/stm32l1/cpu.c
index bf092531d642d850e36ed22faa01d0473583e21d..f0ebc74e62312e38adf1c3ced935035acdff737e 100644
--- a/cpu/stm32l1/cpu.c
+++ b/cpu/stm32l1/cpu.c
@@ -22,6 +22,7 @@
 #include "cpu.h"
 #include "board.h"
 #include "periph_conf.h"
+#include "periph/init.h"
 
 /* Check the source to be used for the PLL */
 #if defined(CLOCK_HSI) && defined(CLOCK_HSE)
@@ -46,6 +47,8 @@ void cpu_init(void)
     cortexm_init();
     /* initialize system clocks */
     clk_init();
+    /* trigger static peripheral initialization */
+    periph_init();
 }
 
 /**
diff --git a/cpu/stm32l1/include/periph_cpu.h b/cpu/stm32l1/include/periph_cpu.h
index d8b06ee2a2e34ae2cbb688b3cff27a906d31c2aa..94880fed64a6cbe44e0ebb6dd33e030ff9a2f41f 100644
--- a/cpu/stm32l1/include/periph_cpu.h
+++ b/cpu/stm32l1/include/periph_cpu.h
@@ -89,6 +89,16 @@ typedef struct {
     uint8_t ev_irqn;        /**< event IRQ */
 } i2c_conf_t;
 
+/**
+ * @brief   Configure the alternate function for the given pin
+ *
+ * @note    This is meant for internal use in STM32L1 peripheral drivers only
+ *
+ * @param[in] pin       pin to configure
+ * @param[in] af        alternate function to use
+ */
+void gpio_init_af(gpio_t pin, gpio_af_t af);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/cpu/stm32l1/periph/spi.c b/cpu/stm32l1/periph/spi.c
deleted file mode 100644
index f9e7f40e580f75e699b7803029db4403192ca80e..0000000000000000000000000000000000000000
--- a/cpu/stm32l1/periph/spi.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright (C) 2014 Freie Universität Berlin
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
- */
-
-/**
- * @addtogroup  driver_periph
- * @{
- *
- * @file
- * @brief       Low-level SPI driver implementation
- *
- * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
- * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
- * @author      Fabian Nack <nack@inf.fu-berlin.de>
- * @author      Thomas Eichinger <thomas.eichinger@fu-berlin.de>
- * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
- *
- * @}
- */
-
-#include "cpu.h"
-#include "mutex.h"
-#include "periph/spi.h"
-#include "periph_conf.h"
-#include "thread.h"
-#include "sched.h"
-
-/* guard file in case no SPI device is defined */
-#if SPI_NUMOF
-
-/**
- * @brief Array holding one pre-initialized mutex for each SPI device
- */
-static mutex_t locks[] =  {
-#if SPI_0_EN
-    [SPI_0] = MUTEX_INIT,
-#endif
-#if SPI_1_EN
-    [SPI_1] = MUTEX_INIT,
-#endif
-#if SPI_2_EN
-    [SPI_2] = MUTEX_INIT
-#endif
-};
-
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
-{
-    SPI_TypeDef *spi;
-
-    /* power on the SPI device */
-    spi_poweron(dev);
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi = SPI_0_DEV;
-            SPI_0_PORT_CLKEN();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            spi = SPI_1_DEV;
-            SPI_1_PORT_CLKEN();
-            break;
-#endif
-        default:
-            return -1;
-    }
-
-    /* configure SCK, MISO and MOSI pin */
-    spi_conf_pins(dev);
-
-    /* reset SPI configuration registers */
-    spi->CR1 = 0;
-    spi->CR2 = 0;
-    spi->I2SCFGR = 0;       /* this makes sure SPI mode is selected */
-
-    /* configure bus clock speed */
-    switch (speed) {
-        case SPI_SPEED_100KHZ:
-            spi->CR1 |= (7 << 3);       /* actual clock: 125KHz (lowest possible) */
-            break;
-        case SPI_SPEED_400KHZ:
-            spi->CR1 |= (5 << 3);       /* actual clock: 500KHz */
-            break;
-        case SPI_SPEED_1MHZ:
-            spi->CR1 |= (4 << 3);       /* actual clock: 1MHz */
-            break;
-        case SPI_SPEED_5MHZ:
-            spi->CR1 |= (2 << 3);       /* actual clock: 4MHz */
-            break;
-        case SPI_SPEED_10MHZ:
-            spi->CR1 |= (1 << 3);       /* actual clock 8MHz */
-    }
-
-    /* select clock polarity and clock phase */
-    spi->CR1 |= conf;
-    /* select master mode */
-    spi->CR1 |= SPI_CR1_MSTR;
-    /* the NSS (chip select) is managed purely by software */
-    spi->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI;
-    /* enable the SPI device */
-    spi->CR1 |= SPI_CR1_SPE;
-    return 0;
-}
-
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data))
-{
-    /* due to issues with the send buffer, the slave mode is not (yet) supported */
-    return -1;
-}
-
-int spi_conf_pins(spi_t dev)
-{
-    GPIO_TypeDef *port;
-    int pin[3];        /* 3 pins: sck, miso, mosi */
-    int af = 0;
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            port = SPI_0_PORT;
-            pin[0] = SPI_0_PIN_SCK;
-            pin[1] = SPI_0_PIN_MISO;
-            pin[2] = SPI_0_PIN_MOSI;
-            af = SPI_0_PIN_AF;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            port = SPI_1_PORT;
-            pin[0] = SPI_1_PIN_SCK;
-            pin[1] = SPI_1_PIN_MISO;
-            pin[2] = SPI_1_PIN_MOSI;
-            af = SPI_1_PIN_AF;
-            break;
-#endif
-        default:
-            return -1;
-    }
-
-    /* configure pins for their correct alternate function */
-    for (int i = 0; i < 3; i++) {
-        port->MODER &= ~(3 << (pin[i] * 2));
-        port->MODER |= (2 << (pin[i] * 2));
-        port->OSPEEDR |= (3 << (pin[i] * 2));
-        int hl = (pin[i] < 8) ? 0 : 1;
-        port->AFR[hl] &= ~(0xf << ((pin[i] - (hl * 8)) * 4));
-        port->AFR[hl] |= (af << ((pin[i] - (hl * 8)) * 4));
-    }
-
-    return 0;
-}
-
-int spi_acquire(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_lock(&locks[dev]);
-    return 0;
-}
-
-int spi_release(spi_t dev)
-{
-    if ((unsigned int)dev >= SPI_NUMOF) {
-        return -1;
-    }
-    mutex_unlock(&locks[dev]);
-    return 0;
-}
-
-int spi_transfer_byte(spi_t dev, char out, char *in)
-{
-    char tmp;
-    SPI_TypeDef *spi = 0;
-
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            spi = SPI_0_DEV;
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            spi = SPI_1_DEV;
-            break;
-#endif
-        default:
-            return 0;
-    }
-
-    /* wait for an eventually previous byte to be readily transferred */
-    while(!(spi->SR & SPI_SR_TXE)) {}
-    /* put next byte into the output register */
-    spi->DR = out;
-    /* wait until the current byte was successfully transferred */
-    while(!(spi->SR & SPI_SR_RXNE)) {}
-    /* read response byte to reset flags */
-    tmp = spi->DR;
-    /* 'return' response byte if wished for */
-    if (in) {
-        *in = tmp;
-    }
-
-#if ENABLE_DEBUG
-    if (in != NULL) {
-        DEBUG("\nout: %x in: %x \n", out, *in, transferred);
-    }
-    else {
-        DEBUG("\nout: %x in: was nullPointer\n", out, transferred);
-    }
-#endif /*ENABLE_DEBUG */
-
-    return 1;
-}
-
-void spi_transmission_begin(spi_t dev, char reset_val)
-{
-    /* slave mode is not (yet) supported */
-}
-
-void spi_poweron(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            SPI_0_CLKEN();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            SPI_1_CLKEN();
-            break;
-#endif
-    }
-}
-
-void spi_poweroff(spi_t dev)
-{
-    switch (dev) {
-#if SPI_0_EN
-        case SPI_0:
-            while (SPI_0_DEV->SR & SPI_SR_BSY) {}
-            SPI_0_CLKDIS();
-            break;
-#endif
-#if SPI_1_EN
-        case SPI_1:
-            while (SPI_1_DEV->SR & SPI_SR_BSY) {}
-            SPI_1_CLKDIS();
-            break;
-#endif
-    }
-}
-
-#endif /* SPI_NUMOF */
diff --git a/cpu/stm32l1/periph/spi.cold b/cpu/stm32l1/periph/spi.cold
new file mode 100644
index 0000000000000000000000000000000000000000..f664b6bd4b0d3bd894d80f0cede9e47ae4ab5a59
--- /dev/null
+++ b/cpu/stm32l1/periph/spi.cold
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2014-2016 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @addtogroup  driver_periph
+ * @{
+ *
+ * @file
+ * @brief       Low-level SPI driver implementation
+ *
+ * @author      Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ * @author      Fabian Nack <nack@inf.fu-berlin.de>
+ * @author      Thomas Eichinger <thomas.eichinger@fu-berlin.de>
+ * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
+ *
+ * @}
+ */
+
+#include "cpu.h"
+#include "mutex.h"
+#include "assert.h"
+#include "periph/spi.h"
+
+/* Remove this ugly guard once we selectively build the periph drivers */
+#ifdef SPI_NUMOF
+
+/**
+ * @brief   Number of bits to shift the BR value in the CR1 register
+ */
+#define BR_SHIFT            (3U)
+
+/**
+ * @brief   Allocate one lock per SPI device
+ */
+static mutex_t locks[SPI_NUMOF];
+
+static inline SPI_TypeDef *dev(spi_t bus)
+{
+    return spi_config[bus].dev;
+}
+
+void spi_init(spi_t bus)
+{
+    assert(bus < SPI_NUMOF);
+
+    /* initialize device lock */
+    mutex_lock(&locks[bus]);
+    /* trigger pin initialization */
+    spi_init_pins(bus);
+}
+
+void spi_init_pins(spi_t bus)
+{
+    gpio_init(spi_config[bus].mosi_pin, GPIO_OUT);
+    gpio_init(spi_config[bus].miso_pin, GPIO_IN);
+    gpio_init(spi_config[bus].sclk_pin, GPIO_OUT);
+    gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af);
+    gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af);
+    gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].af);
+}
+
+int spi_init_cs(spi_t bus, spi_cs_t cs)
+{
+    if (bus >= SPI_NUMOF) {
+        return SPI_NODEV;
+    }
+    if (cs == SPI_CS_UNDEF ||
+        (((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) {
+        return SPI_NOCS;
+    }
+
+    if (cs == SPI_HWCS_MASK) {
+        if (spi_config[bus].cs_pin == GPIO_UNDEF) {
+            return SPI_NOCS;
+        }
+        gpio_init(spi_config[bus].cs_pin, GPIO_OUT);
+        gpio_init_af(spi_config[bus].cs_pin, spi_config[bus].af);
+    }
+    else {
+        gpio_init((gpio_t)cs, GPIO_OUT);
+        gpio_set((gpio_t)cs);
+    }
+
+    return SPI_OK;
+}
+
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    /* check clock speed for validity */
+    if (clk >= 0x0f) {
+        return SPI_NOCLK;
+    }
+
+    /* lock bus */
+    mutex_lock(&locks[bus]);
+    /* enable SPI device clock */
+    periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    /* enable device */
+    uint8_t br = spi_divtable[spi_config[bus].apbbus][clk];
+    dev(bus)->CR1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR);
+    if (cs != SPI_HWCS_MASK) {
+        dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI);
+    }
+
+    return SPI_OK;
+}
+
+void spi_release(spi_t bus)
+{
+    /* disable device and release lock */
+    dev(bus)->CR1 = 0;
+    periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask);
+    mutex_unlock(&locks[bus]);
+}
+
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
+{
+    uint8_t *inbuf = (uint8_t *)in;
+    uint8_t *outbuf = (uint8_t *)out;
+
+    /* make sure at least one input or one output buffer is given */
+    assert(outbuf || inbuf);
+
+    /* active the given chip select line */
+    dev(bus)->CR1 |= (SPI_CR1_SPE);     /* this pulls the HW CS line low */
+    if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) {
+        gpio_clear((gpio_t)cs);
+    }
+
+    /* transfer data, use shortpath if only sending data */
+    if (!inbuf) {
+        for (size_t i = 0; i < len; i++) {
+            while (!(dev(bus)->SR & SPI_SR_TXE));
+            dev(bus)->DR = outbuf[i];
+        }
+        /* wait until everything is finished and empty the receive buffer */
+        while (dev(bus)->SR & SPI_SR_BSY) {}
+        dev(bus)->DR;
+    }
+    else {
+        for (size_t i = 0; i < len; i++) {
+            uint8_t tmp = (outbuf) ? outbuf[i] : 0;
+            while (!(dev(bus)->SR & SPI_SR_TXE));
+            dev(bus)->DR = tmp;
+            while (!(dev(bus)->SR & SPI_SR_RXNE));
+            inbuf[i] = dev(bus)->DR;
+        }
+    }
+
+    /* release the chip select if not specified differently */
+    if ((!cont) && (cs != SPI_CS_UNDEF)) {
+        dev(bus)->CR1 &= ~(SPI_CR1_SPE);    /* pull HW CS line high */
+        if (cs != SPI_HWCS_MASK) {
+            gpio_set((gpio_t)cs);
+        }
+    }
+}
+
+#endif /* SPI_NUMOF */
diff --git a/drivers/adt7310/adt7310.c b/drivers/adt7310/adt7310.c
index 50c38da6237f5b9b601c6bfdfdc9e16746cb1eb8..bf65630e8e39c3fd7374342139b559fe19b80246 100644
--- a/drivers/adt7310/adt7310.c
+++ b/drivers/adt7310/adt7310.c
@@ -95,15 +95,9 @@ static int adt7310_read_reg(const adt7310_t *dev, const uint8_t addr, const uint
     int status = 0;
     uint8_t command = ADT7310_CMD_READ | (addr << ADT7310_CMD_ADDR_SHIFT);
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE_0, dev->clk);
     /* Perform the transaction */
-    gpio_clear(dev->cs);
-
-    if (spi_transfer_regs(dev->spi, command, NULL, (char *)buf, len) < len) {
-        status = -1;
-    }
-
-    gpio_set(dev->cs);
+    spi_transfer_regs(dev->spi, dev->cs, command, NULL, buf, (size_t)len);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
@@ -127,34 +121,28 @@ static int adt7310_write_reg(const adt7310_t *dev, const uint8_t addr,
     int status = 0;
     uint8_t command = ADT7310_CMD_WRITE | (addr << ADT7310_CMD_ADDR_SHIFT);
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE_0, dev->clk);
     /* Perform the transaction */
-    gpio_clear(dev->cs);
-
-    if (spi_transfer_regs(dev->spi, command, (char *)buf, NULL, len) < len) {
-        status = -1;
-    }
-
-    gpio_set(dev->cs);
+    spi_transfer_regs(dev->spi, dev->cs, command, buf, NULL, (size_t)len);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
     return status;
 }
 
-int adt7310_init(adt7310_t *dev, spi_t spi, gpio_t cs)
+int adt7310_init(adt7310_t *dev, spi_t spi, spi_clk_t clk, gpio_t cs)
 {
     int status;
     uint8_t reg = 0;
     /* write device descriptor */
     dev->spi = spi;
+    dev->clk = clk;
     dev->cs = cs;
     dev->initialized = false;
     dev->high_res = false;
 
     /* CS */
-    gpio_init(dev->cs, GPIO_OUT);
-    gpio_set(dev->cs);
+    spi_init_cs(dev->spi, dev->cs);
 
 #if ENABLE_DEBUG
     for (int i = 0; i < 8; ++i) {
diff --git a/drivers/at86rf2xx/at86rf2xx.c b/drivers/at86rf2xx/at86rf2xx.c
index 8f28b4f712e3e5a351a0827ca2bd6f8d3622b6d5..ebeab759d8a5afae5f79f68e67eb3530f4a097f0 100644
--- a/drivers/at86rf2xx/at86rf2xx.c
+++ b/drivers/at86rf2xx/at86rf2xx.c
@@ -46,8 +46,6 @@ void at86rf2xx_setup(at86rf2xx_t *dev, const at86rf2xx_params_t *params)
     dev->idle_state = AT86RF2XX_STATE_TRX_OFF;
     dev->state = AT86RF2XX_STATE_SLEEP;
     dev->pending_tx = 0;
-    /* initialise SPI */
-    spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, params->spi_speed);
 }
 
 void at86rf2xx_reset(at86rf2xx_t *dev)
diff --git a/drivers/at86rf2xx/at86rf2xx_internal.c b/drivers/at86rf2xx/at86rf2xx_internal.c
index 2c5a436aa58e6d91cb4a334aa372353219a6ed37..0265ef6f54bfa221ccd75b00cf09375af2d9e224 100644
--- a/drivers/at86rf2xx/at86rf2xx_internal.c
+++ b/drivers/at86rf2xx/at86rf2xx_internal.c
@@ -28,32 +28,35 @@
 #include "at86rf2xx_internal.h"
 #include "at86rf2xx_registers.h"
 
+#define SPIDEV          (dev->params.spi)
+#define CSPIN           (dev->params.cs_pin)
+
+static inline void getbus(const at86rf2xx_t *dev)
+{
+    spi_acquire(SPIDEV, CSPIN, SPI_MODE_0, dev->params.spi_clk);
+}
+
 void at86rf2xx_reg_write(const at86rf2xx_t *dev,
                          const uint8_t addr,
                          const uint8_t value)
 {
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.cs_pin);
-    spi_transfer_reg(dev->params.spi,
-                     AT86RF2XX_ACCESS_REG | AT86RF2XX_ACCESS_WRITE | addr,
-                     value, 0);
-    gpio_set(dev->params.cs_pin);
-    spi_release(dev->params.spi);
+    uint8_t reg = (AT86RF2XX_ACCESS_REG | AT86RF2XX_ACCESS_WRITE | addr);
+
+    getbus(dev);
+    spi_transfer_reg(SPIDEV, CSPIN, reg, value);
+    spi_release(SPIDEV);
 }
 
 uint8_t at86rf2xx_reg_read(const at86rf2xx_t *dev, const uint8_t addr)
 {
-    char value;
+    uint8_t reg = (AT86RF2XX_ACCESS_REG | AT86RF2XX_ACCESS_READ | addr);
+    uint8_t value;
 
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.cs_pin);
-    spi_transfer_reg(dev->params.spi,
-                     AT86RF2XX_ACCESS_REG | AT86RF2XX_ACCESS_READ | addr,
-                     0, &value);
-    gpio_set(dev->params.cs_pin);
-    spi_release(dev->params.spi);
+    getbus(dev);
+    value = spi_transfer_reg(SPIDEV, CSPIN, reg, 0);
+    spi_release(SPIDEV);
 
-    return (uint8_t)value;
+    return value;
 }
 
 void at86rf2xx_sram_read(const at86rf2xx_t *dev,
@@ -61,14 +64,13 @@ void at86rf2xx_sram_read(const at86rf2xx_t *dev,
                          uint8_t *data,
                          const size_t len)
 {
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.cs_pin);
-    spi_transfer_reg(dev->params.spi,
-                     AT86RF2XX_ACCESS_SRAM | AT86RF2XX_ACCESS_READ,
-                     (char)offset, NULL);
-    spi_transfer_bytes(dev->params.spi, NULL, (char *)data, len);
-    gpio_set(dev->params.cs_pin);
-    spi_release(dev->params.spi);
+    uint8_t reg = (AT86RF2XX_ACCESS_SRAM | AT86RF2XX_ACCESS_READ);
+
+    getbus(dev);
+    spi_transfer_byte(SPIDEV, CSPIN, true, reg);
+    spi_transfer_byte(SPIDEV, CSPIN, true, offset);
+    spi_transfer_bytes(SPIDEV, CSPIN, false, NULL, data, len);
+    spi_release(SPIDEV);
 }
 
 void at86rf2xx_sram_write(const at86rf2xx_t *dev,
@@ -76,36 +78,35 @@ void at86rf2xx_sram_write(const at86rf2xx_t *dev,
                           const uint8_t *data,
                           const size_t len)
 {
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.cs_pin);
-    spi_transfer_reg(dev->params.spi,
-                     AT86RF2XX_ACCESS_SRAM | AT86RF2XX_ACCESS_WRITE,
-                     (char)offset, NULL);
-    spi_transfer_bytes(dev->params.spi, (char *)data, NULL, len);
-    gpio_set(dev->params.cs_pin);
-    spi_release(dev->params.spi);
+    uint8_t reg = (AT86RF2XX_ACCESS_SRAM | AT86RF2XX_ACCESS_WRITE);
+
+    getbus(dev);
+    spi_transfer_byte(SPIDEV, CSPIN, true, reg);
+    spi_transfer_byte(SPIDEV, CSPIN, true, offset);
+    spi_transfer_bytes(SPIDEV, CSPIN, false, data, NULL, len);
+    spi_release(SPIDEV);
 }
 
 void at86rf2xx_fb_start(const at86rf2xx_t *dev)
 {
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.cs_pin);
-    spi_transfer_byte(dev->params.spi,
-                      AT86RF2XX_ACCESS_FB | AT86RF2XX_ACCESS_READ,
-                      NULL);
+    uint8_t reg = AT86RF2XX_ACCESS_FB | AT86RF2XX_ACCESS_READ;
+
+    getbus(dev);
+    spi_transfer_byte(SPIDEV, CSPIN, true, reg);
 }
 
 void at86rf2xx_fb_read(const at86rf2xx_t *dev,
                        uint8_t *data,
                        const size_t len)
 {
-    spi_transfer_bytes(dev->params.spi, NULL, (char *)data, len);
+    spi_transfer_bytes(SPIDEV, CSPIN, true, NULL, data, len);
 }
 
 void at86rf2xx_fb_stop(const at86rf2xx_t *dev)
 {
-    gpio_set(dev->params.cs_pin);
-    spi_release(dev->params.spi);
+    /* transfer one byte (which we ignore) to release the chip select */
+    spi_transfer_byte(SPIDEV, CSPIN, false, 1);
+    spi_release(SPIDEV);
 }
 
 uint8_t at86rf2xx_get_status(const at86rf2xx_t *dev)
diff --git a/drivers/at86rf2xx/at86rf2xx_netdev.c b/drivers/at86rf2xx/at86rf2xx_netdev.c
index 56c6d9376c7c94a55298ff1c3129a22db20bc807..4476ea4891e34eb19db772b37f6d5b4fcbae0f0f 100644
--- a/drivers/at86rf2xx/at86rf2xx_netdev.c
+++ b/drivers/at86rf2xx/at86rf2xx_netdev.c
@@ -70,8 +70,7 @@ static int _init(netdev2_t *netdev)
     at86rf2xx_t *dev = (at86rf2xx_t *)netdev;
 
     /* initialise GPIOs */
-    gpio_init(dev->params.cs_pin, GPIO_OUT);
-    gpio_set(dev->params.cs_pin);
+    spi_init_cs(dev->params.spi, dev->params.cs_pin);
     gpio_init(dev->params.sleep_pin, GPIO_OUT);
     gpio_clear(dev->params.sleep_pin);
     gpio_init(dev->params.reset_pin, GPIO_OUT);
diff --git a/drivers/at86rf2xx/include/at86rf2xx_params.h b/drivers/at86rf2xx/include/at86rf2xx_params.h
index 8dd9a3156825eec3fcd35957b6eb869c0974a976..fad6a8e3b5e9f25f60d86b67f4e9090dca3b2d78 100644
--- a/drivers/at86rf2xx/include/at86rf2xx_params.h
+++ b/drivers/at86rf2xx/include/at86rf2xx_params.h
@@ -32,10 +32,10 @@ extern "C" {
  * @{
  */
 #ifndef AT86RF2XX_PARAM_SPI
-#define AT86RF2XX_PARAM_SPI         (SPI_0)
+#define AT86RF2XX_PARAM_SPI         (SPI_DEV(0))
 #endif
-#ifndef AT86RF2XX_PARAM_SPI_SPEED
-#define AT86RF2XX_PARAM_SPI_SPEED   (SPI_SPEED_5MHZ)
+#ifndef AT86RF2XX_PARAM_SPI_CLK
+#define AT86RF2XX_PARAM_SPI_CLK     (SPI_CLK_5MHZ)
 #endif
 #ifndef AT86RF2XX_PARAM_CS
 #define AT86RF2XX_PARAM_CS          (GPIO_PIN(0, 0))
@@ -51,7 +51,7 @@ extern "C" {
 #endif
 
 #define AT86RF2XX_PARAMS_DEFAULT    {.spi = AT86RF2XX_PARAM_SPI, \
-                                     .spi_speed = AT86RF2XX_PARAM_SPI_SPEED, \
+                                     .spi_clk = AT86RF2XX_PARAM_SPI_CLK, \
                                      .cs_pin = AT86RF2XX_PARAM_CS, \
                                      .int_pin = AT86RF2XX_PARAM_INT, \
                                      .sleep_pin = AT86RF2XX_PARAM_SLEEP, \
diff --git a/drivers/cc110x/cc110x-spi.c b/drivers/cc110x/cc110x-spi.c
index da1ee16aa8143737e69e0af1fb376cacf3f42a4f..5a0c4efb10fd808aa55372aa3fccfd3f49aeb2ea 100644
--- a/drivers/cc110x/cc110x-spi.c
+++ b/drivers/cc110x/cc110x-spi.c
@@ -35,10 +35,18 @@
 #include "xtimer.h"
 #include "irq.h"
 
+#define SPI_CLK         SPI_CLK_5MHZ
+#define SPI_MODE        SPI_MODE_0
+
 /**********************************************************************
  *                      CC110x spi access
  **********************************************************************/
 
+static inline void lock(cc110x_t *dev)
+{
+    spi_acquire(dev->params.spi, dev->params.cs, SPI_MODE, SPI_CLK);
+}
+
 void cc110x_cs(cc110x_t *dev)
 {
     volatile int retry_count = 0;
@@ -68,17 +76,18 @@ void cc110x_cs(cc110x_t *dev)
     }
     /* Switch MISO/GDO1 to spi mode */
 #ifndef GPIO_READS_SPI_PINS
-    spi_conf_pins(dev->params.spi);
+    spi_init_pins(dev->params.spi);
 #endif
 }
 
 void cc110x_writeburst_reg(cc110x_t *dev, uint8_t addr, const char *src, uint8_t count)
 {
     unsigned int cpsr;
-    spi_acquire(dev->params.spi);
+    lock(dev);
     cpsr = irq_disable();
     cc110x_cs(dev);
-    spi_transfer_regs(dev->params.spi, addr | CC110X_WRITE_BURST, (char *)src, 0, count);
+    spi_transfer_regs(dev->params.spi, SPI_CS_UNDEF,
+                      (addr | CC110X_WRITE_BURST), src, NULL, count);
     gpio_set(dev->params.cs);
     irq_restore(cpsr);
     spi_release(dev->params.spi);
@@ -88,12 +97,14 @@ void cc110x_readburst_reg(cc110x_t *dev, uint8_t addr, char *buffer, uint8_t cou
 {
     int i = 0;
     unsigned int cpsr;
-    spi_acquire(dev->params.spi);
+    lock(dev);
     cpsr = irq_disable();
     cc110x_cs(dev);
-    spi_transfer_byte(dev->params.spi, addr | CC110X_READ_BURST, 0);
+    spi_transfer_byte(dev->params.spi, SPI_CS_UNDEF, false,
+                      (addr | CC110X_READ_BURST));
     while (i < count) {
-        spi_transfer_byte(dev->params.spi, CC110X_NOBYTE, &buffer[i]);
+        buffer[i] = (char)spi_transfer_byte(dev->params.spi, SPI_CS_UNDEF,
+                                            false, CC110X_NOBYTE);
         i++;
     }
     gpio_set(dev->params.cs);
@@ -104,10 +115,10 @@ void cc110x_readburst_reg(cc110x_t *dev, uint8_t addr, char *buffer, uint8_t cou
 void cc110x_write_reg(cc110x_t *dev, uint8_t addr, uint8_t value)
 {
     unsigned int cpsr;
-    spi_acquire(dev->params.spi);
+    lock(dev);
     cpsr = irq_disable();
     cc110x_cs(dev);
-    spi_transfer_reg(dev->params.spi, addr, value, 0);
+    spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF, addr, value);
     gpio_set(dev->params.cs);
     irq_restore(cpsr);
     spi_release(dev->params.spi);
@@ -115,26 +126,28 @@ void cc110x_write_reg(cc110x_t *dev, uint8_t addr, uint8_t value)
 
 uint8_t cc110x_read_reg(cc110x_t *dev, uint8_t addr)
 {
-    char result;
+    uint8_t result;
     unsigned int cpsr;
-    spi_acquire(dev->params.spi);
+    lock(dev);
     cpsr = irq_disable();
     cc110x_cs(dev);
-    spi_transfer_reg(dev->params.spi, addr | CC110X_READ_SINGLE, CC110X_NOBYTE, &result);
+    result = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF,
+                              (addr | CC110X_READ_SINGLE), CC110X_NOBYTE);
     gpio_set(dev->params.cs);
     irq_restore(cpsr);
     spi_release(dev->params.spi);
-    return (uint8_t) result;
+    return result;
 }
 
 uint8_t cc110x_read_status(cc110x_t *dev, uint8_t addr)
 {
-    char result;
+    uint8_t result;
     unsigned int cpsr;
-    spi_acquire(dev->params.spi);
+    lock(dev);
     cpsr = irq_disable();
     cc110x_cs(dev);
-    spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result);
+    result = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF,
+                              (addr | CC110X_READ_BURST), CC110X_NOBYTE);
     gpio_set(dev->params.cs);
     irq_restore(cpsr);
     spi_release(dev->params.spi);
@@ -143,19 +156,21 @@ uint8_t cc110x_read_status(cc110x_t *dev, uint8_t addr)
 
 uint8_t cc110x_get_reg_robust(cc110x_t *dev, uint8_t addr)
 {
-    char result, result2;
+    uint8_t res1, res2;
     unsigned int cpsr;
-    spi_acquire(dev->params.spi);
+    lock(dev);
     cpsr = irq_disable();
     cc110x_cs(dev);
     do {
-        spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result);
-        spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result2);
-    } while (result != result2);
+        res1 = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF,
+                                (addr | CC110X_READ_BURST), CC110X_NOBYTE);
+        res2 = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF,
+                                (addr | CC110X_READ_BURST), CC110X_NOBYTE);
+    } while (res1 != res2);
     gpio_set(dev->params.cs);
     irq_restore(cpsr);
     spi_release(dev->params.spi);
-    return (uint8_t) result;
+    return res1;
 }
 
 uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c)
@@ -166,14 +181,14 @@ uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c)
     }
 #endif
 
-    char result;
+    uint8_t result;
     unsigned int cpsr;
-    spi_acquire(dev->params.spi);
+    lock(dev);
     cpsr = irq_disable();
     cc110x_cs(dev);
-    spi_transfer_byte(dev->params.spi, c, &result);
+    result = spi_transfer_byte(dev->params.spi, SPI_CS_UNDEF, false,  c);
     gpio_set(dev->params.cs);
     irq_restore(cpsr);
     spi_release(dev->params.spi);
-    return (uint8_t) result;
+    return result;
 }
diff --git a/drivers/cc110x/cc110x.c b/drivers/cc110x/cc110x.c
index 778a1035979a96381ec485ce2f0583f85ec731f2..0286ed5b04e524f00813b232b89e626149c7f33c 100644
--- a/drivers/cc110x/cc110x.c
+++ b/drivers/cc110x/cc110x.c
@@ -55,17 +55,11 @@ int cc110x_setup(cc110x_t *dev, const cc110x_params_t *params)
     dev->params = *params;
 
     /* Configure chip-select */
-    gpio_init(dev->params.cs, GPIO_OUT);
-    gpio_set(dev->params.cs);
+    spi_init_cs(dev->params.spi, dev->params.cs);
 
     /* Configure GDO1 */
     gpio_init(dev->params.gdo1, GPIO_IN);
 
-    /* Configure SPI */
-    spi_acquire(dev->params.spi);
-    spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ);
-    spi_release(dev->params.spi);
-
 #ifndef CC110X_DONT_RESET
     /* reset device*/
     _power_up_reset(dev);
diff --git a/drivers/cc2420/cc2420.c b/drivers/cc2420/cc2420.c
index abe8cde5275fb89b2eb444878bc6c33d04e5b883..24d8ef2a8b11c9cbda5129e83834f5603a822715 100644
--- a/drivers/cc2420/cc2420.c
+++ b/drivers/cc2420/cc2420.c
@@ -42,7 +42,6 @@ void cc2420_setup(cc2420_t * dev, const cc2420_params_t *params)
     dev->state = CC2420_STATE_IDLE;
     /* reset device descriptor fields */
     dev->options = 0;
-    spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, dev->params.spi_clk);
 }
 
 int cc2420_init(cc2420_t *dev)
diff --git a/drivers/cc2420/cc2420_internal.c b/drivers/cc2420/cc2420_internal.c
index 01ab024f2967560bd2cb1afe86b6a8f0c9f1a965..dea3f04818a0efe74732978b6f8683c5ce4dd46a 100644
--- a/drivers/cc2420/cc2420_internal.c
+++ b/drivers/cc2420/cc2420_internal.c
@@ -27,15 +27,19 @@
 #include "cc2420_internal.h"
 #include "cc2420_registers.h"
 
+#define SPI_BUS             (dev->params.spi)
+#define SPI_CS              (dev->params.pin_cs)
+#define SPI_MODE            (SPI_MODE_0)
+#define SPI_CLK             (dev->params.spi_clk)
+
+
 uint8_t cc2420_strobe(const cc2420_t *dev, const uint8_t command)
 {
-    char res;
+    uint8_t res;
 
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.pin_cs);
-    spi_transfer_byte(dev->params.spi, (char)command, (char *)&res);
-    gpio_set(dev->params.pin_cs);
-    spi_release(dev->params.spi);
+    spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK);
+    res = spi_transfer_byte(SPI_BUS, SPI_CS, false, command);
+    spi_release(SPI_BUS);
 
     return res;
 }
@@ -46,24 +50,18 @@ void cc2420_reg_write(const cc2420_t *dev,
 {
     uint16_t tmp = byteorder_htons(value).u16;
 
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.pin_cs);
-    spi_transfer_regs(dev->params.spi, CC2420_REG_WRITE | addr,
-                      (char *)&tmp, NULL, 2);
-    gpio_set(dev->params.pin_cs);
-    spi_release(dev->params.spi);
+    spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK);
+    spi_transfer_regs(SPI_BUS, SPI_CS, (CC2420_REG_WRITE | addr), &tmp, NULL, 2);
+    spi_release(SPI_BUS);
 }
 
 uint16_t cc2420_reg_read(const cc2420_t *dev, const uint8_t addr)
 {
     network_uint16_t tmp;
 
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.pin_cs);
-    spi_transfer_regs(dev->params.spi, CC2420_REG_READ | addr,
-                      NULL, (char *)&tmp, 2);
-    gpio_set(dev->params.pin_cs);
-    spi_release(dev->params.spi);
+    spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK);
+    spi_transfer_regs(SPI_BUS, SPI_CS, (CC2420_REG_READ | addr),NULL, &tmp, 2);
+    spi_release(SPI_BUS);
 
     return byteorder_ntohs(tmp);
 }
@@ -71,49 +69,40 @@ uint16_t cc2420_reg_read(const cc2420_t *dev, const uint8_t addr)
 void cc2420_ram_read(const cc2420_t *dev, const uint16_t addr,
                      uint8_t *data, const size_t len)
 {
-    char tmp[] = { (CC2420_RAM      | (addr & 0x7f)),
-                   (CC2420_RAM_READ | ((addr >> 1) & 0xc0)) };
+    uint8_t tmp[] = { (CC2420_RAM      | (addr & 0x7f)),
+                      (CC2420_RAM_READ | ((addr >> 1) & 0xc0)) };
 
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.pin_cs);
-    spi_transfer_bytes(dev->params.spi, tmp, NULL, 2);
-    spi_transfer_bytes(dev->params.spi, NULL, (char*)data, len);
-    gpio_set(dev->params.pin_cs);
-    spi_release(dev->params.spi);
+    spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK);
+    spi_transfer_bytes(SPI_BUS, SPI_CS, true, tmp, NULL, 2);
+    spi_transfer_bytes(SPI_BUS, SPI_CS, false, NULL, data, len);
+    spi_release(SPI_BUS);
 }
 
 void cc2420_ram_write(const cc2420_t *dev, const uint16_t addr,
                       const uint8_t *data, const size_t len)
 {
-    char tmp[] = { (CC2420_RAM       | (addr & 0x7f)),
-                   (CC2420_RAM_WRITE | ((addr >> 1) & 0xc0)) };
+    uint8_t tmp[] = { (CC2420_RAM       | (addr & 0x7f)),
+                      (CC2420_RAM_WRITE | ((addr >> 1) & 0xc0)) };
 
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.pin_cs);
-    spi_transfer_bytes(dev->params.spi, tmp, NULL, 2);
-    spi_transfer_bytes(dev->params.spi, (char*)data, NULL, len);
-    gpio_set(dev->params.pin_cs);
-    spi_release(dev->params.spi);
+    spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK);
+    spi_transfer_bytes(SPI_BUS, SPI_CS, true, tmp, NULL, 2);
+    spi_transfer_bytes(SPI_BUS, SPI_CS, false, data, NULL, len);
+    spi_release(SPI_BUS);
 }
 
 void cc2420_fifo_read(const cc2420_t *dev, uint8_t *data, const size_t len)
 {
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.pin_cs);
-    spi_transfer_regs(dev->params.spi, CC2420_FIFO_READ,
-                      NULL, (char *)data, len);
-    gpio_set(dev->params.pin_cs);
-    spi_release(dev->params.spi);
+    spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK);
+    spi_transfer_regs(SPI_BUS, SPI_CS, CC2420_FIFO_READ, NULL, data, len);
+    spi_release(SPI_BUS);
 }
 
 void cc2420_fifo_write(const cc2420_t *dev, uint8_t *data, const size_t len)
 {
-    spi_acquire(dev->params.spi);
-    gpio_clear(dev->params.pin_cs);
-    spi_transfer_regs(dev->params.spi, CC2420_FIFO_WRITE,
-                      (char *)data, NULL, len);
+    spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK);
+    spi_transfer_regs(SPI_BUS, SPI_CS, CC2420_FIFO_WRITE, data, NULL, len);
     gpio_set(dev->params.pin_cs);
-    spi_release(dev->params.spi);
+    spi_release(SPI_BUS);
 }
 
 uint8_t cc2420_status(cc2420_t *dev)
diff --git a/drivers/cc2420/cc2420_netdev.c b/drivers/cc2420/cc2420_netdev.c
index cfdd054b74fcd3e7741c346d3aa97866286714b9..c3bf61e9187c56d7b82f3b3aec72f6c0ddde731c 100644
--- a/drivers/cc2420/cc2420_netdev.c
+++ b/drivers/cc2420/cc2420_netdev.c
@@ -116,8 +116,7 @@ static int _init(netdev2_t *netdev)
     gpio_init_int(dev->params.pin_fifop, GPIO_IN, GPIO_RISING, _irq_handler, dev);
 
     /* initialize the chip select line and the SPI bus */
-    gpio_init(dev->params.pin_cs, GPIO_OUT);
-    gpio_set(dev->params.pin_cs);
+    spi_init_cs(dev->params.spi, dev->params.pin_cs);
 
     /* power on and toggle reset */
     gpio_set(dev->params.pin_vrefen);
diff --git a/drivers/cc2420/include/cc2420_params.h b/drivers/cc2420/include/cc2420_params.h
index 77d901aa5aefa06bd5554b30737d7c439a05b1dc..9687c0cdd8f12f9b4956fe417201405baefefc9d 100644
--- a/drivers/cc2420/include/cc2420_params.h
+++ b/drivers/cc2420/include/cc2420_params.h
@@ -30,10 +30,10 @@ extern "C" {
  * @{
  */
 #ifndef CC2420_PARAM_SPI
-#define CC2420_PARAM_SPI        (SPI_0)
+#define CC2420_PARAM_SPI        (SPI_DEV(0))
 #endif
 #ifndef CC2420_PARAM_SPI_CLK
-#define CC2420_PARAM_SPI_CLK    (SPI_SPEED_5MHZ)
+#define CC2420_PARAM_SPI_CLK    (SPI_CLK_5MHZ)
 #endif
 #ifndef CC2420_PARAM_CS
 #define CC2420_PARAM_CS         (GPIO_PIN(0, 0))
diff --git a/drivers/enc28j60/enc28j60.c b/drivers/enc28j60/enc28j60.c
index 848d8ad3cdc000f96e46bafc8e46e28a88aef3f8..ee8d0ca8a0c63111d0156bd7e528c044af94b676 100644
--- a/drivers/enc28j60/enc28j60.c
+++ b/drivers/enc28j60/enc28j60.c
@@ -51,7 +51,7 @@
  * The SPI speed is set to a fixed value, as it must be > 8MHz (see the devices
  * errata sheet).
  */
-#define SPI_SPEED                   SPI_SPEED_10MHZ
+#define SPI_CLK                     SPI_CLK_10MHZ
 
 /**
  * @brief   The devices build-in buffer size
@@ -82,61 +82,79 @@ static void switch_bank(enc28j60_t *dev, int8_t bank)
         return;
     }
     /* clear old value */
-    gpio_clear(dev->cs_pin);
-    spi_transfer_reg(dev->spi, CMD_BFC | REG_ECON1, 0x03, 0);
-    gpio_set(dev->cs_pin);
+    spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_BFC | REG_ECON1), 0x03);
     /* set new value */
-    gpio_clear(dev->cs_pin);
-    spi_transfer_reg(dev->spi, CMD_BFS | REG_ECON1, bank, 0);
-    gpio_set(dev->cs_pin);
+    spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_BFS | REG_ECON1), bank);
     /* remember active bank */
     dev->bank = bank;
 }
 
 static uint8_t cmd_rcr(enc28j60_t *dev, uint8_t reg, int8_t bank)
 {
-    char res;
+    uint8_t res;
+
+    /* start transaction */
+    spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK);
 
     switch_bank(dev, bank);
-    gpio_clear(dev->cs_pin);
-    spi_transfer_reg(dev->spi, CMD_RCR | reg, 0, &res);
-    gpio_set(dev->cs_pin);
-    return (uint8_t)res;
+    res = spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_RCR | reg), 0);
+
+    /* finish SPI transaction */
+    spi_release(dev->spi);
+
+    return res;
 }
 
 static uint8_t cmd_rcr_miimac(enc28j60_t *dev, uint8_t reg, int8_t bank)
 {
     char res[2];
 
+    /* start transaction */
+    spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK);
+
     switch_bank(dev, bank);
-    gpio_clear(dev->cs_pin);
-    spi_transfer_regs(dev->spi, CMD_RCR | reg, NULL, res, 2);
-    gpio_set(dev->cs_pin);
+    spi_transfer_regs(dev->spi, dev->cs_pin, (CMD_RCR | reg), NULL, res, 2);
+
+    /* finish SPI transaction */
+    spi_release(dev->spi);
+
     return (uint8_t)res[1];
 }
 
 static void cmd_wcr(enc28j60_t *dev, uint8_t reg, int8_t bank, uint8_t value)
 {
+    /* start transaction */
+    spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK);
+
     switch_bank(dev, bank);
-    gpio_clear(dev->cs_pin);
-    spi_transfer_reg(dev->spi, CMD_WCR | reg, (char)value, 0);
-    gpio_set(dev->cs_pin);
+    spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_WCR | reg), value);
+
+    /* finish SPI transaction */
+    spi_release(dev->spi);
 }
 
 static void cmd_bfs(enc28j60_t *dev, uint8_t reg, int8_t bank, uint8_t mask)
 {
+    /* start transaction */
+    spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK);
+
     switch_bank(dev, bank);
-    gpio_clear(dev->cs_pin);
-    spi_transfer_reg(dev->spi, CMD_BFS | reg, mask, 0);
-    gpio_set(dev->cs_pin);
+    spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_BFS | reg), mask);
+
+    /* finish SPI transaction */
+    spi_release(dev->spi);
 }
 
 static void cmd_bfc(enc28j60_t *dev, uint8_t reg, int8_t bank, uint8_t mask)
 {
+    /* start transaction */
+    spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK);
+
     switch_bank(dev, bank);
-    gpio_clear(dev->cs_pin);
-    spi_transfer_reg(dev->spi, CMD_BFC | reg, mask, 0);
-    gpio_set(dev->cs_pin);
+    spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_BFC | reg), mask);
+
+    /* finish SPI transaction */
+    spi_release(dev->spi);
 }
 
 static uint16_t cmd_r_addr(enc28j60_t *dev, uint8_t addr)
@@ -178,16 +196,22 @@ static void cmd_w_phy(enc28j60_t *dev, uint8_t reg, uint16_t val)
 
 static void cmd_rbm(enc28j60_t *dev, uint8_t *data, size_t len)
 {
-    gpio_clear(dev->cs_pin);
-    spi_transfer_regs(dev->spi, CMD_RBM, NULL, (char *)data, len);
-    gpio_set(dev->cs_pin);
+    /* start transaction */
+    spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK);
+    /* transfer data */
+    spi_transfer_regs(dev->spi, dev->cs_pin, CMD_RBM, NULL, data, len);
+    /* finish SPI transaction */
+    spi_release(dev->spi);
 }
 
 static void cmd_wbm(enc28j60_t *dev, uint8_t *data, size_t len)
 {
-    gpio_clear(dev->cs_pin);
-    spi_transfer_regs(dev->spi, CMD_WBM, (char *)data, NULL, len);
-    gpio_set(dev->cs_pin);
+    /* start transaction */
+    spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK);
+    /* transfer data */
+    spi_transfer_regs(dev->spi, dev->cs_pin, CMD_WBM, data, NULL, len);
+    /* finish SPI transaction */
+    spi_release(dev->spi);
 }
 
 static void mac_get(enc28j60_t *dev, uint8_t *mac)
@@ -296,14 +320,11 @@ static int nd_init(netdev2_t *netdev)
     /* setup the low-level interfaces */
     gpio_init(dev->reset_pin, GPIO_OUT);
     gpio_clear(dev->reset_pin);     /* this puts the device into reset state */
-    gpio_init(dev->cs_pin, GPIO_OUT);
-    gpio_set(dev->cs_pin);
-    gpio_init_int(dev->int_pin, GPIO_IN, GPIO_FALLING, on_int, (void *)dev);
-    res = spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, SPI_SPEED);
-    if (res < 0) {
-        DEBUG("[enc28j60] init: error initializing SPI bus [%i]\n", res);
+    if (spi_init_cs(dev->spi, dev->cs_pin) != SPI_OK) {
+        DEBUG("[enc28j60] init: error initializing the CS pin [%i]\n", res);
         return -1;
     }
+    gpio_init_int(dev->int_pin, GPIO_IN, GPIO_FALLING, on_int, (void *)dev);
 
     /* wait at least 1ms and then release device from reset state */
     xtimer_usleep(DELAY_RESET);
diff --git a/drivers/enc28j60/include/enc28j60_params.h b/drivers/enc28j60/include/enc28j60_params.h
index 6546ae448111966be5754d58d2154e94df9c6e08..5266440217c5e2e1e963fb0e817b609d11b6ea22 100644
--- a/drivers/enc28j60/include/enc28j60_params.h
+++ b/drivers/enc28j60/include/enc28j60_params.h
@@ -30,7 +30,7 @@ extern "C" {
  * @{
  */
 #ifndef ENC28J60_PARAM_SPI
-#define ENC28J60_PARAM_SPI      (SPI_0)
+#define ENC28J60_PARAM_SPI      (SPI_DEV(0))
 #endif
 #ifndef ENC28J60_PARAM_CS
 #define ENC28J60_PARAM_CS       (GPIO_PIN(0, 0))
diff --git a/drivers/encx24j600/encx24j600.c b/drivers/encx24j600/encx24j600.c
index 96542bdeb2c6f28a2394d3e01aa6ee3695698253..d46fa63d2b74ffc7c4cd90fdccd8de1012e2b2c7 100644
--- a/drivers/encx24j600/encx24j600.c
+++ b/drivers/encx24j600/encx24j600.c
@@ -37,18 +37,19 @@
 #define ENABLE_DEBUG (0)
 #include "debug.h"
 
-#define ENCX24J600_SPI_SPEED SPI_SPEED_1MHZ
+#define SPI_CLK                 SPI_CLK_1MHZ
+#define SPI_MODE                SPI_MODE_0
 
-#define ENCX24J600_INIT_DELAY 100000U
+#define ENCX24J600_INIT_DELAY   (100000U)
 
-#define ENC_BUFFER_START 0x0000
-#define ENC_BUFFER_SIZE  0x6000
-#define ENC_BUFFER_END   0x5FFF
-#define RX_BUFFER_START (0x5340) /* Default value */
-#define RX_BUFFER_END   (ENC_BUFFER_END)
-#define TX_BUFFER_LEN   (0x2000)
-#define TX_BUFFER_END   (RX_BUFFER_START)
-#define TX_BUFFER_START (TX_BUFFER_END - TX_BUFFER_LEN)
+#define ENC_BUFFER_START        (0x0000)
+#define ENC_BUFFER_SIZE         (0x6000)
+#define ENC_BUFFER_END          (0x5FFF)
+#define RX_BUFFER_START         (0x5340) /* Default value */
+#define RX_BUFFER_END           (ENC_BUFFER_END)
+#define TX_BUFFER_LEN           (0x2000)
+#define TX_BUFFER_END           (RX_BUFFER_START)
+#define TX_BUFFER_START         (TX_BUFFER_END - TX_BUFFER_LEN)
 
 static void cmd(encx24j600_t *dev, char cmd);
 static void reg_set(encx24j600_t *dev, uint8_t reg, uint16_t value);
@@ -75,11 +76,11 @@ const static netdev2_driver_t netdev2_driver_encx24j600 = {
 };
 
 static inline void lock(encx24j600_t *dev) {
-    mutex_lock(&dev->mutex);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
 }
 
 static inline void unlock(encx24j600_t *dev) {
-    mutex_unlock(&dev->mutex);
+    spi_release(dev->spi);
 }
 
 void encx24j600_setup(encx24j600_t *dev, const encx24j600_params_t *params)
@@ -89,8 +90,6 @@ void encx24j600_setup(encx24j600_t *dev, const encx24j600_params_t *params)
     dev->cs = params->cs_pin;
     dev->int_pin = params->int_pin;
     dev->rx_next_ptr = RX_BUFFER_START;
-
-    mutex_init(&dev->mutex);
 }
 
 static void encx24j600_isr(void *arg)
@@ -147,11 +146,7 @@ static void _isr(netdev2_t *netdev)
 
 static inline void enc_spi_transfer(encx24j600_t *dev, char *out, char *in, int len)
 {
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    spi_transfer_bytes(dev->spi, out, in, len);
-    gpio_set(dev->cs);
-    spi_release(dev->spi);
+    spi_transfer_bytes(dev->spi, dev->cs, false, out, in, len);
 }
 
 static inline uint16_t reg_get(encx24j600_t *dev, uint8_t reg)
@@ -170,20 +165,12 @@ static void phy_reg_set(encx24j600_t *dev, uint8_t reg, uint16_t value) {
 }
 
 static void cmd(encx24j600_t *dev, char cmd) {
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    spi_transfer_byte(dev->spi, cmd, NULL);
-    gpio_set(dev->cs);
-    spi_release(dev->spi);
+    spi_transfer_byte(dev->spi, dev->cs, false, (uint8_t)cmd);
 }
 
 static void cmdn(encx24j600_t *dev, uint8_t cmd, char *out, char *in, int len) {
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    spi_transfer_byte(dev->spi, cmd, NULL);
-    spi_transfer_bytes(dev->spi, out, in, len);
-    gpio_set(dev->cs);
-    spi_release(dev->spi);
+    spi_transfer_byte(dev->spi, dev->cs, true, cmd);
+    spi_transfer_bytes(dev->spi, dev->cs, false, out, in, len);
 }
 
 static void reg_set(encx24j600_t *dev, uint8_t reg, uint16_t value)
@@ -249,13 +236,10 @@ static int _init(netdev2_t *encdev)
     DEBUG("encx24j600: starting initialization...\n");
 
     /* setup IO */
-    gpio_init(dev->cs, GPIO_OUT);
-    gpio_set(dev->cs);
-    gpio_init_int(dev->int_pin, GPIO_IN_PU, GPIO_FALLING, encx24j600_isr, (void*)dev);
-
-    if (spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, ENCX24J600_SPI_SPEED) < 0) {
+    if (spi_init_cs(dev->spi, dev->cs) != SPI_OK) {
         return -1;
     }
+    gpio_init_int(dev->int_pin, GPIO_IN_PU, GPIO_FALLING, encx24j600_isr, (void*)dev);
 
     lock(dev);
 
diff --git a/drivers/include/adt7310.h b/drivers/include/adt7310.h
index 2cf37fb190a0f88bef71810384d0de985ebc0559..4ba673b6fb2fcba211a6dd7facf740798f766a73 100644
--- a/drivers/include/adt7310.h
+++ b/drivers/include/adt7310.h
@@ -65,6 +65,7 @@ extern "C"
  */
 typedef struct {
     spi_t spi;              /**< SPI bus the sensor is connected to */
+    spi_clk_t clk;          /**< SPI bus clock speed */
     gpio_t cs;              /**< CS pin GPIO handle */
     bool initialized;       /**< sensor status, true if sensor is initialized */
     bool high_res;          /**< Sensor resolution, true if configured to 16 bit resolution */
@@ -119,12 +120,13 @@ int adt7310_set_config(adt7310_t *dev, uint8_t config);
  *
  * @param[in]  dev          pointer to sensor device descriptor
  * @param[in]  spi          SPI bus the sensor is connected to
+ * @param[in]  clk          SPI bus speed
  * @param[in]  cs           GPIO pin the chip select signal is connected to
  *
  * @return                  0 on success
  * @return                  <0 on error
  */
-int adt7310_init(adt7310_t *dev, spi_t spi, gpio_t cs);
+int adt7310_init(adt7310_t *dev, spi_t spi, spi_clk_t clk, gpio_t cs);
 
 /**
  * @brief Read raw temperature register value
diff --git a/drivers/include/at86rf2xx.h b/drivers/include/at86rf2xx.h
index 74a9630836679f22416dc66f12c37feaa2239101..a2e49b9e1d816c68473235290f9221777e70bee2 100644
--- a/drivers/include/at86rf2xx.h
+++ b/drivers/include/at86rf2xx.h
@@ -137,8 +137,8 @@ extern "C" {
  */
 typedef struct at86rf2xx_params {
     spi_t spi;              /**< SPI bus the device is connected to */
-    spi_speed_t spi_speed;  /**< SPI speed to use */
-    gpio_t cs_pin;          /**< GPIO pin connected to chip select */
+    spi_clk_t spi_clk;      /**< SPI clock speed to use */
+    spi_cs_t cs_pin;        /**< GPIO pin connected to chip select */
     gpio_t int_pin;         /**< GPIO pin connected to the interrupt pin */
     gpio_t sleep_pin;       /**< GPIO pin connected to the sleep pin */
     gpio_t reset_pin;       /**< GPIO pin connected to the reset pin */
diff --git a/drivers/include/cc2420.h b/drivers/include/cc2420.h
index c10d0cf0a51d1bdfcb80842b188db67a5fd6811f..ab4758054e9975424f72514845db1ad89d23813f 100644
--- a/drivers/include/cc2420.h
+++ b/drivers/include/cc2420.h
@@ -74,7 +74,7 @@ enum {
  */
 typedef struct cc2420_params {
     spi_t spi;              /**< SPI bus the device is connected to */
-    spi_speed_t spi_clk;    /**< SPI speed to use */
+    spi_clk_t spi_clk;      /**< SPI speed to use */
     gpio_t pin_cs;          /**< pin connected to chip select */
     gpio_t pin_fifo;        /**< pin connected to the FIFO interrupt pin */
     gpio_t pin_fifop;       /**< pin connected to the FIFOP interrupt pin */
diff --git a/drivers/include/encx24j600.h b/drivers/include/encx24j600.h
index 683b6c1efc0cb7c104e420d13ff2160e1b241d80..a4ab05c40e77642556ea1c105cbf3a906061ca0b 100644
--- a/drivers/include/encx24j600.h
+++ b/drivers/include/encx24j600.h
@@ -41,7 +41,6 @@ typedef struct {
     gpio_t cs;              /**< SPI chip select pin */
     gpio_t int_pin;         /**< SPI interrupt pin */
     uint16_t rx_next_ptr;   /**< ptr to next packet whithin devices memory */
-    mutex_t mutex;          /**< mutex used to lock device access */
 } encx24j600_t;
 
 /**
diff --git a/drivers/include/kw2xrf.h b/drivers/include/kw2xrf.h
index a90fc43a44fece2b6c81672b51bb689d68443e95..c7682ba1b7c5e530220c202da70dfd3cda49acf3 100644
--- a/drivers/include/kw2xrf.h
+++ b/drivers/include/kw2xrf.h
@@ -130,14 +130,14 @@ typedef struct {
  * @brief   Initialize the given KW2XRF device
  * @param[out] dev          device descriptor
  * @param[in] spi           SPI bus the device is connected to
- * @param[in] spi_speed     SPI speed to use
+ * @param[in] spi_clk       SPI bus clock speed to use
  * @param[in] cs_pin        GPIO pin connected to chip select
  * @param[in] int_pin       GPIO pin connected to the interrupt pin
  *
  * @return                  0 on success
  * @return                  <0 on error
  */
-int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_speed_t spi_speed,
+int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_clk_t spi_clk,
                     gpio_t cs_pin, gpio_t int_pin);
 
 /**
@@ -145,7 +145,7 @@ int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_speed_t spi_speed,
  */
 typedef struct kw2xrf_params {
     spi_t spi;              /**< SPI bus the device is connected to */
-    spi_speed_t spi_speed;  /**< SPI speed to use */
+    spi_clk_t spi_speed;    /**< SPI speed to use */
     gpio_t cs_pin;          /**< GPIO pin connected to chip select */
     gpio_t int_pin;         /**< GPIO pin connected to the interrupt pin */
 } kw2xrf_params_t;
diff --git a/drivers/include/lis3dh.h b/drivers/include/lis3dh.h
index ec4bfb8298c81149dcd5396051670187ea2afada..a0015fdc7d86585698c955e403b0d5c74d1a5cd8 100644
--- a/drivers/include/lis3dh.h
+++ b/drivers/include/lis3dh.h
@@ -677,10 +677,11 @@ typedef enum {
 /** @} */
 
 /**
- * @brief Device descriptor for LIS3DH sensors
+ * @brief Configuration parameters for LIS3DH devices
  */
 typedef struct {
     spi_t spi;              /**< SPI device the sensor is connected to */
+    spi_clk_t clk;          /**< designated clock speed of the SPI bus */
     gpio_t cs;              /**< Chip select pin */
     gpio_t int1;            /**< INT1 pin */
     gpio_t int2;            /**< INT2 (DRDY) pin */
@@ -688,8 +689,12 @@ typedef struct {
     uint8_t odr;            /**< Default sensor ODR setting: LIS3DH_ODR_xxxHz */
 } lis3dh_params_t;
 
+/**
+ * @brief Device descriptor for LIS3DH sensors
+ */
 typedef struct {
     spi_t spi;              /**< SPI device the sensor is connected to */
+    spi_clk_t clk;          /**< clock speed of the SPI bus */
     gpio_t cs;              /**< Chip select pin */
     int16_t scale;          /**< Current scale setting of the sensor */
 } lis3dh_t;
@@ -710,13 +715,15 @@ typedef struct __attribute__((packed))
  *
  * @param[in]  dev          Device descriptor of sensor to initialize
  * @param[in]  spi          SPI bus the accelerometer is connected to
+ * @param[in]  clk          SPI bus speed
  * @param[in]  cs_pin       GPIO connected to the chip select pin of the accelerometer
  * @param[in]  scale        Initial scale setting of the sensor
  *
  * @return                  0 on success
  * @return                  -1 on error
  */
-int lis3dh_init(lis3dh_t *dev, spi_t spi, gpio_t cs_pin, uint8_t scale);
+int lis3dh_init(lis3dh_t *dev, spi_t spi, spi_clk_t clk,
+                gpio_t cs_pin, uint8_t scale);
 
 /**
  * @brief Read 3D acceleration data from the accelerometer
diff --git a/drivers/include/nvram-spi.h b/drivers/include/nvram-spi.h
index c03a163106cc206feb55fd62a07cc444831be06a..c064d93e228b3b443aca12559720a05b4e31d82f 100644
--- a/drivers/include/nvram-spi.h
+++ b/drivers/include/nvram-spi.h
@@ -38,6 +38,8 @@ extern "C" {
 typedef struct nvram_spi_params {
     /** @brief RIOT SPI device */
     spi_t spi;
+    /** @brief SPI clock speed */
+    spi_clk_t clk;
     /** @brief Chip select pin */
     gpio_t cs;
     /** @brief Number of address bytes following each read/write command. */
diff --git a/drivers/include/periph/init.h b/drivers/include/periph/init.h
new file mode 100644
index 0000000000000000000000000000000000000000..3e74d35ba76e30fe3205e95e47696514ae6c2293
--- /dev/null
+++ b/drivers/include/periph/init.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup    drivers_periph_init Common peripheral initialization
+ * @ingroup     drivers_periph
+ * @brief       Common static peripheral driver initialization
+ *
+ * This interface provides a central hook for any static peripheral
+ * initialization that might be needed. Typical drivers that need this are
+ * shared peripherals like SPI and I2C.
+ *
+ * @{
+ * @file
+ * @brief       Common peripheral driver initialization interface
+ *
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ */
+
+#ifndef PERIPH_INIT_H
+#define PERIPH_INIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Common peripheral initialization function
+ *
+ * This function should call all needed static initialization functions for
+ * configured peripheral drivers like SPI or I2C. This function SHOULD be called
+ * early in the boot process, e.g. before the actual kernel initialization is
+ * started.
+ */
+void periph_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PERIPH_INIT_H */
+/** @} */
diff --git a/drivers/include/periph/spi.h b/drivers/include/periph/spi.h
index 64888141eddaf35d0086ded4dab2e35763e9b143..adbc2bf85e8a1747bcfa6eb88a44f9c45700ef9d 100644
--- a/drivers/include/periph/spi.h
+++ b/drivers/include/periph/spi.h
@@ -1,9 +1,9 @@
 /*
- * Copyright (C) 2014 Freie Universität Berlin
+ * Copyright (C) 2014-2016 Freie Universität Berlin
  *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
  */
 
 /**
@@ -11,258 +11,316 @@
  * @ingroup     drivers_periph
  * @brief       Low-level SPI peripheral driver
  *
- * The current design of this interface targets implementations that use the SPI in blocking mode.
- *
- * TODO: add means for asynchronous SPI usage
+ * This interface defines an abstraction for using a CPU's hardware SPI units.
+ * The interface only supports SPI master mode.
+ *
+ * As SPI buses can have multiple devices connected to them they are to be
+ * considered as shared resources. To reflect this, the SPI interface is based
+ * on a transaction model. This requires that the bus needs to be acquired
+ * before usage and released afterwards, using the `spi_acquire()` and the
+ * `spi_release()` functions.
+ *
+ * This interface supports both software and hardware chip select lines. This is
+ * reflected by the cpi_cs_t type, which overloads the gpio_t type with platform
+ * specific values for defining platform dependent hardware chip select lines.
+ *
+ * Some devices have however very uncommon requirements on the usage and the
+ * timings of their chip select line. For those cases this interface allows to
+ * manage the chip select line manually from the user code (e.g. by calling
+ * gpio_set/clear explicitly) while deactivating the SPI driver internal chip
+ * select handling by passing @ref GPIO_UNDEF as CS parameter.
+ *
+ * In the time, when the SPI bus is not used, the SPI unit should be in
+ * low-power mode to save energy.
+ *
+ * The SPI unit's initialization is split into 3 parts:
+ * 1. `spi_init()` should be called once for each SPI unit defined by a board
+ *    during system initialization.
+ * 2. `spi_init_cs()` should be called during device driver initialization, as
+ *    each chip select pin/line is used uniquely by a specific device, i.e. chip
+ *    select lines are no shared resource.
+ * 3. `spi_aquire()` needs to be called for each new transaction. This function
+ *    configures the bus with specific parameters (clock, mode) for the duration
+ *    of that transaction.
  *
  * @{
  * @file
- * @brief       Low-level SPI peripheral driver interface definitions
+ * @brief       Low-level SPI peripheral driver interface definition
  *
  * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  */
 
-#ifndef SPI_H
-#define SPI_H
+#ifndef PERIPH_SPI_H
+#define PERIPH_SPI_H
 
+#include <stdbool.h>
+#include <stddef.h>
 #include <stdint.h>
+#include <limits.h>
 
 #include "periph_cpu.h"
 #include "periph_conf.h"
+#include "periph/gpio.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* add guard for the case that no SPI device is defined */
-#if SPI_NUMOF
+/**
+ * @brief   Default SPI device access macro
+ */
+#ifndef SPI_DEV
+#define SPI_DEV(x)      (x)
+#endif
 
 /**
- * @brief Definition available SPI devices
+ * @brief   Define global value for undefined SPI device
  */
-typedef enum {
-#if SPI_0_EN
-    SPI_0 = 0,          /**< SPI device 0 */
+#ifndef SPI_UNDEF
+#define SPI_UNDEF       (UINT_MAX)
 #endif
-#if SPI_1_EN
-    SPI_1,              /**< SPI device 1 */
+
+/**
+ * @brief   Define value for unused CS line
+ */
+#ifndef SPI_CS_UNDEF
+#define SPI_CS_UNDEF    (GPIO_UNDEF)
 #endif
-#if SPI_2_EN
-    SPI_2,              /**< SPI device 2 */
+
+/**
+ * @brief   Default SPI hardware chip select access macro
+ *
+ * Per default, we map all hardware chip select lines to be not defined. If an
+ * implementation makes use of HW chip select lines, this value needs to be
+ * overridden by the corresponding CPU.
+ */
+#ifndef SPI_HWCS
+#define SPI_HWCS(x)     (SPI_CS_UNDEF)
 #endif
-#if SPI_3_EN
-    SPI_3,              /**< SPI device 3 */
+
+/**
+ * @brief   Default type for SPI devices
+ */
+#ifndef HAVE_SPI_T
+typedef unsigned int spi_t;
 #endif
-} spi_t;
 
 /**
- * @brief The SPI mode is defined by the four possible combinations of clock polarity and
- *        clock phase.
- * @{
+ * @brief   Chip select pin type overlaps with gpio_t so it can be casted to
+ *          this
  */
-#ifndef HAVE_SPI_CONF_T
-typedef enum {
-    /**
-     * The first data bit is sampled by the receiver on the first SCK edge. The
-     * first edge of SCK is rising. This is sometimes also referred to as SPI
-     * mode 0, or (CPOL=0, CPHA=0).
-     */
-    SPI_CONF_FIRST_RISING = 0,
-    /**
-     * The first data bit is sampled by the receiver on the second SCK edge. The
-     * first edge of SCK is rising, i.e. the sampling edge is falling. This is
-     * sometimes also referred to as SPI mode 1, or (CPOL=0, CPHA=1).
-     */
-    SPI_CONF_SECOND_RISING = 1,
-    /**
-     * The first data bit is sampled by the receiver on the first SCK edge. The
-     * first edge of SCK is falling. This is sometimes also referred to as SPI
-     * mode 2, or (CPOL=1, CPHA=0).
-     */
-    SPI_CONF_FIRST_FALLING = 2,
-    /**
-     * The first data bit is sampled by the receiver on the second SCK edge. The
-     * first edge of SCK is falling, i.e. the sampling edge is rising. This is
-     * sometimes also referred to as SPI mode 3, or (CPOL=1, CPHA=1).
-     */
-    SPI_CONF_SECOND_FALLING = 3
-} spi_conf_t;
+#ifndef HAVE_SPI_CS_T
+typedef gpio_t spi_cs_t;
 #endif
-/** @} */
 
 /**
- * @brief Define a set of pre-defined SPI clock speeds.
- *
- * The actual speed of the bus can vary to some extend, as the combination of CPU clock and
- * available prescale values on certain platforms may not make the exact values possible.
- *
- * @{
+ * @brief   Status codes used by the SPI driver interface
+ */
+enum {
+    SPI_OK          =  0,   /**< everything went as planned */
+    SPI_NODEV       = -1,   /**< invalid SPI bus specified */
+    SPI_NOCS        = -2,   /**< invalid chip select line specified */
+    SPI_NOMODE      = -3,   /**< selected mode is not supported */
+    SPI_NOCLK       = -4    /**< selected clock value is not supported */
+};
+
+/**
+ * @brief   Available SPI modes, defining the configuration of clock polarity
+ *          and clock phase
+ *
+ * RIOT is using the mode numbers as commonly defined by most vendors
+ * (https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Mode_numbers):
+ *
+ * - MODE_0: CPOL=0, CPHA=0 - The first data bit is sampled by the receiver on
+ *           the first SCK rising SCK edge (this mode is used most often).
+ * - MODE_1: CPOL=0, CPHA=1 - The first data bit is sampled by the receiver on
+ *           the second rising SCK edge.
+ * - MODE_2: CPOL=1, CPHA=0 - The first data bit is sampled by the receiver on
+ *           the first falling SCK edge.
+ * - MODE_3: CPOL=1, CPHA=1 - The first data bit is sampled by the receiver on
+ *           the second falling SCK edge.
  */
-#ifndef HAVE_SPI_SPEED_T
+#ifndef HAVE_SPI_MODE_T
 typedef enum {
-    SPI_SPEED_100KHZ = 0,       /**< drive the SPI bus with 100KHz */
-    SPI_SPEED_400KHZ,           /**< drive the SPI bus with 400KHz */
-    SPI_SPEED_1MHZ,             /**< drive the SPI bus with 1MHz */
-    SPI_SPEED_5MHZ,             /**< drive the SPI bus with 5MHz */
-    SPI_SPEED_10MHZ             /**< drive the SPI bus with 10MHz */
-} spi_speed_t;
+    SPI_MODE_0 = 0,         /**< CPOL=0, CPHA=0 */
+    SPI_MODE_1,             /**< CPOL=0, CPHA=1 */
+    SPI_MODE_2,             /**< CPOL=1, CPHA=0 */
+    SPI_MODE_3              /**< CPOL=1, CPHA=1 */
+} spi_mode_t;
 #endif
-/** @} */
 
 /**
- * @brief Initialize the given SPI device to work in master mode
- *
- * In master mode the SPI device is configured to control the SPI bus. This means the device
- * will start and end all communication on the bus and control the CLK line. For transferring
- * data on the bus the below defined transfer functions should be used.
- *
- * @param[in] dev       SPI device to initialize
- * @param[in] conf      Mode of clock phase and clock polarity
- * @param[in] speed     desired clock speed for driving the SPI bus
+ * @brief   Available SPI clock speeds
  *
- * @return              0 on success
- * @return              -1 on unavailable speed value
- * @return              -2 on other errors
+ * The actual speed of the bus can vary to some extend, as the combination of
+ * CPU clock and available prescaler values on certain platforms may not make
+ * the exact values possible.
  */
-int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed);
+#ifndef HAVE_SPI_CLK_T
+typedef enum {
+    SPI_CLK_100KHZ = 0,     /**< drive the SPI bus with 100KHz */
+    SPI_CLK_400KHZ,         /**< drive the SPI bus with 400KHz */
+    SPI_CLK_1MHZ,           /**< drive the SPI bus with 1MHz */
+    SPI_CLK_5MHZ,           /**< drive the SPI bus with 5MHz */
+    SPI_CLK_10MHZ           /**< drive the SPI bus with 10MHz */
+} spi_clk_t;
+#endif
 
 /**
- * @brief Initialize the given SPI device to work in slave mode
+ * @brief   Basic initialization of the given SPI bus
  *
- * In slave mode the SPI device is purely reacting to the bus. Transaction will be started and
- * ended by a connected SPI master. When a byte is received, the callback is called in interrupt
- * context with this byte as argument. The return byte of the callback is transferred to the
- * master in the next transmission cycle. This interface enables easy implementation of a register
- * based access paradigm for the SPI slave.
+ * This function does the basic initialization including pin configuration for
+ * MISO, MOSI, and CLK pins. After initialization, the given device should be
+ * in power down state.
  *
- * @param[in] dev       The SPI device to initialize as SPI slave
- * @param[in] conf      Mode of clock phase and polarity
- * @param[in] cb        callback called every time a byte was received
+ * This function is intended to be called by the board initialization code
+ * during system startup to prepare the (shared) SPI device for further usage.
+ * It uses the board specific initialization parameters as defined in the
+ * board's `periph_conf.h`.
  *
- * @return              0 on success
- * @return              -1 on error
- */
-int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data));
-
-/**
- * @brief Configure SCK, MISO and MOSI pins for the given SPI device
+ * Errors (e.g. invalid @p bus parameter) are not signaled through a return
+ * value, but should be signaled using the assert() function internally.
  *
- * @param[in] dev       SPI device to use
+ * @note    This function MUST not be called more than once per bus!
  *
- * @return              0 on success
- * @return              -1 on error
+ * @param[in] bus       SPI device to initialize
  */
-int spi_conf_pins(spi_t dev);
+void spi_init(spi_t bus);
 
 /**
- * @brief Get mutually exclusive access to the given SPI bus
+ * @brief   Initialize the used SPI bus pins, i.e. MISO, MOSI, and CLK
+ *
  *
- * In case the SPI device is busy, this function will block until the bus is free again.
+ * After calling spi_init, the pins must be initialized (i.e. spi_init is
+ * calling) this function internally. In normal cases, this function will not be
+ * used. But there are some devices (e.g. CC110x), that use SPI bus lines also
+ * for other purposes and need the option to dynamically re-configure one or
+ * more of the used pins. So they can take control over certain pins and return
+ * control back to the SPI driver using this function.
  *
- * @param[in] dev       SPI device to access
+ * The pins used are configured in the board's periph_conf.h.
  *
- * @return              0 on success
- * @return              -1 on error
+ * @param[in] bus       SPI device the pins are configure for
  */
-int spi_acquire(spi_t dev);
+void spi_init_pins(spi_t bus);
 
 /**
- * @brief Release the given SPI device to be used by others
+ * @brief   Initialize the given chip select pin
  *
- * @param[in] dev       SPI device to release
+ * The chip select can be any generic GPIO pin (e.g. GPIO_PIN(x,y)), or it can
+ * be a hardware chip select line. The existence and number of of hardware chip
+ * select lines depends on the underlying platform and the actual pins used for
+ * hardware chip select lines are defined in the board's `periph_conf.h`.
  *
- * @return              0 on success
- * @return              -1 on error
- */
-int spi_release(spi_t dev);
-
-/**
- * @brief Transfer one byte on the given SPI bus
+ * Define the used chip select line using the @ref SPI_HWCS(x) macro for
+ * hardware chip select line `x` or the GPIO_PIN(x,y) macro for using any
+ * GPIO pin for manual chip select.
  *
- * @param[in] dev       SPI device to use
- * @param[in] out       Byte to send out, set NULL if only receiving
- * @param[out] in       Byte to read, set NULL if only sending
+ * @param[in] bus       SPI device that is used with the given CS line
+ * @param[in] cs        chip select pin to initialize
  *
- * @return              Number of bytes that were transfered
- * @return              -1 on error
+ * @return              SPI_OK on success
+ * @return              SPI_NODEV on invalid device
+ * @return              SPI_NOCS on invalid CS pin/line
  */
-int spi_transfer_byte(spi_t dev, char out, char *in);
+int spi_init_cs(spi_t bus, spi_cs_t cs);
 
 /**
- * @brief Transfer a number bytes on the given SPI bus
+ * @brief   Start a new SPI transaction
+ *
+ * Starting a new SPI transaction will get exclusive access to the SPI bus
+ * and configure it according to the given values. If another SPI transaction
+ * is active when this function is called, this function will block until the
+ * other transaction is complete (spi_relase was called).
+ *
+ * @note    This function expects the @p bus and the @p cs parameters to be
+ *          valid (they are checked in spi_init and spi_init_cs before)
  *
- * @param[in] dev       SPI device to use
- * @param[in] out       Array of bytes to send, set NULL if only receiving
- * @param[out] in       Buffer to receive bytes to, set NULL if only sending
- * @param[in] length    Number of bytes to transfer
+ * @param[in] bus       SPI device to access
+ * @param[in] cs        chip select pin/line to use, set to SPI_CS_UNDEF if chip
+ *                      select should not be handled by the SPI driver
+ * @param[in] mode      mode to use for the new transaction
+ * @param[in] clk       bus clock speed to use for the transaction
  *
- * @return              Number of bytes that were transfered
- * @return              -1 on error
+ * @return              SPI_OK on success
+ * @return              SPI_NOMODE if given mode is not supported
+ * @return              SPI_NOCLK if given clock speed is not supported
  */
-int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length);
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk);
 
 /**
- * @brief Transfer one byte to/from a given register address
+ * @brief   Finish an ongoing SPI transaction by releasing the given SPI bus
  *
- * This function is a shortcut function for easier handling of register based SPI devices. As
- * many SPI devices use a register based addressing scheme, this function is a convenient short-
- * cut for interfacing with such devices.
+ * After release, the given SPI bus should be fully powered down until acquired
+ * again.
  *
- * @param[in] dev       SPI device to use
- * @param[in] reg       Register address to transfer data to/from
- * @param[in] out       Byte to send, set NULL if only receiving data
- * @param[out] in       Byte to read, set NULL if only sending
- *
- * @return              Number of bytes that were transfered
- * @return              -1 on error
+ * @param[in] bus       SPI device to release
  */
-int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in);
+void spi_release(spi_t bus);
 
 /**
- * @brief Transfer a number of bytes from/to a given register address
- *
- * This function is a shortcut function for easier handling of register based SPI devices. As
- * many SPI devices use a register based addressing scheme, this function is a convenient short-
- * cut for interfacing with such devices.
+ * @brief Transfer one byte on the given SPI bus
  *
- * @param[in] dev       SPI device to use
- * @param[in] reg       Register address to transfer data to/from
- * @param[in] out       Byte array to send data from, set NULL if only receiving
- * @param[out] in       Byte buffer to read into, set NULL if only sending
- * @param[in] length    Number of bytes to transfer
+ * @param[in] bus       SPI device to use
+ * @param[in] cs        chip select pin/line to use, set to SPI_CS_UNDEF if chip
+ *                      select should not be handled by the SPI driver
+ * @param[in] cont      if true, keep device selected after transfer
+ * @param[in] out       byte to send out, set NULL if only receiving
  *
- * @return              Number of bytes that were transfered
- * @return              -1 on error
+ * @return              the received byte
  */
-int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length);
+uint8_t spi_transfer_byte(spi_t bus, spi_cs_t cs, bool cont, uint8_t out);
 
 /**
- * @brief Tell the SPI driver that a new transaction was started. Call only when SPI in slave mode!
- *
- * @param[in] dev       SPI device that is active
- * @param[in] reset_val The byte that is send to the master as first byte
+ * @brief   Transfer a number bytes using the given SPI bus
+ *
+ * @param[in]  bus      SPI device to use
+ * @param[in]  cs       chip select pin/line to use, set to SPI_CS_UNDEF if chip
+ *                      select should not be handled by the SPI driver
+ * @param[in]  cont     if true, keep device selected after transfer
+ * @param[in]  out      buffer to send data from, set NULL if only receiving
+ * @param[out] in       buffer to read into, set NULL if only sending
+ * @param[in]  len      number of bytes to transfer
  */
-void spi_transmission_begin(spi_t dev, char reset_val);
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len);
 
 /**
- * @brief Power on the given SPI device
+ * @brief   Transfer one byte to/from a given register address
+ *
+ * This function is a shortcut function for easier handling of SPI devices that
+ * implement a register based access scheme.
+ *
+ * @param[in] bus       SPI device to use
+ * @param[in]  cs       chip select pin/line to use, set to SPI_CS_UNDEF if chip
+ *                      select should not be handled by the SPI driver
+ * @param[in] reg       register address to transfer data to/from
+ * @param[in] out       byte to send, set NULL if only receiving data
  *
- * @param[in] dev       SPI device to power on
+ * @return              value that was read from the given register address
  */
-void spi_poweron(spi_t dev);
+uint8_t spi_transfer_reg(spi_t bus, spi_cs_t cs, uint8_t reg, uint8_t out);
 
 /**
- * @brief Power off the given SPI device
- *
- * @param[in] dev       SPI device to power off
+ * @brief   Transfer a number of bytes to/from a given register address
+ *
+ * This function is a shortcut function for easier handling of SPI devices that
+ * implement a register based access scheme.
+ *
+ * @param[in]  bus      SPI device to use
+ * @param[in]  cs       chip select pin/line to use, set to SPI_CS_UNDEF if chip
+ *                      select should not be handled by the SPI driver
+ * @param[in]  reg      register address to transfer data to/from
+ * @param[in]  out      buffer to send data from, set NULL if only receiving
+ * @param[out] in       buffer to read into, set NULL if only sending
+ * @param[in]  len      number of bytes to transfer
  */
-void spi_poweroff(spi_t dev);
-
-#endif /* SPI_NUMOF */
+void spi_transfer_regs(spi_t bus, spi_cs_t cs, uint8_t reg,
+                       const void *out, void *in, size_t len);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* SPI_H */
+#endif /* PERIPH_SPI_H */
 /** @} */
diff --git a/drivers/include/sdcard_spi.h b/drivers/include/sdcard_spi.h
index 87758921285dfadcfbd690a1264fb46f05b4e171..0d19a56d1bd0c1099b1624000c5a7833cea12401 100644
--- a/drivers/include/sdcard_spi.h
+++ b/drivers/include/sdcard_spi.h
@@ -185,13 +185,14 @@ typedef struct {
  * @brief   Device descriptor for sdcard_spi
  */
 struct {
-    sdcard_spi_params_t params;  /**< parameters for pin and spi config */
-    bool use_block_addr;         /**< true if block adressing (vs. byte adressing) is used */
-    bool init_done;              /**< set to true once the init procedure completed sucessfully */
-    sd_version_t card_type;      /**< version of SD-card */
-    int csd_structure;           /**< version of the CSD register structure */
-    cid_t cid;                   /**< CID register */
-    csd_t csd;                   /**< CSD register */
+    sdcard_spi_params_t params;     /**< parameters for pin and spi config */
+    spi_clk_t spi_clk;              /**< active SPI clock speed */
+    bool use_block_addr;            /**< true if block adressing (vs. byte adressing) is used */
+    bool init_done;                 /**< set to true once the init procedure completed sucessfully */
+    sd_version_t card_type;         /**< version of SD-card */
+    int csd_structure;              /**< version of the CSD register structure */
+    cid_t cid;                      /**< CID register */
+    csd_t csd;                      /**< CSD register */
 } typedef sdcard_spi_t;
 
 /**
diff --git a/drivers/include/w5100.h b/drivers/include/w5100.h
index 9cd72076c9dd60c42bc90347c88dd3218fcf3c24..75447a08f695e784726dfff6513d74445052bbd6 100644
--- a/drivers/include/w5100.h
+++ b/drivers/include/w5100.h
@@ -56,7 +56,7 @@ enum {
  */
 typedef struct {
     spi_t spi;              /**< SPI bus used */
-    spi_speed_t spi_speed;  /**< clock speed used on the selected SPI bus */
+    spi_clk_t clk;          /**< clock speed used on the selected SPI bus */
     gpio_t cs;              /**< pin connected to the chip select line */
     gpio_t evt;             /**< pin connected to the INT line */
 } w5100_params_t;
diff --git a/drivers/kw2xrf/include/kw2xrf_spi.h b/drivers/kw2xrf/include/kw2xrf_spi.h
index 3368ed21ee4bc36a13fccc21c935d27e2e8cbf04..a973a5510f1c5190eae47c9d0aa6b43f0a381c63 100644
--- a/drivers/kw2xrf/include/kw2xrf_spi.h
+++ b/drivers/kw2xrf/include/kw2xrf_spi.h
@@ -30,14 +30,13 @@ extern "C" {
 /**
  * @brief SPI interface initialization
  * @param[in] spi           SPI bus the device is connected to
- * @param[in] spi_speed     SPI speed to use
+ * @param[in] spi_clk     SPI clock speed to use
  * @param[in] cs_pin        GPIO pin connected to chip select
  *
  * @return 0 on success
  * @return -1 on error
  */
-int kw2xrf_spi_init(spi_t spi, spi_speed_t spi_speed,
-                    gpio_t cs_pin);
+int kw2xrf_spi_init(spi_t spi, spi_clk_t spi_clk, spi_cs_t cs_pin);
 
 /**
  * @brief Writes a byte to the kw2xrf register.
diff --git a/drivers/kw2xrf/kw2xrf.c b/drivers/kw2xrf/kw2xrf.c
index ebb4dff1e6318478281752a0d25f18c189683c7b..fd2b41d9b7ff62dd4eb150674412eae92a70772e 100644
--- a/drivers/kw2xrf/kw2xrf.c
+++ b/drivers/kw2xrf/kw2xrf.c
@@ -383,7 +383,7 @@ int kw2xrf_set_addr_long(kw2xrf_t *dev, uint64_t addr)
     return sizeof(uint64_t);
 }
 
-int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_speed_t spi_speed,
+int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_clk_t spi_clk,
                 gpio_t cs_pin, gpio_t int_pin)
 {
     uint8_t reg = 0;
@@ -405,7 +405,7 @@ int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_speed_t spi_speed,
         return -ENODEV;
     }
 
-    kw2xrf_spi_init(spi, spi_speed, cs_pin);
+    kw2xrf_spi_init(spi, spi_clk, cs_pin);
 
     if (kw2xrf_on(dev) != 0) {
         core_panic(PANIC_GENERAL_ERROR, "Could not start MKW2XD radio transceiver");
diff --git a/drivers/kw2xrf/kw2xrf_spi.c b/drivers/kw2xrf/kw2xrf_spi.c
index 8a9bc9e4f58fd4c037f88e18506da7f833b76ed2..f129925dccc0d373d7cffd6fa5cbbc77d88e5544 100644
--- a/drivers/kw2xrf/kw2xrf_spi.c
+++ b/drivers/kw2xrf/kw2xrf_spi.c
@@ -27,49 +27,36 @@
 #define ENABLE_DEBUG    (0)
 #include "debug.h"
 
-#define KW2XRF_IBUF_LENGTH    9
+#define SPI_MODE                (SPI_MODE_0)
+#define KW2XRF_IBUF_LENGTH      (9)
 
 static uint8_t ibuf[KW2XRF_IBUF_LENGTH];
 
 /** Set up in kw2xrf_spi_init during initialization */
-static gpio_t kw2xrf_cs_pin;
 static spi_t kw2xrf_spi;
+static spi_clk_t kw2xrf_clk;
+static spi_cs_t kw2xrf_cs_pin;
 
-void kw2xrf_spi_transfer_head(void)
+static inline void kw2xrf_spi_transfer_head(void)
 {
-#if KW2XRF_SHARED_SPI
-    spi_acquire(kw2xrf_spi);
-    gpio_clear(kw2xrf_cs_pin);
-#endif
+    spi_acquire(kw2xrf_spi, kw2xrf_cs_pin, SPI_MODE, kw2xrf_clk);
 }
 
-void kw2xrf_spi_transfer_tail(void)
+static inline void kw2xrf_spi_transfer_tail(void)
 {
-#if KW2XRF_SHARED_SPI
-    gpio_set(kw2xrf_cs_pin);
     spi_release(kw2xrf_spi);
-#endif
 }
 
-int kw2xrf_spi_init(spi_t spi, spi_speed_t spi_speed,
-                    gpio_t cs_pin)
+int kw2xrf_spi_init(spi_t spi, spi_clk_t spi_clk, spi_cs_t cs_pin)
 {
     int res;
-    kw2xrf_cs_pin = cs_pin;     /**< for later reference */
     kw2xrf_spi = spi;
+    kw2xrf_clk = spi_clk;
+    kw2xrf_cs_pin = cs_pin;     /**< for later reference */
 
-#if KW2XRF_SHARED_SPI
-    spi_acquire(kw2xrf_spi);
-#endif
-    res = spi_init_master(kw2xrf_spi, SPI_CONF_FIRST_RISING, spi_speed);
-#if KW2XRF_SHARED_SPI
-    spi_release(kw2xrf_spi);
-    gpio_init(kw2xrf_cs_pin, GPIO_OUT);
-    gpio_set(kw2xrf_cs_pin);
-#endif
-
-    if (res < 0) {
-        DEBUG("kw2xrf_spi_init: error initializing SPI_%i device (code %i)\n",
+    res = spi_init_cs(kw2xrf_spi, kw2xrf_cs_pin);
+    if (res != SPI_OK) {
+        DEBUG("kw2xrf_spi_init: error initializing SPI_DEV(%i) (code %i)\n",
               kw2xrf_spi, res);
         return -1;
     }
@@ -80,7 +67,7 @@ int kw2xrf_spi_init(spi_t spi, spi_speed_t spi_speed,
 void kw2xrf_write_dreg(uint8_t addr, uint8_t value)
 {
     kw2xrf_spi_transfer_head();
-    spi_transfer_reg(kw2xrf_spi, addr, value, NULL);
+    spi_transfer_reg(kw2xrf_spi, kw2xrf_cs_pin, addr, value);
     kw2xrf_spi_transfer_tail();
     return;
 }
@@ -89,8 +76,8 @@ uint8_t kw2xrf_read_dreg(uint8_t addr)
 {
     uint8_t value;
     kw2xrf_spi_transfer_head();
-    spi_transfer_reg(kw2xrf_spi, (addr | MKW2XDRF_REG_READ),
-                     0x0, (char *)&value);
+    value = spi_transfer_reg(kw2xrf_spi, kw2xrf_cs_pin,
+                             (addr | MKW2XDRF_REG_READ), 0x0);
     kw2xrf_spi_transfer_tail();
     return value;
 }
@@ -108,8 +95,8 @@ void kw2xrf_write_iregs(uint8_t addr, uint8_t *buf, uint8_t length)
     }
 
     kw2xrf_spi_transfer_head();
-    spi_transfer_regs(kw2xrf_spi, MKW2XDM_IAR_INDEX,
-                      (char *)ibuf, NULL, length + 1);
+    spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDM_IAR_INDEX,
+                      ibuf, NULL, length + 1);
     kw2xrf_spi_transfer_tail();
 
     return;
@@ -124,8 +111,9 @@ void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length)
     ibuf[0] = addr;
 
     kw2xrf_spi_transfer_head();
-    spi_transfer_regs(kw2xrf_spi, MKW2XDM_IAR_INDEX | MKW2XDRF_REG_READ,
-                      (char *)ibuf, (char *)ibuf, length + 1);
+    spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin,
+                      MKW2XDM_IAR_INDEX | MKW2XDRF_REG_READ,
+                      ibuf, ibuf, length + 1);
     kw2xrf_spi_transfer_tail();
 
     for (uint8_t i = 0; i < length; i++) {
@@ -138,16 +126,15 @@ void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length)
 void kw2xrf_write_fifo(uint8_t *data, uint8_t length)
 {
     kw2xrf_spi_transfer_head();
-    spi_transfer_regs(kw2xrf_spi, MKW2XDRF_BUF_WRITE,
-                      (char *)data, NULL, length);
+    spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDRF_BUF_WRITE,
+                      data, NULL, length);
     kw2xrf_spi_transfer_tail();
 }
 
 void kw2xrf_read_fifo(uint8_t *data, uint8_t length)
 {
     kw2xrf_spi_transfer_head();
-    spi_transfer_regs(kw2xrf_spi, MKW2XDRF_BUF_READ, NULL,
-                      (char *)data, length);
+    spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDRF_BUF_READ,
+                      NULL, data, length);
     kw2xrf_spi_transfer_tail();
 }
-/** @} */
diff --git a/drivers/lis3dh/include/lis3dh_params.h b/drivers/lis3dh/include/lis3dh_params.h
index 77c47fae5adce764c1afdba0fd41d3af48a24e59..8d0159fe5618a8baa0ccede483d1ea60f5b5732c 100644
--- a/drivers/lis3dh/include/lis3dh_params.h
+++ b/drivers/lis3dh/include/lis3dh_params.h
@@ -32,7 +32,7 @@ extern "C" {
  * @{
  */
 #ifndef LIS3DH_PARAM_SPI
-#define LIS3DH_PARAM_SPI            (SPI_0)
+#define LIS3DH_PARAM_SPI            (SPI_DEV(0))
 #endif
 #ifndef LIS3DH_PARAM_CS
 #define LIS3DH_PARAM_CS             (GPIO_PIN(0, 0))
diff --git a/drivers/lis3dh/lis3dh.c b/drivers/lis3dh/lis3dh.c
index fae0064e0e6c019f4393180207bfccb1cbeca650..808687bae1e02a784ccb26bc2fbaef3359e94d6c 100644
--- a/drivers/lis3dh/lis3dh.c
+++ b/drivers/lis3dh/lis3dh.c
@@ -1,54 +1,59 @@
 /*
  * Copyright (C) 2015 Eistec AB
+ *               2016 Freie Universität Berlin
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License v2.1. See the file LICENSE in the top level
  * directory for more details.
  */
 
-#include <stddef.h>
-#include <stdint.h>
-#include "periph/gpio.h"
-#include "periph/spi.h"
-#include "lis3dh.h"
-
 /**
  * @ingroup     drivers_lis3dh
  * @{
  *
  * @file
- * @brief  Implementation of LIS3DH SPI driver
+ * @brief       Implementation of LIS3DH SPI driver
  *
- * @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
+ * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  */
 
+#include <stddef.h>
+#include <stdint.h>
+#include "periph/gpio.h"
+#include "periph/spi.h"
+#include "lis3dh.h"
 
-static inline int lis3dh_write_bits(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t mask,
-                                    const uint8_t values);
-static int lis3dh_write_reg(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t value);
-static int lis3dh_read_regs(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t len,
-                            uint8_t *buf);
+#define SPI_MODE            SPI_MODE_0
 
+static inline int lis3dh_write_bits(const lis3dh_t *dev, const lis3dh_reg_t reg,
+                                    const uint8_t mask,  const uint8_t values);
+static int lis3dh_write_reg(const lis3dh_t *dev, const lis3dh_reg_t reg,
+                            const uint8_t value);
+static int lis3dh_read_regs(const lis3dh_t *dev, const lis3dh_reg_t reg,
+                            const uint8_t len, uint8_t *buf);
 
-int lis3dh_init(lis3dh_t *dev, spi_t spi, gpio_t cs_pin, uint8_t scale)
+int lis3dh_init(lis3dh_t *dev, spi_t spi, spi_clk_t clk,
+                gpio_t cs_pin, uint8_t scale)
 {
-    uint8_t in;
+    uint8_t test;
 
     dev->spi = spi;
+    dev->clk = clk;
     dev->cs = cs_pin;
     dev->scale = 0;
 
-    /* CS */
-    gpio_init(dev->cs, GPIO_OUT);
-    gpio_set(dev->cs);
-
-    if (lis3dh_read_regs(dev, LIS3DH_REG_WHO_AM_I, 1, &in) < 0) {
-        /* Communication error */
+    /* initialize the chip select line */
+    if (spi_init_cs(dev->spi, dev->cs) != SPI_OK) {
         return -1;
     }
 
-    if (in != LIS3DH_WHO_AM_I_RESPONSE) {
-        /* Chip is not responding correctly */
+    /* test connection to the device */
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, dev->clk);
+    test = spi_transfer_reg(dev->spi, dev->cs, LIS3DH_REG_WHO_AM_I, 0);
+    spi_release(dev->spi);
+    if (test != LIS3DH_WHO_AM_I_RESPONSE) {
+        /* chip is not responding correctly */
         return -1;
     }
 
@@ -78,23 +83,14 @@ int lis3dh_read_xyz(const lis3dh_t *dev, lis3dh_data_t *acc_data)
 {
     uint8_t i;
     /* Set READ MULTIPLE mode */
-    static const uint8_t addr = (LIS3DH_REG_OUT_X_L | LIS3DH_SPI_READ_MASK | LIS3DH_SPI_MULTI_MASK);
+    static const uint8_t addr = (LIS3DH_REG_OUT_X_L | LIS3DH_SPI_READ_MASK |
+                                 LIS3DH_SPI_MULTI_MASK);
 
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, dev->clk);
     /* Perform the transaction */
-    gpio_clear(dev->cs);
-
-    if (spi_transfer_regs(dev->spi, addr, NULL, (char *)acc_data,
-                          sizeof(lis3dh_data_t)) != sizeof(lis3dh_data_t)) {
-        /* Transfer error */
-        gpio_set(dev->cs);
-        /* Release the bus for other threads. */
-        spi_release(dev->spi);
-        return -1;
-    }
-
-    gpio_set(dev->cs);
+    spi_transfer_regs(dev->spi, dev->cs, addr,
+                      NULL, acc_data, sizeof(lis3dh_data_t));
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
@@ -111,29 +107,35 @@ int lis3dh_read_xyz(const lis3dh_t *dev, lis3dh_data_t *acc_data)
 
 int lis3dh_read_aux_adc1(const lis3dh_t *dev, int16_t *out)
 {
-    return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC1_L, LIS3DH_ADC_DATA_SIZE, (uint8_t *)out);
+    return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC1_L,
+                            LIS3DH_ADC_DATA_SIZE, (uint8_t *)out);
 }
 
 int lis3dh_read_aux_adc2(const lis3dh_t *dev, int16_t *out)
 {
-    return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC2_L, LIS3DH_ADC_DATA_SIZE, (uint8_t *)out);
+    return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC2_L,
+                            LIS3DH_ADC_DATA_SIZE, (uint8_t *)out);
 }
 
 int lis3dh_read_aux_adc3(const lis3dh_t *dev, int16_t *out)
 {
-    return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC3_L, LIS3DH_ADC_DATA_SIZE, (uint8_t *)out);
+    return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC3_L,
+                            LIS3DH_ADC_DATA_SIZE, (uint8_t *)out);
 }
 
-int lis3dh_set_aux_adc(lis3dh_t *dev, const uint8_t enable, const uint8_t temperature)
+int lis3dh_set_aux_adc(lis3dh_t *dev, const uint8_t enable,
+                       const uint8_t temperature)
 {
-    return lis3dh_write_bits(dev, LIS3DH_REG_TEMP_CFG_REG, LIS3DH_TEMP_CFG_REG_ADC_PD_MASK,
+    return lis3dh_write_bits(dev, LIS3DH_REG_TEMP_CFG_REG,
+                             LIS3DH_TEMP_CFG_REG_ADC_PD_MASK,
                              (enable ? LIS3DH_TEMP_CFG_REG_ADC_PD_MASK : 0) |
                              (temperature ? LIS3DH_TEMP_CFG_REG_TEMP_EN_MASK : 0));
 }
 
 int lis3dh_set_axes(lis3dh_t *dev, const uint8_t axes)
 {
-    return lis3dh_write_bits(dev, LIS3DH_REG_CTRL_REG1, LIS3DH_CTRL_REG1_XYZEN_MASK, axes);
+    return lis3dh_write_bits(dev, LIS3DH_REG_CTRL_REG1,
+                             LIS3DH_CTRL_REG1_XYZEN_MASK, axes);
 }
 
 int lis3dh_set_fifo(lis3dh_t *dev, const uint8_t mode, const uint8_t watermark)
@@ -190,8 +192,8 @@ int lis3dh_set_scale(lis3dh_t *dev, const uint8_t scale)
         default:
             return -1;
     }
-    return lis3dh_write_bits(dev, LIS3DH_REG_CTRL_REG4, LIS3DH_CTRL_REG4_FS_MASK,
-                             scale_reg);
+    return lis3dh_write_bits(dev, LIS3DH_REG_CTRL_REG4,
+                             LIS3DH_CTRL_REG4_FS_MASK, scale_reg);
 }
 
 int lis3dh_set_int1(lis3dh_t *dev, const uint8_t mode)
@@ -218,31 +220,23 @@ int lis3dh_get_fifo_level(lis3dh_t *dev)
  * @param[in]  dev          Device descriptor
  * @param[in]  reg          The source register starting address
  * @param[in]  len          Number of bytes to read
- * @param[out] buf          The values of the source registers will be written here
+ * @param[out] buf          The values of the source registers will be written
+ *                          here
  *
  * @return                  0 on success
  * @return                  -1 on error
  */
-static int lis3dh_read_regs(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t len,
-                            uint8_t *buf)
+static int lis3dh_read_regs(const lis3dh_t *dev, const lis3dh_reg_t reg,
+                            const uint8_t len, uint8_t *buf)
 {
     /* Set READ MULTIPLE mode */
-    uint8_t addr = (reg & LIS3DH_SPI_ADDRESS_MASK) | LIS3DH_SPI_READ_MASK | LIS3DH_SPI_MULTI_MASK;
+    uint8_t addr = (reg & LIS3DH_SPI_ADDRESS_MASK) | LIS3DH_SPI_READ_MASK |
+                    LIS3DH_SPI_MULTI_MASK;
 
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, dev->clk);
     /* Perform the transaction */
-    gpio_clear(dev->cs);
-
-    if (spi_transfer_regs(dev->spi, addr, NULL, (char *)buf, len) < 0) {
-        /* Transfer error */
-        gpio_set(dev->cs);
-        /* Release the bus for other threads. */
-        spi_release(dev->spi);
-        return -1;
-    }
-
-    gpio_set(dev->cs);
+    spi_transfer_regs(dev->spi, dev->cs, addr, NULL, buf, (size_t)len);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
@@ -258,27 +252,20 @@ static int lis3dh_read_regs(const lis3dh_t *dev, const lis3dh_reg_t reg, const u
  * @return                  0 on success
  * @return                  -1 on error
  */
-static int lis3dh_write_reg(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t value)
+static int lis3dh_write_reg(const lis3dh_t *dev, const lis3dh_reg_t reg,
+                            const uint8_t value)
 {
     /* Set WRITE SINGLE mode */
-    uint8_t addr = (reg & LIS3DH_SPI_ADDRESS_MASK) | LIS3DH_SPI_WRITE_MASK | LIS3DH_SPI_SINGLE_MASK;
+    uint8_t addr = ((reg & LIS3DH_SPI_ADDRESS_MASK) | LIS3DH_SPI_WRITE_MASK |
+                    LIS3DH_SPI_SINGLE_MASK);
 
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, dev->clk);
     /* Perform the transaction */
-    gpio_clear(dev->cs);
-
-    if (spi_transfer_reg(dev->spi, addr, value, NULL) < 0) {
-        /* Transfer error */
-        gpio_set(dev->cs);
-        /* Release the bus for other threads. */
-        spi_release(dev->spi);
-        return -1;
-    }
-
-    gpio_set(dev->cs);
+    spi_transfer_reg(dev->spi, dev->cs, addr, value);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
+
     return 0;
 }
 
@@ -292,9 +279,8 @@ static int lis3dh_write_reg(const lis3dh_t *dev, const lis3dh_reg_t reg, const u
  * @return                  0 on success
  * @return                  -1 on error
  */
-static inline int
-lis3dh_write_bits(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t mask,
-                  const uint8_t values)
+static inline int lis3dh_write_bits(const lis3dh_t *dev, const lis3dh_reg_t reg,
+                                    const uint8_t mask, const uint8_t values)
 {
     uint8_t tmp;
 
diff --git a/drivers/nrf24l01p/nrf24l01p.c b/drivers/nrf24l01p/nrf24l01p.c
index d82a5a1b0ec916ca425781ee551f339b2a0f290c..344a381b7abe4118d81081a3c208d46fd59d51b2 100644
--- a/drivers/nrf24l01p/nrf24l01p.c
+++ b/drivers/nrf24l01p/nrf24l01p.c
@@ -31,43 +31,34 @@
 #define DELAY_AFTER_FUNC_TICKS      (xtimer_ticks_from_usec(DELAY_AFTER_FUNC_US))
 #define DELAY_CHANGE_TXRX_TICKS     (xtimer_ticks_from_usec(DELAY_CHANGE_TXRX_US))
 
+#define SPI_MODE            SPI_MODE_0
+#define SPI_CLK             SPI_CLK_400KHZ
+
 int nrf24l01p_read_reg(nrf24l01p_t *dev, char reg, char *answer)
 {
-    int status;
-
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    status = spi_transfer_reg(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & reg)), CMD_NOP, answer);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    *answer = (char)spi_transfer_reg(dev->spi, dev->cs,
+                                     (CMD_R_REGISTER | (REGISTER_MASK & reg)),
+                                     CMD_NOP);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
     xtimer_spin(DELAY_AFTER_FUNC_TICKS);
-
-    return (status < 0) ? status : 0;
+    return 0;
 }
 
 int nrf24l01p_write_reg(nrf24l01p_t *dev, char reg, char write)
 {
-    int status;
-    char reg_content;
-
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    status = spi_transfer_reg(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & reg)), write, &reg_content);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    spi_transfer_reg(dev->spi, dev->cs,
+                     (CMD_W_REGISTER | (REGISTER_MASK & reg)), (uint8_t)write);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
     xtimer_spin(DELAY_AFTER_FUNC_TICKS);
-
-    return (status < 0) ? status : 0;
+    return 0;
 }
 
 
@@ -87,22 +78,17 @@ int nrf24l01p_init(nrf24l01p_t *dev, spi_t spi, gpio_t ce, gpio_t cs, gpio_t irq
     gpio_init(dev->ce, GPIO_OUT);
 
     /* Init CS pin */
-    gpio_init(dev->cs, GPIO_OUT);
-    gpio_set(dev->cs);
+    spi_init_cs(dev->spi, dev->cs);
 
     /* Init IRQ pin */
     gpio_init_int(dev->irq, GPIO_IN_PU, GPIO_FALLING, nrf24l01p_rx_cb, dev);
 
-
-    /* Init SPI */
-    spi_poweron(dev->spi);
-    spi_acquire(dev->spi);
-    status = spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, SPI_SPEED_400KHZ);
-    spi_release(dev->spi);
-
-    if (status < 0) {
-        return status;
+    /* Test the SPI connection */
+    if (spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK) != SPI_OK) {
+        DEBUG("error: unable to acquire SPI bus with given params\n");
+        return -1;
     }
+    spi_release(dev->spi);
 
     xtimer_spin(DELAY_AFTER_FUNC_TICKS);
 
@@ -237,20 +223,14 @@ void nrf24l01p_transmit(nrf24l01p_t *dev)
 
 int nrf24l01p_read_payload(nrf24l01p_t *dev, char *answer, unsigned int size)
 {
-    int status;
-
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    status = spi_transfer_regs(dev->spi, CMD_R_RX_PAYLOAD, 0, answer, size);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    spi_transfer_regs(dev->spi, dev->cs, CMD_R_RX_PAYLOAD, NULL, answer, size);
     xtimer_spin(DELAY_AFTER_FUNC_TICKS);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
-    return status;
+    return 0;
 }
 
 void nrf24l01p_register(nrf24l01p_t *dev, unsigned int *pid)
@@ -288,23 +268,16 @@ void nrf24l01p_stop(nrf24l01p_t *dev)
 
 int nrf24l01p_preload(nrf24l01p_t *dev, char *data, unsigned int size)
 {
-    int status;
-
     size = (size <= 32) ? size : 32;
 
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    status = spi_transfer_regs(dev->spi, CMD_W_TX_PAYLOAD, data, NULL, size);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    spi_transfer_regs(dev->spi, dev->cs, CMD_W_TX_PAYLOAD, data, NULL, size);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
     xtimer_spin(DELAY_AFTER_FUNC_TICKS);
-
-    return status;
+    return 0;
 }
 
 
@@ -395,27 +368,21 @@ int nrf24l01p_set_payload_width(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char
 
 int nrf24l01p_set_tx_address(nrf24l01p_t *dev, char *saddr, unsigned int length)
 {
-    int status;
-
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), saddr, NULL, length); /* address width is 5 byte */
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    spi_transfer_regs(dev->spi, dev->cs,
+                      (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)),
+                      saddr, NULL, length);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
     xtimer_spin(DELAY_AFTER_FUNC_TICKS);
 
-    return (status < 0) ? status : length;
+    return (int)length;
 }
 
 int nrf24l01p_set_tx_address_long(nrf24l01p_t *dev, uint64_t saddr, unsigned int length)
 {
-    int status;
-
     char buf[length];
 
     if (length <= INITIAL_ADDRESS_WIDTH) {
@@ -429,44 +396,32 @@ int nrf24l01p_set_tx_address_long(nrf24l01p_t *dev, uint64_t saddr, unsigned int
     }
 
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), buf, NULL, length); /* address width is 5 byte */
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    spi_transfer_regs(dev->spi, dev->cs,
+                      (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)),
+                      buf, NULL, length);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
     xtimer_spin(DELAY_AFTER_FUNC_TICKS);
-
-    return (status < 0) ? status : length;
+    return (int)length;
 }
 
 uint64_t nrf24l01p_get_tx_address_long(nrf24l01p_t *dev)
 {
-    int status;
     uint64_t saddr_64 = 0;
     char addr_array[INITIAL_ADDRESS_WIDTH];
 
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    status = spi_transfer_regs(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), 0, addr_array, INITIAL_ADDRESS_WIDTH); /* address width is 5 byte */
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    spi_transfer_regs(dev->spi, dev->cs,
+                      (CMD_R_REGISTER | (REGISTER_MASK & REG_TX_ADDR)),
+                      NULL, addr_array, INITIAL_ADDRESS_WIDTH);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
     xtimer_spin(DELAY_AFTER_FUNC_TICKS);
 
-    if (status < 0) {
-        return -1;
-    }
-
-    xtimer_spin(DELAY_AFTER_FUNC_TICKS);
-
     for (int i = 0; i < INITIAL_ADDRESS_WIDTH; i++) {
         saddr_64 |= (((uint64_t) addr_array[i]) << (8 * (INITIAL_ADDRESS_WIDTH - i - 1)));
     }
@@ -477,7 +432,6 @@ uint64_t nrf24l01p_get_tx_address_long(nrf24l01p_t *dev)
 
 int nrf24l01p_set_rx_address(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char *saddr, unsigned int length)
 {
-    int status;
     char pipe_addr;
 
     switch (pipe) {
@@ -510,12 +464,10 @@ int nrf24l01p_set_rx_address(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char *s
     }
 
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & pipe_addr)), saddr, NULL, length); /* address width is 5 byte */
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    spi_transfer_regs(dev->spi, dev->cs,
+                      (CMD_W_REGISTER | (REGISTER_MASK & pipe_addr)),
+                      saddr, NULL, length);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
@@ -523,7 +475,7 @@ int nrf24l01p_set_rx_address(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char *s
 
     /* Enable this pipe */
     nrf24l01p_enable_pipe(dev, pipe);
-    return (status < 0) ? status : length;
+    return (int)length;
 }
 
 int nrf24l01p_set_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, uint64_t saddr, unsigned int length)
@@ -546,7 +498,6 @@ int nrf24l01p_set_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, ui
 
 uint64_t nrf24l01p_get_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe)
 {
-    int status;
     char pipe_addr;
     uint64_t saddr_64 = 0;
 
@@ -582,19 +533,13 @@ uint64_t nrf24l01p_get_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pip
     }
 
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    status = spi_transfer_regs(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & pipe_addr)), 0, addr_array, INITIAL_ADDRESS_WIDTH); /* address width is 5 byte */
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    spi_transfer_regs(dev->spi, dev->cs,
+                      (CMD_R_REGISTER | (REGISTER_MASK & pipe_addr)),
+                      NULL, addr_array, INITIAL_ADDRESS_WIDTH);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
-    if (status < 0) {
-        return -1;
-    }
-
     xtimer_spin(DELAY_AFTER_FUNC_TICKS);
 
     for (int i = 0; i < INITIAL_ADDRESS_WIDTH; i++) {
@@ -635,14 +580,11 @@ int nrf24l01p_set_datarate(nrf24l01p_t *dev, nrf24l01p_dr_t dr)
 
 int nrf24l01p_get_status(nrf24l01p_t *dev)
 {
-    char status;
+    uint8_t status;
+
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    spi_transfer_byte(dev->spi, CMD_NOP, &status);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    status = spi_transfer_byte(dev->spi, dev->cs, false, CMD_NOP);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
@@ -971,42 +913,28 @@ int nrf24l01p_disable_all_auto_ack(nrf24l01p_t *dev)
 
 int nrf24l01p_flush_tx_fifo(nrf24l01p_t *dev)
 {
-    int status;
-    char reg_content;
-
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    status = spi_transfer_byte(dev->spi, CMD_FLUSH_TX, &reg_content);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    spi_transfer_byte(dev->spi, dev->cs, false, CMD_FLUSH_TX);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
     xtimer_spin(DELAY_AFTER_FUNC_TICKS);
 
-    return (status < 0) ? status : 0;
+    return 0;
 }
 
 int nrf24l01p_flush_rx_fifo(nrf24l01p_t *dev)
 {
-    int status;
-    char reg_content;
-
     /* Acquire exclusive access to the bus. */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    status = spi_transfer_byte(dev->spi, CMD_FLUSH_RX, &reg_content);
-    xtimer_spin(DELAY_CS_TOGGLE_TICKS);
-    gpio_set(dev->cs);
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+    spi_transfer_byte(dev->spi, dev->cs, false, CMD_FLUSH_RX);
     /* Release the bus for other threads. */
     spi_release(dev->spi);
 
     xtimer_spin(DELAY_AFTER_FUNC_TICKS);
 
-    return (status < 0) ? status : 0;
+    return 0;
 }
 
 void nrf24l01p_rx_cb(void *arg)
diff --git a/drivers/nvram_spi/nvram-spi.c b/drivers/nvram_spi/nvram-spi.c
index 9ed5ee664d9563b585ab870f42dd9044afe61492..6cba3f4fbce1141c312e8fb846567e868dfee7b3 100644
--- a/drivers/nvram_spi/nvram-spi.c
+++ b/drivers/nvram_spi/nvram-spi.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2015 Eistec AB
+ *               2016 Freie Universität Berlin
  *
  * This file is subject to the terms and conditions of the GNU Lesser General
  * Public License v2.1. See the file LICENSE in the top level directory for more
@@ -27,6 +28,7 @@
  * - Cypress/Ramtron FM25L04B.
  *
  * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  */
 
 typedef enum {
@@ -114,8 +116,9 @@ int nvram_spi_init(nvram_t *dev, nvram_spi_params_t *spi_params, size_t size)
     }
     dev->extra = spi_params;
 
-    gpio_init(spi_params->cs, GPIO_OUT);
-    gpio_set(spi_params->cs);
+    if (spi_init_cs(spi_params->spi, spi_params->cs) != SPI_OK) {
+        return -1;
+    }
 
     return 0;
 }
@@ -123,54 +126,37 @@ int nvram_spi_init(nvram_t *dev, nvram_spi_params_t *spi_params, size_t size)
 static int nvram_spi_write(nvram_t *dev, const uint8_t *src, uint32_t dst, size_t len)
 {
     nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra;
-    int status;
     union {
         uint32_t u32;
         char c[4];
     } addr;
+
     /* Address is expected by the device as big-endian, i.e. network byte order,
      * we utilize the network byte order macros here. */
     addr.u32 = HTONL(dst);
-    /* Acquire exclusive bus access */
-    spi_acquire(spi_dev->spi);
-    /* Assert CS */
-    gpio_clear(spi_dev->cs);
+
+    /* Acquire exclusive bus access while configuring clock and mode */
+    spi_acquire(spi_dev->spi, spi_dev->cs, SPI_MODE_0, spi_dev->clk);
     /* Enable writes */
-    status = spi_transfer_byte(spi_dev->spi, NVRAM_SPI_CMD_WREN, NULL);
-    if (status < 0)
-    {
-        return status;
-    }
-    /* Release CS */
-    gpio_set(spi_dev->cs);
+    spi_transfer_byte(spi_dev->spi, spi_dev->cs, false, NVRAM_SPI_CMD_WREN);
+    /* Make sure we have a minimum gap between transfers */
     xtimer_spin(NVRAM_SPI_CS_TOGGLE_TICKS);
-    /* Re-assert CS */
-    gpio_clear(spi_dev->cs);
     /* Write command and address */
-    status = spi_transfer_regs(spi_dev->spi, NVRAM_SPI_CMD_WRITE,
+    spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, NVRAM_SPI_CMD_WRITE);
+    spi_transfer_bytes(spi_dev->spi, spi_dev->cs, true,
                       &addr.c[sizeof(addr.c) - spi_dev->address_count], NULL,
                       spi_dev->address_count);
-    if (status < 0)
-    {
-        return status;
-    }
-    /* Keep holding CS and write data */
-    status = spi_transfer_bytes(spi_dev->spi, (char *)src, NULL, len);
-    if (status < 0)
-    {
-        return status;
-    }
-    /* Release CS */
-    gpio_set(spi_dev->cs);
+    /* Write data (we still hold the CS line low in between) */
+    spi_transfer_bytes(spi_dev->spi, spi_dev->cs, false, src, NULL, len);
     /* Release exclusive bus access */
     spi_release(spi_dev->spi);
-    return status;
+
+    return (int)len;
 }
 
 static int nvram_spi_read(nvram_t *dev, uint8_t *dst, uint32_t src, size_t len)
 {
     nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra;
-    int status;
     union {
         uint32_t u32;
         char c[4];
@@ -178,40 +164,31 @@ static int nvram_spi_read(nvram_t *dev, uint8_t *dst, uint32_t src, size_t len)
     /* Address is expected by the device as big-endian, i.e. network byte order,
      * we utilize the network byte order macros here. */
     addr.u32 = HTONL(src);
-    /* Acquire exclusive bus access */
-    spi_acquire(spi_dev->spi);
-    /* Assert CS */
-    gpio_clear(spi_dev->cs);
+
+    /* Acquire exclusive bus access while configuring clock and mode */
+    spi_acquire(spi_dev->spi, spi_dev->cs, SPI_MODE_0, spi_dev->clk);
     /* Write command and address */
-    status = spi_transfer_regs(spi_dev->spi, NVRAM_SPI_CMD_READ,
+    spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, NVRAM_SPI_CMD_READ);
+    spi_transfer_bytes(spi_dev->spi, spi_dev->cs, true,
                                &addr.c[sizeof(addr.c) - spi_dev->address_count],
                                NULL, spi_dev->address_count);
-    if (status < 0)
-    {
-        return status;
-    }
-    /* Keep holding CS and read data */
-    status = spi_transfer_bytes(spi_dev->spi, NULL, (char *)dst, len);
-    if (status < 0)
-    {
-        return status;
-    }
-    /* Release CS */
-    gpio_set(spi_dev->cs);
+    /* Read data (while still holding the CS line active) */
+    spi_transfer_bytes(spi_dev->spi, spi_dev->cs, false, NULL, dst, len);
     /* Release exclusive bus access */
     spi_release(spi_dev->spi);
+
     /* status contains the number of bytes actually read from the SPI bus. */
-    return status;
+    return (int)len;
 }
 
 
 static int nvram_spi_write_9bit_addr(nvram_t *dev, const uint8_t *src, uint32_t dst, size_t len)
 {
     nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra;
-    int status;
     uint8_t cmd;
     uint8_t addr;
     cmd = NVRAM_SPI_CMD_WRITE;
+
     /* The upper address bit is mixed into the command byte on certain devices,
      * probably just to save a byte in the SPI transfer protocol. */
     if (dst > 0xff) {
@@ -219,42 +196,30 @@ static int nvram_spi_write_9bit_addr(nvram_t *dev, const uint8_t *src, uint32_t
     }
     /* LSB of address */
     addr = (dst & 0xff);
-    spi_acquire(spi_dev->spi);
-    gpio_clear(spi_dev->cs);
+
+    spi_acquire(spi_dev->spi, spi_dev->cs, SPI_MODE_0, spi_dev->clk);
     /* Enable writes */
-    status = spi_transfer_byte(spi_dev->spi, NVRAM_SPI_CMD_WREN, NULL);
-    if (status < 0)
-    {
-        return status;
-    }
-    gpio_set(spi_dev->cs);
+    spi_transfer_byte(spi_dev->spi, spi_dev->cs, false, NVRAM_SPI_CMD_WREN);
+    /* Insert needed delay between transactions */
     xtimer_spin(NVRAM_SPI_CS_TOGGLE_TICKS);
-    gpio_clear(spi_dev->cs);
     /* Write command and address */
-    status = spi_transfer_reg(spi_dev->spi, cmd, addr, NULL);
-    if (status < 0)
-    {
-        return status;
-    }
+    spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, cmd);
+    spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, addr);
     /* Keep holding CS and write data */
-    status = spi_transfer_bytes(spi_dev->spi, (char *)src, NULL, len);
-    if (status < 0)
-    {
-        return status;
-    }
-    gpio_set(spi_dev->cs);
+    spi_transfer_bytes(spi_dev->spi, spi_dev->cs, false, src, NULL, len);
     spi_release(spi_dev->spi);
+
     /* status contains the number of bytes actually written to the SPI bus. */
-    return status;
+    return (int)len;
 }
 
 static int nvram_spi_read_9bit_addr(nvram_t *dev, uint8_t *dst, uint32_t src, size_t len)
 {
     nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra;
-    int status;
     uint8_t cmd;
     uint8_t addr;
     cmd = NVRAM_SPI_CMD_READ;
+
     /* The upper address bit is mixed into the command byte on certain devices,
      * probably just to save a byte in the SPI transfer protocol. */
     if (src > 0xff) {
@@ -262,24 +227,17 @@ static int nvram_spi_read_9bit_addr(nvram_t *dev, uint8_t *dst, uint32_t src, si
     }
     /* LSB of address */
     addr = (src & 0xff);
-    spi_acquire(spi_dev->spi);
-    gpio_clear(spi_dev->cs);
+
+    spi_acquire(spi_dev->spi, spi_dev->cs, SPI_MODE_0, spi_dev->clk);
     /* Write command and address */
-    status = spi_transfer_reg(spi_dev->spi, (char)cmd, addr, NULL);
-    if (status < 0)
-    {
-        return status;
-    }
+    spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, cmd);
+    spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, addr);
     /* Keep holding CS and read data */
-    status = spi_transfer_bytes(spi_dev->spi, NULL, (char *)dst, len);
-    if (status < 0)
-    {
-        return status;
-    }
-    gpio_set(spi_dev->cs);
+    spi_transfer_bytes(spi_dev->spi, spi_dev->cs, false, NULL, dst, len);
     spi_release(spi_dev->spi);
+
     /* status contains the number of bytes actually read from the SPI bus. */
-    return status;
+    return (int)len;
 }
 
 /** @} */
diff --git a/drivers/pcd8544/pcd8544.c b/drivers/pcd8544/pcd8544.c
index 208af5660f8a5d2096d0a26d4cd27612b2144513..daa643b446cb79cf6e24a34836f12cd4cb0937b9 100644
--- a/drivers/pcd8544/pcd8544.c
+++ b/drivers/pcd8544/pcd8544.c
@@ -32,6 +32,9 @@
 #define ASCII_MAX           0x7e    /**< end of ASCII table */
 #define CHAR_WIDTH          (6U)    /**< pixel width of a single character */
 
+#define SPI_CLK             (SPI_CLK_1MHZ)
+#define SPI_MODE            (SPI_MODE_0)
+
 static const uint8_t _ascii[][5] = {
     {0x00, 0x00, 0x00, 0x00, 0x00},/* 20 SPACE*/
     {0x00, 0x00, 0x5f, 0x00, 0x00},/* 21 ! */
@@ -196,17 +199,22 @@ static const char _riot[] = {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
+static inline void lock(pcd8544_t *dev)
+{
+    spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK);
+}
+
+static inline void done(pcd8544_t *dev)
+{
+    spi_release(dev->spi);
+}
 
 static void _write(pcd8544_t *dev, uint8_t is_data, char data)
 {
     /* set command or data mode */
     gpio_write(dev->mode, is_data);
     /* write byte to LCD */
-    spi_acquire(dev->spi);
-    gpio_clear(dev->cs);
-    spi_transfer_byte(dev->spi, data, 0);
-    gpio_set(dev->cs);
-    spi_release(dev->spi);
+    spi_transfer_bytes(dev->spi, dev->cs, false, (uint8_t *)&data, NULL, 1);
 }
 
 static inline void _set_x(pcd8544_t *dev, uint8_t x)
@@ -231,15 +239,13 @@ int pcd8544_init(pcd8544_t *dev, spi_t spi, gpio_t cs, gpio_t reset, gpio_t mode
     DEBUG("done setting dev members\n");
 
     /* initialze pins */
-    gpio_init(cs, GPIO_OUT);
     gpio_init(reset, GPIO_OUT);
     gpio_init(mode, GPIO_OUT);
     DEBUG("done with gpios\n");
     /* clear CS line */
-    gpio_set(cs);
     DEBUG("done clearing CS line\n");
     /* initialize SPI */
-    spi_init_master(spi, SPI_CONF_FIRST_RISING, SPI_SPEED_1MHZ);
+    spi_init_cs(spi, (spi_cs_t)cs);
     DEBUG("done initializing SPI master\n");
     /* reset display */
     gpio_clear(reset);
@@ -253,8 +259,10 @@ int pcd8544_init(pcd8544_t *dev, spi_t spi, gpio_t cs, gpio_t reset, gpio_t mode
     pcd8544_set_bias(dev, PCD8544_DEFAULT_BIAS);
     pcd8544_set_tempcoef(dev, PCD8544_DEFAULT_TEMPCOEF);
     /* enable display */
+    lock(dev);
     _write(dev, MODE_CMD, CMD_ENABLE_H);
     _write(dev, MODE_CMD, CMD_MODE_NORMAL);
+    done(dev);
     return 0;
 }
 
@@ -263,9 +271,11 @@ void pcd8544_set_contrast(pcd8544_t *dev, uint8_t contrast)
     if (contrast > CONTRAST_MAX) {
         contrast = CONTRAST_MAX;
     }
+    lock(dev);
     _write(dev, MODE_CMD, CMD_EXTENDED);
     _write(dev, MODE_CMD, (CMD_EXT_CONTRAST | contrast));
     _write(dev, MODE_CMD, CMD_ENABLE_H);
+    done(dev);
 }
 
 void pcd8544_set_tempcoef(pcd8544_t *dev, uint8_t coef)
@@ -273,9 +283,11 @@ void pcd8544_set_tempcoef(pcd8544_t *dev, uint8_t coef)
     if (coef > TEMP_MAX) {
         coef = TEMP_MAX;
     }
+    lock(dev);
     _write(dev, MODE_CMD, CMD_EXTENDED);
     _write(dev, MODE_CMD, (CMD_EXT_TEMP | coef));
     _write(dev, MODE_CMD, CMD_ENABLE_H);
+    done(dev);
 }
 
 void pcd8544_set_bias(pcd8544_t *dev, uint8_t bias)
@@ -283,9 +295,11 @@ void pcd8544_set_bias(pcd8544_t *dev, uint8_t bias)
     if (bias > BIAS_MAX) {
         bias = BIAS_MAX;
     }
+    lock(dev);
     _write(dev, MODE_CMD, CMD_EXTENDED);
     _write(dev, MODE_CMD, (CMD_EXT_BIAS | bias));
     _write(dev, MODE_CMD, CMD_ENABLE_H);
+    done(dev);
 }
 
 void pcd8544_riot(pcd8544_t *dev)
@@ -296,12 +310,14 @@ void pcd8544_riot(pcd8544_t *dev)
 void pcd8544_write_img(pcd8544_t *dev, const char img[])
 {
     /* set initial position */
+    lock(dev);
     _set_x(dev, 0);
     _set_y(dev, 0);
     /* write image data to display */
     for (int i = 0; i < (PCD8544_RES_X * PCD8544_RES_Y / 8); i++) {
         _write(dev, MODE_DTA, img[i]);
     }
+    done(dev);
 }
 
 void pcd8544_write_c(pcd8544_t *dev, uint8_t x, uint8_t y, char c)
@@ -311,6 +327,7 @@ void pcd8544_write_c(pcd8544_t *dev, uint8_t x, uint8_t y, char c)
         return ;
     }
     /* set position */
+    lock(dev);
     _set_x(dev, x * CHAR_WIDTH);
     _set_y(dev, y);
     /* write char */
@@ -318,6 +335,7 @@ void pcd8544_write_c(pcd8544_t *dev, uint8_t x, uint8_t y, char c)
         _write(dev, MODE_DTA, _ascii[c - ASCII_MIN][i]);
     }
     _write(dev, MODE_DTA, 0x00);
+    done(dev);
 }
 
 void pcd8544_write_s(pcd8544_t *dev, uint8_t x, uint8_t y, const char *s)
@@ -329,15 +347,18 @@ void pcd8544_write_s(pcd8544_t *dev, uint8_t x, uint8_t y, const char *s)
 
 void pcd8544_clear(pcd8544_t *dev)
 {
+    lock(dev);
     _set_x(dev, 0);
     _set_y(dev, 0);
     for (int i = 0; i < PCD8544_RES_X * PCD8544_ROWS; i++) {
         _write(dev, MODE_DTA, 0x00);
     }
+    done(dev);
 }
 
 void pcd8544_invert(pcd8544_t *dev)
 {
+    lock(dev);
     if (dev->inverted) {
         _write(dev, MODE_CMD, CMD_MODE_NORMAL);
     }
@@ -345,6 +366,7 @@ void pcd8544_invert(pcd8544_t *dev)
         _write(dev, MODE_CMD, CMD_MODE_INVERSE);
     }
     dev->inverted ^= 0x01;
+    done(dev);
 }
 
 int pcd8544_is_inverted(pcd8544_t *dev)
@@ -354,10 +376,14 @@ int pcd8544_is_inverted(pcd8544_t *dev)
 
 void pcd8544_poweron(pcd8544_t *dev)
 {
+    lock(dev);
     _write(dev, MODE_CMD, CMD_ENABLE_H);
+    done(dev);
 }
 
 void pcd8544_poweroff(pcd8544_t *dev)
 {
+    lock(dev);
     _write(dev, MODE_CMD, CMD_DISABLE);
+    done(dev);
 }
diff --git a/drivers/periph_common/init.c b/drivers/periph_common/init.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c13f15120d558c0a6e40fb78c70ceff008bd1b6
--- /dev/null
+++ b/drivers/periph_common/init.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     drivers_periph_init
+ * @{
+ *
+ * @file
+ * @brief       Common static peripheral driver initialization implementation
+ *
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ *
+ * @}
+ */
+
+#include "periph/spi.h"
+
+void periph_init(void)
+{
+    /* initialize configured SPI devices */
+#ifdef SPI_NUMOF
+    for (unsigned i = 0; i < SPI_NUMOF; i++) {
+        spi_init(SPI_DEV(i));
+    }
+#endif
+}
diff --git a/drivers/periph_common/spi.c b/drivers/periph_common/spi.c
index ec0747ef1420d2d7b81ffe9cc9b542b2484d0b0b..bc15a3016cce21d91b21fe671b86088fc08b84b2 100644
--- a/drivers/periph_common/spi.c
+++ b/drivers/periph_common/spi.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
+ *               2016 Freie Universität Berlin
  *
  * This file is subject to the terms and conditions of the GNU Lesser General
  * Public License v2.1. See the file LICENSE in the top level directory for more
@@ -14,6 +15,7 @@
  * @brief       common SPI function fallback implementations
  *
  * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
  *
  * @}
  */
@@ -22,76 +24,49 @@
 #include "board.h"
 #include "cpu.h"
 #include "periph/spi.h"
-#include "periph_cpu.h"
 
-#if SPI_NUMOF
+#ifdef SPI_NUMOF
 
-#ifdef PERIPH_SPI_NEEDS_TRANSFER_BYTES
-int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length)
+#ifdef PERIPH_SPI_NEEDS_INIT_CS
+int spi_init_cs(spi_t bus, spi_cs_t cs)
 {
-    int trans_ret;
-    unsigned trans_bytes = 0;
-    char in_temp;
-
-    for (trans_bytes = 0; trans_bytes < length; trans_bytes++) {
-        if (out != NULL) {
-            trans_ret = spi_transfer_byte(dev, out[trans_bytes], &in_temp);
-        }
-        else {
-            trans_ret = spi_transfer_byte(dev, 0, &in_temp);
-        }
-        if (trans_ret < 0) {
-            return -1;
-        }
-        if (in != NULL) {
-            in[trans_bytes] = in_temp;
-        }
+    if (bus >= SPI_NUMOF) {
+        return SPI_NODEV;
+    }
+    if ((cs == SPI_CS_UNDEF) || (cs == GPIO_UNDEF)) {
+        return SPI_NOCS;
     }
 
-    return trans_bytes;
+    gpio_init((gpio_t)cs, GPIO_OUT);
+    gpio_set((gpio_t)cs);
+
+    return SPI_OK;
 }
 #endif
 
 #ifdef PERIPH_SPI_NEEDS_TRANSFER_BYTE
-int spi_transfer_byte(spi_t dev, char out, char *in)
+uint8_t spi_transfer_byte(spi_t bus, spi_cs_t cs, bool cont, uint8_t out)
 {
-    return spi_transfer_bytes(dev, &out, in, 1);
+    uint8_t in;
+    spi_transfer_bytes(bus, cs, cont, &out, &in, 1);
+    return in;
 }
 #endif
 
 #ifdef PERIPH_SPI_NEEDS_TRANSFER_REG
-int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in)
+uint8_t spi_transfer_reg(spi_t bus, spi_cs_t cs, uint8_t reg, uint8_t out)
 {
-    int trans_ret;
-
-    trans_ret = spi_transfer_byte(dev, reg, in);
-    if (trans_ret < 0) {
-        return -1;
-    }
-    trans_ret = spi_transfer_byte(dev, out, in);
-    if (trans_ret < 0) {
-        return -1;
-    }
-
-    return 1;
+    spi_transfer_bytes(bus, cs, true, &reg, NULL, 1);
+    return spi_transfer_byte(bus, cs, false, out);
 }
 #endif
 
 #ifdef PERIPH_SPI_NEEDS_TRANSFER_REGS
-int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length)
+void spi_transfer_regs(spi_t bus, spi_cs_t cs,
+                       uint8_t reg, const void *out, void *in, size_t len)
 {
-    int trans_ret;
-
-    trans_ret = spi_transfer_byte(dev, reg, in);
-    if (trans_ret < 0) {
-        return -1;
-    }
-    trans_ret = spi_transfer_bytes(dev, out, in, length);
-    if (trans_ret < 0) {
-        return -1;
-    }
-
-    return trans_ret;
+    spi_transfer_bytes(bus, cs, true, &reg, NULL, 1);
+    spi_transfer_bytes(bus, cs, false, out, in, len);
 }
 #endif
 
diff --git a/drivers/sdcard_spi/include/sdcard_spi_internal.h b/drivers/sdcard_spi/include/sdcard_spi_internal.h
index 5ca30cfd205e365dd35f220d352df981ae27b5b9..dfc428891c8b5d154debc3a67983e4cb57e73e8b 100644
--- a/drivers/sdcard_spi/include/sdcard_spi_internal.h
+++ b/drivers/sdcard_spi/include/sdcard_spi_internal.h
@@ -139,13 +139,13 @@ extern "C" {
 /* memory capacity in bytes = (C_SIZE+1) * SD_CSD_V2_C_SIZE_BLOCK_MULT * BLOCK_LEN */
 #define SD_CSD_V2_C_SIZE_BLOCK_MULT 1024
 
-#define SD_CARD_SPI_MODE SPI_CONF_FIRST_RISING
+#define SD_CARD_SPI_MODE SPI_MODE_0
 
 /* this speed setting is only used while the init procedure is performed */
-#define SD_CARD_SPI_SPEED_PREINIT SPI_SPEED_400KHZ
+#define SD_CARD_SPI_SPEED_PREINIT SPI_CLK_400KHZ
 
 /* after init procedure is finished the driver auto sets the card to this speed */
-#define SD_CARD_SPI_SPEED_POSTINIT SPI_SPEED_10MHZ
+#define SD_CARD_SPI_SPEED_POSTINIT SPI_CLK_10MHZ
 
 #define SD_CARD_DUMMY_BYTE 0xFF
 
diff --git a/drivers/sdcard_spi/include/sdcard_spi_params.h b/drivers/sdcard_spi/include/sdcard_spi_params.h
index 0f46304054ff4335a3ceb2ab8e563a7f00f98908..36a07e1c5572f43b0a177ab439a339a0acd5362b 100644
--- a/drivers/sdcard_spi/include/sdcard_spi_params.h
+++ b/drivers/sdcard_spi/include/sdcard_spi_params.h
@@ -30,7 +30,7 @@ extern "C" {
  * @{
  */
 #ifndef SDCARD_SPI_PARAM_SPI
-#define SDCARD_SPI_PARAM_SPI         (SPI_0)
+#define SDCARD_SPI_PARAM_SPI         (SPI_DEV(0))
 #endif
 #ifndef SDCARD_SPI_PARAM_CS
 #define SDCARD_SPI_PARAM_CS          (GPIO_PIN(2,4))
diff --git a/drivers/sdcard_spi/sdcard_spi.c b/drivers/sdcard_spi/sdcard_spi.c
index ceeff4d204457b2bfa2c6c202712a6547d9807c7..d61c3c0e9bee6933da4abda4daa606e866768932 100644
--- a/drivers/sdcard_spi/sdcard_spi.c
+++ b/drivers/sdcard_spi/sdcard_spi.c
@@ -65,6 +65,7 @@ int sdcard_spi_init(sdcard_spi_t *card, const sdcard_spi_params_t *params)
 {
     sd_init_fsm_state_t state = SD_INIT_START;
     memcpy(&card->params, params, sizeof(sdcard_spi_params_t));
+    card->spi_clk = SD_CARD_SPI_SPEED_PREINIT;
 
     do {
         state = _init_sd_fsm_step(card, state);
@@ -88,7 +89,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
             if ((gpio_init(card->params.mosi, GPIO_OUT) == 0) &&
                 (gpio_init(card->params.clk,  GPIO_OUT) == 0) &&
                 (gpio_init(card->params.cs,   GPIO_OUT) == 0) &&
-                (gpio_init(card->params.miso, GPIO_IN) == 0) &&
+                (gpio_init(card->params.miso, GPIO_IN_PU) == 0) &&
                 ( (card->params.power == GPIO_UNDEF) ||
                   (gpio_init(card->params.power, GPIO_OUT) == 0)) ) {
 
@@ -125,43 +126,37 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
             DEBUG("SD_INIT_SEND_CMD0\n");
 
             gpio_clear(card->params.mosi);
-            gpio_clear(card->params.cs);   /* select sdcard for cmd0 */
 
             /* use soft-spi to perform init command to allow use of internal pull-ups on miso */
             _dyn_spi_rxtx_byte = &_sw_spi_rxtx_byte;
 
-            _select_card_spi(card);
+            /* select sdcard for cmd0 */
+            gpio_clear(card->params.cs);
             char cmd0_r1 = sdcard_spi_send_cmd(card, SD_CMD_0, SD_CMD_NO_ARG, INIT_CMD0_RETRY_CNT);
+            gpio_set(card->params.cs);
+
             if (R1_VALID(cmd0_r1) && !R1_ERROR(cmd0_r1) && R1_IDLE_BIT_SET(cmd0_r1)) {
                 DEBUG("CMD0: [OK]\n");
-                _unselect_card_spi(card);
-
-                if (spi_init_master(card->params.spi_dev, SD_CARD_SPI_MODE,
-                                    SD_CARD_SPI_SPEED_PREINIT) == 0) {
-                    DEBUG("spi_init_master(): [OK]\n");
-
-                    /* switch to hw spi since sd card is now in real spi mode */
-                    _dyn_spi_rxtx_byte = &_hw_spi_rxtx_byte;
-                    return SD_INIT_ENABLE_CRC;
-                }
 
-                DEBUG("spi_init_master(): [ERROR]\n");
-                return SD_INIT_CARD_UNKNOWN;
+                /* give control over SPI pins back to HW SPI device */
+                spi_init_pins(card->params.spi_dev);
+                /* switch to HW SPI since SD card is now in real SPI mode */
+                _dyn_spi_rxtx_byte = &_hw_spi_rxtx_byte;
+                return SD_INIT_ENABLE_CRC;
             }
 
-            _unselect_card_spi(card);
             return SD_INIT_CARD_UNKNOWN;
 
         case SD_INIT_ENABLE_CRC:
             DEBUG("SD_INIT_ENABLE_CRC\n");
             _select_card_spi(card);
             char r1 = sdcard_spi_send_cmd(card, SD_CMD_59, SD_CMD_59_ARG_EN, INIT_CMD_RETRY_CNT);
+            _unselect_card_spi(card);
+
             if (R1_VALID(r1) && !R1_ERROR(r1)) {
                 DEBUG("CMD59: [OK]\n");
-                _unselect_card_spi(card);
                 return SD_INIT_SEND_CMD8;
             }
-            _unselect_card_spi(card);
             return SD_INIT_CARD_UNKNOWN;
 
         case SD_INIT_SEND_CMD8:
@@ -327,15 +322,9 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
 
         case SD_INIT_SET_MAX_SPI_SPEED:
             DEBUG("SD_INIT_SET_MAX_SPI_SPEED\n");
-            if (spi_init_master(card->params.spi_dev, SD_CARD_SPI_MODE,
-                                SD_CARD_SPI_SPEED_POSTINIT) == 0) {
-                DEBUG("SD_INIT_SET_MAX_SPI_SPEED: [OK]\n");
-                return SD_INIT_FINISH;
-            }
-            else {
-                DEBUG("SD_INIT_SET_MAX_SPI_SPEED: [ERROR]\n");
-                return SD_INIT_CARD_UNKNOWN;
-            }
+            card->spi_clk = SD_CARD_SPI_SPEED_POSTINIT;
+            DEBUG("SD_INIT_SET_MAX_SPI_SPEED: [OK]\n");
+            return SD_INIT_FINISH;
 
         default:
             DEBUG("SD-INIT-FSM REACHED INVALID STATE!\n");
@@ -350,18 +339,14 @@ static inline bool _wait_for_token(sdcard_spi_t *card, char token, int32_t max_r
 
     do {
         char read_byte = 0;
-        if (spi_transfer_byte(card->params.spi_dev, SD_CARD_DUMMY_BYTE, &read_byte) == 1) {
-            if (read_byte == token) {
-                DEBUG("_wait_for_token: [MATCH]\n");
-                return true;
-            }
-            else {
-                DEBUG("_wait_for_token: [NO MATCH] (0x%02x)\n", read_byte);
-            }
+        read_byte = spi_transfer_byte(card->params.spi_dev, GPIO_UNDEF, true,
+                                      SD_CARD_DUMMY_BYTE);
+        if (read_byte == token) {
+            DEBUG("_wait_for_token: [MATCH]\n");
+            return true;
         }
         else {
-            DEBUG("spi_transfer_byte: [FAILED]\n");
-            return false;
+            DEBUG("_wait_for_token: [NO MATCH] (0x%02x)\n", read_byte);
         }
 
         tried++;
@@ -557,7 +542,8 @@ static inline char _wait_for_r1(sdcard_spi_t *card, int32_t max_retries)
 
 void _select_card_spi(sdcard_spi_t *card)
 {
-    spi_acquire(card->params.spi_dev);
+    spi_acquire(card->params.spi_dev, GPIO_UNDEF,
+                SD_CARD_SPI_MODE, card->spi_clk);
     gpio_clear(card->params.cs);
 }
 
@@ -587,7 +573,8 @@ static inline int _sw_spi_rxtx_byte(sdcard_spi_t *card, char out, char *in){
 }
 
 static inline int _hw_spi_rxtx_byte(sdcard_spi_t *card, char out, char *in){
-    return spi_transfer_byte(card->params.spi_dev, out, in);
+    *in = spi_transfer_byte(card->params.spi_dev, GPIO_UNDEF, true, out);
+    return 1;
 }
 
 static inline int _transfer_bytes(sdcard_spi_t *card, char *out, char *in, unsigned int length){
@@ -720,66 +707,54 @@ int sdcard_spi_read_blocks(sdcard_spi_t *card, int blockaddr, char *data, int bl
 static sd_rw_response_t _write_data_packet(sdcard_spi_t *card, char token, char *data, int size)
 {
 
-    if (spi_transfer_byte(card->params.spi_dev, token, 0) == 1) {
+    spi_transfer_byte(card->params.spi_dev, GPIO_UNDEF, true, token);
 
-        if (_transfer_bytes(card, data, 0, size) == size) {
+    if (_transfer_bytes(card, data, 0, size) == size) {
 
-            uint16_t data__crc_16 = _crc_16(data, size);
-            char crc[sizeof(uint16_t)] = { data__crc_16 >> 8, data__crc_16 & 0xFF };
+        uint16_t data__crc_16 = _crc_16(data, size);
+        char crc[sizeof(uint16_t)] = { data__crc_16 >> 8, data__crc_16 & 0xFF };
 
-            if (_transfer_bytes(card, crc, 0, sizeof(crc)) == sizeof(crc)) {
+        if (_transfer_bytes(card, crc, 0, sizeof(crc)) == sizeof(crc)) {
 
-                char data_response;
-
-                if (spi_transfer_byte(card->params.spi_dev, SD_CARD_DUMMY_BYTE,
-                                      &data_response) == 1) {
-
-                    DEBUG("_write_data_packet: DATA_RESPONSE: 0x%02x\n", data_response);
+            char data_response;
 
-                    if (DATA_RESPONSE_IS_VALID(data_response)) {
+            data_response = (char)spi_transfer_byte(card->params.spi_dev, GPIO_UNDEF,
+                                                    true, SD_CARD_DUMMY_BYTE);
 
-                        if (DATA_RESPONSE_ACCEPTED(data_response)) {
-                            DEBUG("_write_data_packet: DATA_RESPONSE: [OK]\n");
-                            return SD_RW_OK;
-                        }
-                        else {
+            DEBUG("_write_data_packet: DATA_RESPONSE: 0x%02x\n", data_response);
 
-                            if (DATA_RESPONSE_WRITE_ERR(data_response)) {
-                                DEBUG("_write_data_packet: DATA_RESPONSE: [WRITE_ERROR]\n");
-                            }
+            if (DATA_RESPONSE_IS_VALID(data_response)) {
 
-                            if (DATA_RESPONSE_CRC_ERR(data_response)) {
-                                DEBUG("_write_data_packet: DATA_RESPONSE: [CRC_ERROR]\n");
-                            }
-                            return SD_RW_WRITE_ERROR;
-                        }
+                if (DATA_RESPONSE_ACCEPTED(data_response)) {
+                    DEBUG("_write_data_packet: DATA_RESPONSE: [OK]\n");
+                    return SD_RW_OK;
+                }
+                else {
 
+                    if (DATA_RESPONSE_WRITE_ERR(data_response)) {
+                        DEBUG("_write_data_packet: DATA_RESPONSE: [WRITE_ERROR]\n");
                     }
-                    else {
-                        DEBUG("_write_data_packet: DATA_RESPONSE invalid\n");
-                        return SD_RW_RX_TX_ERROR;
-                    }
-
 
+                    if (DATA_RESPONSE_CRC_ERR(data_response)) {
+                        DEBUG("_write_data_packet: DATA_RESPONSE: [CRC_ERROR]\n");
+                    }
+                    return SD_RW_WRITE_ERROR;
                 }
-                else {
-                    DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting data response)\n");
-                    return SD_RW_RX_TX_ERROR;
-                }
+
             }
             else {
-                DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting CRC16)\n");
+                DEBUG("_write_data_packet: DATA_RESPONSE invalid\n");
                 return SD_RW_RX_TX_ERROR;
             }
+
         }
         else {
-            DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting payload)\n");
+            DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting CRC16)\n");
             return SD_RW_RX_TX_ERROR;
         }
-
     }
     else {
-        DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting token)\n");
+        DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting payload)\n");
         return SD_RW_RX_TX_ERROR;
     }
 }
@@ -823,16 +798,10 @@ static inline int _write_blocks(sdcard_spi_t *card, char cmd_idx, int bladdr, ch
 
         /* if this is a multi-block write it is needed to issue a stop command*/
         if (cmd_idx == SD_CMD_25) {
-            char data_response;
-            if (spi_transfer_byte(card->params.spi_dev, SD_DATA_TOKEN_CMD_25_STOP,
-                                  &data_response) == 1) {
-                DEBUG("_write_blocks: write multi (%d) blocks: [OK]\n", nbl);
-            }
-            else {
-                DEBUG("_write_blocks: spi_transfer_byte: [FAILED] (SD_DATA_TOKEN_CMD_25_STOP)\n");
-                _unselect_card_spi(card);
-                *state = SD_RW_RX_TX_ERROR;
-            }
+            spi_transfer_byte(card->params.spi_dev, GPIO_UNDEF, true,
+                              SD_DATA_TOKEN_CMD_25_STOP);
+            DEBUG("_write_blocks: write multi (%d) blocks: [OK]\n", nbl);
+
             _send_dummy_byte(card); //sd card needs dummy byte before we can wait for not-busy state
             if (!_wait_for_not_busy(card, SD_WAIT_FOR_NOT_BUSY_CNT)) {
                 _unselect_card_spi(card);
diff --git a/drivers/w5100/include/w5100_params.h b/drivers/w5100/include/w5100_params.h
index 315bfd5b681f90b37dcf51d2c424811f82370cf4..10ea7fb903a379546a47f07a3a0966c88f8d6b0c 100644
--- a/drivers/w5100/include/w5100_params.h
+++ b/drivers/w5100/include/w5100_params.h
@@ -28,10 +28,10 @@ extern "C" {
  * @{
  */
 #ifndef W5100_PARAM_SPI
-#define W5100_PARAM_SPI         (SPI_0)
+#define W5100_PARAM_SPI         (SPI_DEV(0))
 #endif
-#ifndef W5100_PARAM_SPI_SPEED
-#define W5100_PARAM_SPI_SPEED   (SPI_SPEED_5MHZ)
+#ifndef W5100_PARAM_SPI_CLK
+#define W5100_PARAM_SPI_CLK     (SPI_CLK_5MHZ)
 #endif
 #ifndef W5100_PARAM_CS
 #define W5100_PARAM_CS          (GPIO_PIN(0, 0))
@@ -46,10 +46,10 @@ extern "C" {
  */
 static const  w5100_params_t w5100_params[] = {
     {
-        .spi       = W5100_PARAM_SPI,
-        .spi_speed = W5100_PARAM_SPI_SPEED,
-        .cs        = W5100_PARAM_CS,
-        .evt       = W5100_PARAM_EVT
+        .spi = W5100_PARAM_SPI,
+        .clk = W5100_PARAM_SPI_CLK,
+        .cs  = W5100_PARAM_CS,
+        .evt = W5100_PARAM_EVT
     },
 };
 /** @} */
diff --git a/drivers/w5100/w5100.c b/drivers/w5100/w5100.c
index af958da9e8b24537ebb5178240981bab03b939c4..443d61883f2b88654e86b35edd5f2ee1766cf084 100644
--- a/drivers/w5100/w5100.c
+++ b/drivers/w5100/w5100.c
@@ -35,7 +35,7 @@
 #include "debug.h"
 
 
-#define SPI_CONF            SPI_CONF_FIRST_RISING
+#define SPI_CONF            SPI_MODE_0
 #define RMSR_DEFAULT_VALUE  (0x55)
 
 #define S0_MEMSIZE          (0x2000)
@@ -48,25 +48,26 @@ static const netdev2_driver_t netdev2_driver_w5100;
 static inline void send_addr(w5100_t *dev, uint16_t addr)
 {
 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-    spi_transfer_byte(dev->p.spi, (addr >> 8), NULL);
-    spi_transfer_byte(dev->p.spi, (addr & 0xff), NULL);
+    spi_transfer_byte(dev->p.spi, dev->p.cs, true, (addr >> 8));
+    spi_transfer_byte(dev->p.spi, dev->p.cs, true, (addr & 0xff));
 #else
-    spi_transfer_byte(dev->p.spi, (addr & 0xff), NULL);
-    spi_transfer_byte(dev->p.spi, (addr >> 8), NULL);
+    spi_transfer_byte(dev->p.spi, dev->p.cs, true, (addr & 0xff));
+    spi_transfer_byte(dev->p.spi, dev->p.cs, true, (addr >> 8));
 #endif
 }
 
 static uint8_t rreg(w5100_t *dev, uint16_t reg)
 {
-    uint8_t data;
-
-    gpio_clear(dev->p.cs);
-    spi_transfer_byte(dev->p.spi, CMD_READ, NULL);
+    spi_transfer_byte(dev->p.spi, dev->p.cs, true, CMD_READ);
     send_addr(dev, reg++);
-    spi_transfer_byte(dev->p.spi, 0, (char *)&data);
-    gpio_set(dev->p.cs);
+    return spi_transfer_byte(dev->p.spi, dev->p.cs, false, 0);
+}
 
-    return data;
+static void wreg(w5100_t *dev, uint16_t reg, uint8_t data)
+{
+    spi_transfer_byte(dev->p.spi, dev->p.cs, true, CMD_WRITE);
+    send_addr(dev, reg);
+    spi_transfer_byte(dev->p.spi, dev->p.cs, false, data);
 }
 
 static uint16_t raddr(w5100_t *dev, uint16_t addr_high, uint16_t addr_low)
@@ -76,6 +77,13 @@ static uint16_t raddr(w5100_t *dev, uint16_t addr_high, uint16_t addr_low)
     return res;
 }
 
+static void waddr(w5100_t *dev,
+                  uint16_t addr_high, uint16_t addr_low, uint16_t val)
+{
+    wreg(dev, addr_high, (uint8_t)(val >> 8));
+    wreg(dev, addr_low, (uint8_t)(val & 0xff));
+}
+
 static void rchunk(w5100_t *dev, uint16_t addr, uint8_t *data, size_t len)
 {
     /* reading a chunk must be split in multiple single byte reads, as the
@@ -85,22 +93,6 @@ static void rchunk(w5100_t *dev, uint16_t addr, uint8_t *data, size_t len)
     }
 }
 
-static void wreg(w5100_t *dev, uint16_t reg, uint8_t data)
-{
-    gpio_clear(dev->p.cs);
-    spi_transfer_byte(dev->p.spi, CMD_WRITE, NULL);
-    send_addr(dev, reg);
-    spi_transfer_byte(dev->p.spi, data, NULL);
-    gpio_set(dev->p.cs);
-}
-
-static void waddr(w5100_t *dev,
-                  uint16_t addr_high, uint16_t addr_low, uint16_t val)
-{
-    wreg(dev, addr_high, (uint8_t)(val >> 8));
-    wreg(dev, addr_low, (uint8_t)(val & 0xff));
-}
-
 static void wchunk(w5100_t *dev, uint16_t addr, uint8_t *data, size_t len)
 {
     /* writing a chunk must be split in multiple single byte writes, as the
@@ -129,11 +121,8 @@ void w5100_setup(w5100_t *dev, const w5100_params_t *params)
     /* initialize the device descriptor */
     memcpy(&dev->p, params, sizeof(w5100_params_t));
 
-    /* initialize pins and SPI */
-    gpio_init(dev->p.cs, GPIO_OUT);
-    gpio_set(dev->p.cs);
-    spi_init_master(dev->p.spi, SPI_CONF, dev->p.spi_speed);
-
+    /* initialize the chip select pin and the external interrupt pin */
+    spi_init_cs(dev->p.spi, dev->p.cs);
     gpio_init_int(dev->p.evt, GPIO_IN, GPIO_FALLING, extint, dev);
 }
 
@@ -143,9 +132,13 @@ static int init(netdev2_t *netdev)
     uint8_t tmp;
     uint8_t hwaddr[ETHERNET_ADDR_LEN];
 
+    /* get access to the SPI bus for the duration of this function */
+    spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
+
     /* test the SPI connection by reading the value of the RMSR register */
     tmp = rreg(dev, REG_TMSR);
     if (tmp != RMSR_DEFAULT_VALUE) {
+        spi_release(dev->p.spi);
         LOG_ERROR("[w5100] error: no SPI connection\n");
         return W5100_ERR_BUS;
     }
@@ -180,6 +173,9 @@ static int init(netdev2_t *netdev)
     /* start receiving packets */
     wreg(dev, S0_CR, CR_RECV);
 
+    /* release the SPI bus again */
+    spi_release(dev->p.spi);
+
     return 0;
 }
 
@@ -203,6 +199,9 @@ static int send(netdev2_t *netdev, const struct iovec *vector, unsigned count)
     w5100_t *dev = (w5100_t *)netdev;
     int sum = 0;
 
+    /* get access to the SPI bus for the duration of this function */
+    spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
+
     uint16_t pos = raddr(dev, S0_TX_WR0, S0_TX_WR1);
 
     /* the register is only set correctly after the first send pkt, so we need
@@ -211,7 +210,7 @@ static int send(netdev2_t *netdev, const struct iovec *vector, unsigned count)
         pos = S0_TX_BASE;
     }
 
-    for (int i = 0; i < count; i++) {
+    for (unsigned i = 0; i < count; i++) {
         pos = tx_upload(dev, pos, vector[i].iov_base, vector[i].iov_len);
         sum += vector[i].iov_len;
     }
@@ -225,15 +224,22 @@ static int send(netdev2_t *netdev, const struct iovec *vector, unsigned count)
 
     DEBUG("[w5100] send: transferred %i byte (at 0x%04x)\n", sum, (int)pos);
 
+    /* release the SPI bus again */
+    spi_release(dev->p.spi);
+
     return sum;
 }
 
 static int recv(netdev2_t *netdev, void *buf, size_t len, void *info)
 {
+    (void)info;
     w5100_t *dev = (w5100_t *)netdev;
     uint8_t *in_buf = (uint8_t *)buf;
     int n = 0;
 
+    /* get access to the SPI bus for the duration of this function */
+    spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
+
     uint16_t num = raddr(dev, S0_RX_RSR0, S0_RX_RSR1);
 
     if (num > 0) {
@@ -267,16 +273,23 @@ static int recv(netdev2_t *netdev, void *buf, size_t len, void *info)
         }
     }
 
+    /* release the SPI bus again */
+    spi_release(dev->p.spi);
+
     return n;
 }
 
 static void isr(netdev2_t *netdev)
 {
+    uint8_t ir;
     w5100_t *dev = (w5100_t *)netdev;
 
     /* we only react on RX events, and if we see one, we read from the RX buffer
      * until it is empty */
-    while (rreg(dev, S0_IR) & IR_RECV) {
+    spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
+    ir = rreg(dev, S0_IR);
+    spi_release(dev->p.spi);
+    while (ir & IR_RECV) {
         DEBUG("[w5100] netdev2 RX complete\n");
         netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE);
     }
@@ -290,7 +303,9 @@ static int get(netdev2_t *netdev, netopt_t opt, void *value, size_t max_len)
     switch (opt) {
         case NETOPT_ADDRESS:
             assert(max_len >= ETHERNET_ADDR_LEN);
+            spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
             rchunk(dev, REG_SHAR0, value, ETHERNET_ADDR_LEN);
+            spi_release(dev->p.spi);
             res = ETHERNET_ADDR_LEN;
             break;
         default:
diff --git a/pkg/u8g2/README.md b/pkg/u8g2/README.md
index f8d77777cc65658fade2082afd6b68b730b3722f..8eaae174aba57d69793f5254f35e8e3718e702a0 100644
--- a/pkg/u8g2/README.md
+++ b/pkg/u8g2/README.md
@@ -46,7 +46,7 @@ uint32_t bitmap = (
 u8g2_Setup_ssd1306_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_riotos_hw_spi, u8x8_gpio_and_delay_riotos);
 
 u8g2_SetPins(&u8g2, pins, bitmap);
-u8g2_SetDevice(&u8g2, SPI_0);
+u8g2_SetDevice(&u8g2, SPI_DEV(0));
 ```
 
 ## Virtual displays
diff --git a/pkg/u8g2/patches/0001-u8g2-add-riot-os-makefiles.patch b/pkg/u8g2/patches/0001-u8g2-add-riot-os-makefiles.patch
index 1eb0aec881d65585959a3b4bd038b9f3963b5e05..54cf0184767de03bef9f3476c8ab4096ec60683c 100644
Binary files a/pkg/u8g2/patches/0001-u8g2-add-riot-os-makefiles.patch and b/pkg/u8g2/patches/0001-u8g2-add-riot-os-makefiles.patch differ
diff --git a/pkg/u8g2/patches/0002-u8g2-add-riot-os-interface.patch b/pkg/u8g2/patches/0002-u8g2-add-riot-os-interface.patch
index 208b30def7e965b63b05804d6f93a7cc4f78a3a1..7f938b8b3a772f61657c7042e0605c9e21a97ee3 100644
Binary files a/pkg/u8g2/patches/0002-u8g2-add-riot-os-interface.patch and b/pkg/u8g2/patches/0002-u8g2-add-riot-os-interface.patch differ
diff --git a/pkg/u8g2/patches/0003-u8g2-adapted-RIOT-interface-to-SPI-changes.patch b/pkg/u8g2/patches/0003-u8g2-adapted-RIOT-interface-to-SPI-changes.patch
new file mode 100644
index 0000000000000000000000000000000000000000..1d9786191dd5184a3a9e81d39211e8287dd551da
Binary files /dev/null and b/pkg/u8g2/patches/0003-u8g2-adapted-RIOT-interface-to-SPI-changes.patch differ
diff --git a/sys/auto_init/saul/auto_init_lis3dh.c b/sys/auto_init/saul/auto_init_lis3dh.c
index 46e2285cc93f5b0ec6dc76ed5e78f90c84ba498d..4890069e411faeba5cddb8e0a22ffd7742051569 100644
--- a/sys/auto_init/saul/auto_init_lis3dh.c
+++ b/sys/auto_init/saul/auto_init_lis3dh.c
@@ -55,7 +55,7 @@ void auto_init_lis3dh(void)
 
         LOG_DEBUG("[auto_init_saul] initializing lis3dh #%u\n", i);
 
-        res = lis3dh_init(&lis3dh_devs[i], p->spi, p->cs, p->scale);
+        res = lis3dh_init(&lis3dh_devs[i], p->spi, p->clk, p->cs, p->scale);
         if (res < 0) {
             LOG_ERROR("[auto_init_saul] error initializing lis3dh #%u\n", i);
             continue;
diff --git a/sys/auto_init/storage/auto_init_sdcard_spi.c b/sys/auto_init/storage/auto_init_sdcard_spi.c
index 8c7dc3c25f0af2dbd86d08c28e0b252982dc8cf5..5c8fd1a86c62e6cd2fadda908d161047bd2b1982 100644
--- a/sys/auto_init/storage/auto_init_sdcard_spi.c
+++ b/sys/auto_init/storage/auto_init_sdcard_spi.c
@@ -18,6 +18,7 @@
 
 #ifdef MODULE_SDCARD_SPI
 
+#include "log.h"
 #include "sdcard_spi.h"
 #include "sdcard_spi_params.h"
 
@@ -40,11 +41,12 @@ sdcard_spi_t sdcard_spi_devs[SDCARD_SPI_NUM];
 
 void auto_init_sdcard_spi(void)
 {
-    for (int i = 0; i < SDCARD_SPI_NUM; i++) {
-        DEBUG("sdcard_spi_auto_init(): initializing device [%i]...\n", i);
-        int resu = sdcard_spi_init(&sdcard_spi_devs[i], &sdcard_spi_params[i]);
-        if(resu != 0){
-            DEBUG("error initializing device [%i]\n", i);
+    for (unsigned i = 0; i < SDCARD_SPI_NUM; i++) {
+        LOG_DEBUG("[auto_init_storage] initializing sdcard_spi #%u\n", i);
+
+        if (sdcard_spi_init(&sdcard_spi_devs[i], &sdcard_spi_params[i]) !=
+            SDCARD_SPI_OK) {
+            LOG_ERROR("[auto_init_storage] error initializing sdcard_spi #%u\n", i);
         }
     }
 }
diff --git a/tests/driver_adt7310/Makefile b/tests/driver_adt7310/Makefile
index bf177ad98a8bc0e03640dfb3163307ee181b191a..a5403ff15a55de43cee8411116e9a182db478d2f 100644
--- a/tests/driver_adt7310/Makefile
+++ b/tests/driver_adt7310/Makefile
@@ -9,7 +9,7 @@ USEMODULE += adt7310
 USEMODULE += xtimer
 
 # set default device parameters in case they are undefined
-TEST_ADT7310_SPI ?= SPI_0
+TEST_ADT7310_SPI ?= SPI_DEV\(0\)
 TEST_ADT7310_CS  ?= GPIO_PIN\(0,0\)
 
 # export parameters
diff --git a/tests/driver_adt7310/main.c b/tests/driver_adt7310/main.c
index c9eef6cb1fdf2c5e0149aac3873d4a3d723dce75..bf4b0f055bc2ebb364c668ba7763e598830662a4 100644
--- a/tests/driver_adt7310/main.c
+++ b/tests/driver_adt7310/main.c
@@ -36,7 +36,7 @@
 #endif
 
 #define SPI_CONF    (SPI_CONF_SECOND_FALLING)
-#define SPI_SPEED   (SPI_SPEED_10MHZ)
+#define SPI_CLK     (SPI_CLK_10MHZ)
 
 #define SLEEP_CONT  (100 * 1000U)
 #define SLEEP_1SPS  (1000 * 1000U)
@@ -89,17 +89,9 @@ int main(void)
     adt7310_t dev;
 
     puts("ADT7310 temperature driver test application\n");
-    printf("Initializing SPI_%i... ", TEST_ADT7310_SPI);
-    if (spi_init_master(TEST_ADT7310_SPI, SPI_CONF, SPI_SPEED) == 0) {
-        puts("[OK]");
-    }
-    else {
-        puts("[Failed]\n");
-        return 1;
-    }
 
     puts("Initializing ADT7310 sensor... ");
-    if (adt7310_init(&dev, TEST_ADT7310_SPI, TEST_ADT7310_CS) == 0) {
+    if (adt7310_init(&dev, TEST_ADT7310_SPI, SPI_CLK, TEST_ADT7310_CS) == 0) {
         puts("[OK]");
     }
     else {
diff --git a/tests/driver_enc28j60/Makefile b/tests/driver_enc28j60/Makefile
index a243bf222ee41b51b71c4cac2be74f15061382d8..ae89bc8b3e80e414a359dfbad999c4fdb6c4b822 100644
--- a/tests/driver_enc28j60/Makefile
+++ b/tests/driver_enc28j60/Makefile
@@ -4,7 +4,7 @@ include ../Makefile.tests_common
 FEATURES_REQUIRED = periph_spi periph_gpio
 
 BOARD_INSUFFICIENT_MEMORY := msb-430h nucleo-f334 stm32f0discovery telosb \
-                             weio z1
+                             weio z1 msb-430
 
 USEMODULE += gnrc_netdev2
 USEMODULE += gnrc_netdev_default
@@ -18,14 +18,14 @@ USEMODULE += ps
 
 # set board specific peripheral configurations
 ifneq (,$(filter stm32f4discovery,$(BOARD)))
-  ENC_SPI ?= SPI_1
+  ENC_SPI ?= SPI_DEV\(1\)
   ENC_CS  ?= GPIO_PIN\(PORT_B,12\)
   ENC_INT ?= GPIO_PIN\(PORT_B,11\)
   ENC_RST ?= GPIO_PIN\(PORT_B,10\)
 endif
 
 # fallback: set SPI bus and pins to default values
-ENC_SPI ?= SPI_0
+ENC_SPI ?= SPI_DEV\(0\)
 ENC_CS  ?= GPIO_PIN\(0,0\)
 ENC_INT ?= GPIO_PIN\(0,1\)
 ENC_RST ?= GPIO_PIN\(0,2\)
diff --git a/tests/driver_encx24j600/Makefile b/tests/driver_encx24j600/Makefile
index 5fee1398157e672bc04424c645569842ce3fe23f..df2eac0808ad3760fcb71a633546abb0552b9945 100644
--- a/tests/driver_encx24j600/Makefile
+++ b/tests/driver_encx24j600/Makefile
@@ -3,7 +3,7 @@ include ../Makefile.tests_common
 
 FEATURES_REQUIRED = periph_spi periph_gpio
 
-BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery telosb weio z1
+BOARD_INSUFFICIENT_MEMORY := msb-430 msb-430h stm32f0discovery telosb weio z1
 
 USEMODULE += gnrc_netdev2
 USEMODULE += gnrc_netdev_default
@@ -22,13 +22,13 @@ CFLAGS += -DGNRC_PKTBUF_SIZE=2048
 ifneq (,$(filter nucleo-f334,$(BOARD)))
 # these settings are probably valid for PoEll-i on most nucelo boards, but
 # tested only on nucleo-f334
-  ENC_SPI ?= SPI_0
+  ENC_SPI ?= SPI_DEV\(0\)
   ENC_CS  ?= GPIO_PIN\(PORT_C,10\)
   ENC_INT ?= GPIO_PIN\(PORT_D,2\)
 endif
 
 # fallback: set SPI bus and pins to default values
-ENC_SPI ?= SPI_0
+ENC_SPI ?= SPI_DEV\(0\)
 ENC_CS  ?= GPIO_PIN\(0,0\)
 ENC_INT ?= GPIO_PIN\(0,1\)
 # export SPI and pins
diff --git a/tests/driver_kw2xrf/Makefile b/tests/driver_kw2xrf/Makefile
index e52d829856eac8800c72626e7ae01d5820483206..936b69c279b7a1ce1457a05579260a8e2a9ce833 100644
--- a/tests/driver_kw2xrf/Makefile
+++ b/tests/driver_kw2xrf/Makefile
@@ -26,8 +26,8 @@ ifneq (true,$(USE_BOARD_PARAMETERS))
   # set default device parameters in case they are undefined
   DRIVER            ?= kw2xrf
   KW2XRF_SHARED_SPI ?= 1
-  KWRF_SPI          ?= SPI_0
-  KWRF_SPI_SPEED    ?= SPI_SPEED_5MHZ
+  KWRF_SPI          ?= SPI_DEV\(0\)
+  KWRF_SPI_SPEED    ?= SPI_CLK_5MHZ
   KWRF_CS           ?= GPIO_PIN\(0,0\)
   KWRF_INT          ?= GPIO_PIN\(0,1\)
 
diff --git a/tests/driver_kw2xrf/kw2xrf_params.h b/tests/driver_kw2xrf/kw2xrf_params.h
index 7251fd59a012f6319338a48b362bdabad3c572ac..0ff9db424562c714de0d389433847e935c226e59 100644
--- a/tests/driver_kw2xrf/kw2xrf_params.h
+++ b/tests/driver_kw2xrf/kw2xrf_params.h
@@ -40,7 +40,7 @@ extern "C" {
 #error "Interrupt pin not defined"
 #endif
 #ifndef KWRF_SPI_SPEED
-#define KWRF_SPI_SPEED          (SPI_SPEED_10MHZ)
+#define KWRF_SPI_SPEED          (SPI_CLK_10MHZ)
 #endif
 /**@}*/
 
diff --git a/tests/driver_lis3dh/Makefile b/tests/driver_lis3dh/Makefile
index 2097649d77be7e887b016545c0bfec60f93ea60e..5e10cf99f28ff6eade89ef56d5dabd517136296d 100644
--- a/tests/driver_lis3dh/Makefile
+++ b/tests/driver_lis3dh/Makefile
@@ -7,7 +7,7 @@ USEMODULE += lis3dh
 USEMODULE += xtimer
 
 # set default device parameters in case they are undefined
-TEST_LIS3DH_SPI  ?= SPI_0
+TEST_LIS3DH_SPI  ?= SPI_DEV\(0\)
 TEST_LIS3DH_CS   ?= GPIO_PIN\(0,0\)
 TEST_LIS3DH_INT1 ?= GPIO_PIN\(0,1\)
 TEST_LIS3DH_INT2 ?= GPIO_PIN\(0,2\)
diff --git a/tests/driver_lis3dh/main.c b/tests/driver_lis3dh/main.c
index 2fea3559cdbc10bad69ab40b6f244b63a3082443..6dfb770a2d38a02bdf105913a5186772f4b3246c 100644
--- a/tests/driver_lis3dh/main.c
+++ b/tests/driver_lis3dh/main.c
@@ -61,7 +61,7 @@
 #define ODR         LIS3DH_ODR_100Hz
 #define SLEEP       (100 * 1000U)
 #define SPI_CONF    (SPI_CONF_SECOND_FALLING)
-#define SPI_SPEED   (SPI_SPEED_10MHZ)
+#define SPI_CLK     (SPI_CLK_10MHZ)
 
 #define WATERMARK_LEVEL 16
 
@@ -79,17 +79,9 @@ int main(void)
     lis3dh_data_t acc_data;
 
     puts("LIS3DH accelerometer driver test application\n");
-    printf("Initializing SPI_%i... ", TEST_LIS3DH_SPI);
-    if (spi_init_master(TEST_LIS3DH_SPI, SPI_CONF, SPI_SPEED) == 0) {
-        puts("[OK]");
-    }
-    else {
-        puts("[Failed]\n");
-        return 1;
-    }
 
     puts("Initializing LIS3DH sensor... ");
-    if (lis3dh_init(&dev, TEST_LIS3DH_SPI, TEST_LIS3DH_CS, SCALE) == 0) {
+    if (lis3dh_init(&dev, TEST_LIS3DH_SPI, SPI_CLK, TEST_LIS3DH_CS, SCALE) == 0) {
         puts("[OK]");
     }
     else {
diff --git a/tests/driver_nrf24l01p_lowlevel/Makefile b/tests/driver_nrf24l01p_lowlevel/Makefile
index 8df69ec9158b56bbc1e733c66360c7d0d2d104e4..6936803e44e862b5832e6bb84ba553161a5ec5e9 100644
--- a/tests/driver_nrf24l01p_lowlevel/Makefile
+++ b/tests/driver_nrf24l01p_lowlevel/Makefile
@@ -10,7 +10,7 @@ USEMODULE += xtimer
 USEMODULE += nrf24l01p
 
 # set default device parameters in case they are undefined
-SPI_PORT ?= SPI_0
+SPI_PORT ?= SPI_DEV\(0\)
 CE_PIN   ?= GPIO_PIN\(0,0\)
 CS_PIN   ?= GPIO_PIN\(0,1\)
 IRQ_PIN  ?= GPIO_PIN\(0,2\)
diff --git a/tests/driver_nrf24l01p_lowlevel/main.c b/tests/driver_nrf24l01p_lowlevel/main.c
index e16fd6b0084c4b2865e32f3e1d7fe4f0415f59ae..7d4e5b168ec1c8692592a0363382cd09c47dd170 100644
--- a/tests/driver_nrf24l01p_lowlevel/main.c
+++ b/tests/driver_nrf24l01p_lowlevel/main.c
@@ -85,34 +85,26 @@ void print_register(char reg, int num_bytes)
 {
 
     char buf_return[num_bytes];
-    int ret;
 
+    spi_transfer_regs(SPI_PORT, CS_PIN,
+                      (CMD_R_REGISTER | (REGISTER_MASK & reg)),
+                      NULL, (uint8_t *)buf_return, num_bytes);
 
-    gpio_clear(CS_PIN);
-    xtimer_usleep(1);
-    ret = spi_transfer_regs(SPI_PORT, (CMD_R_REGISTER | (REGISTER_MASK & reg)), 0, buf_return, num_bytes);
-    gpio_set(CS_PIN);
+    if (num_bytes < 2) {
+        printf("0x%x returned: ", reg);
 
-    if (ret < 0) {
-        printf("Error in read access\n");
+        for (int i = 0; i < num_bytes; i++) {
+            prtbin(buf_return[i]);
+        }
     }
     else {
-        if (num_bytes < 2) {
-            printf("0x%x returned: ", reg);
+        printf("0x%x returned: ", reg);
 
-            for (int i = 0; i < num_bytes; i++) {
-                prtbin(buf_return[i]);
-            }
+        for (int i = 0; i < num_bytes; i++) {
+            printf("%x ", buf_return[i]);
         }
-        else {
-            printf("0x%x returned: ", reg);
-
-            for (int i = 0; i < num_bytes; i++) {
-                printf("%x ", buf_return[i]);
-            }
 
-            printf("\n\n");
-        }
+        printf("\n\n");
     }
 }
 
@@ -266,6 +258,7 @@ int cmd_print_regs(int argc, char **argv)
 
     printf("################## Print Registers ###################\n");
 
+    spi_acquire(SPI_PORT, CS_PIN, SPI_MODE_0, SPI_CLK_400KHZ);
 
     puts("REG_CONFIG: ");
     print_register(REG_CONFIG, 1);
@@ -315,6 +308,8 @@ int cmd_print_regs(int argc, char **argv)
     puts("REG_FEATURE: ");
     print_register(REG_FEATURE, 1);
 
+    spi_release(SPI_PORT);
+
     return 0;
 }
 
diff --git a/tests/driver_nvram_spi/Makefile b/tests/driver_nvram_spi/Makefile
index 083fcf303ceb57a4857677545119d1af0fccbee4..de928f30a4011b4407ddec1865087251b7ca6d7c 100644
--- a/tests/driver_nvram_spi/Makefile
+++ b/tests/driver_nvram_spi/Makefile
@@ -7,7 +7,7 @@ USEMODULE += nvram_spi
 USEMODULE += xtimer
 
 # set default device parameters in case they are undefined
-TEST_NVRAM_SPI_DEV           ?= SPI_0
+TEST_NVRAM_SPI_DEV           ?= SPI_DEV\(0\)
 TEST_NVRAM_SPI_CS            ?= GPIO_PIN\(0,0\)
 TEST_NVRAM_SPI_SIZE          ?= 64
 TEST_NVRAM_SPI_ADDRESS_COUNT ?= 1
diff --git a/tests/driver_nvram_spi/main.c b/tests/driver_nvram_spi/main.c
index c4e701967185f1c1ebd8d37405e8180060bf458c..a517784068ce806de5ba2b3b52f0416a43c7dce4 100644
--- a/tests/driver_nvram_spi/main.c
+++ b/tests/driver_nvram_spi/main.c
@@ -40,16 +40,16 @@
 #error "TEST_NVRAM_SPI_ADDRESS_COUNT not defined"
 #endif
 
-#ifdef TEST_NVRAM_SPI_CONF
-#define SPI_CONF    (TEST_NVRAM_SPI_CONF)
+#ifdef TEST_NVRAM_SPI_MODE
+#define SPI_MODE    (TEST_NVRAM_SPI_MODE)
 #else
-#define SPI_CONF    (SPI_CONF_FIRST_RISING)
+#define SPI_MODE    (SPI_MODE_0)
 #endif
 
 #ifdef TEST_NVRAM_SPI_SPEED
-#define SPI_SPEED   (TEST_NVRAM_SPI_SPEED)
+#define SPI_CLK     (TEST_NVRAM_SPI_SPEED)
 #else
-#define SPI_SPEED   (SPI_SPEED_10MHZ)
+#define SPI_CLK     (SPI_CLK_10MHZ)
 #endif
 
 /* This will only work on small memories. Modify if you need to test NVRAM
@@ -114,6 +114,7 @@ int main(void)
     uint32_t i;
     nvram_spi_params_t spi_params = {
         .spi = TEST_NVRAM_SPI_DEV,
+        .clk = SPI_CLK,
         .cs = TEST_NVRAM_SPI_CS,
         .address_count = TEST_NVRAM_SPI_ADDRESS_COUNT,
     };
@@ -121,14 +122,6 @@ int main(void)
     uint32_t start_delay = 10;
 
     puts("NVRAM SPI test application starting...");
-    printf("Initializing SPI_%i... ", TEST_NVRAM_SPI_DEV);
-    if (spi_init_master(TEST_NVRAM_SPI_DEV, SPI_CONF, SPI_SPEED_10MHZ) == 0) {
-        puts("[OK]");
-    }
-    else {
-        puts("[Failed]\n");
-        return 1;
-    }
 
     puts("Initializing NVRAM SPI device descriptor... ");
     if (nvram_spi_init(&dev, &spi_params, TEST_NVRAM_SPI_SIZE) == 0) {
diff --git a/tests/driver_pcd8544/Makefile b/tests/driver_pcd8544/Makefile
index 32a7c7f2864f553000f1585afebaa014c3b57c4a..0504804716b0fbdea3da2a64dbd8932ffe557349 100644
--- a/tests/driver_pcd8544/Makefile
+++ b/tests/driver_pcd8544/Makefile
@@ -7,7 +7,7 @@ USEMODULE += shell
 USEMODULE += pcd8544
 
 # set default device parameters in case they are undefined
-TEST_PCD8544_SPI   ?= SPI_0
+TEST_PCD8544_SPI   ?= SPI_DEV\(0\)
 TEST_PCD8544_CS    ?= GPIO_PIN\(0,0\)
 TEST_PCD8544_RESET ?= GPIO_PIN\(0,1\)
 TEST_PCD8544_MODE  ?= GPIO_PIN\(0,2\)
diff --git a/tests/emb6/Makefile b/tests/emb6/Makefile
index d958a2a6e4403b4fe7769887cc45b1e3a73b23aa..bc3832ba8d1b06a7215bf9de9654c47b4931b12b 100644
--- a/tests/emb6/Makefile
+++ b/tests/emb6/Makefile
@@ -7,7 +7,8 @@ FEATURES_REQUIRED = periph_gpio periph_spi  # for at86rf231
 
 RIOTBASE ?= $(CURDIR)/../..
 
-BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery telosb weio z1
+BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery telosb weio z1 \
+                             wsn430-v1_3b wsn430-v1_4
 
 USEPKG += emb6
 
diff --git a/tests/lwip/Makefile b/tests/lwip/Makefile
index 38c10c2841ca72f5d394ae2e8919a60af8b98178..668918293741c34910cc020d4088821c029b7a30 100644
--- a/tests/lwip/Makefile
+++ b/tests/lwip/Makefile
@@ -6,10 +6,10 @@ include ../Makefile.tests_common
 RIOTBASE ?= $(CURDIR)/../..
 
 BOARD_BLACKLIST := arduino-mega2560 msb-430h telosb waspmote-pro z1 arduino-uno \
-                   arduino-duemilanove
+                   arduino-duemilanove msb-430 wsn430-v1_4 wsn430-v1_3b
 BOARD_INSUFFICIENT_MEMORY := airfy-beacon arduino-mega2560 msb-430h nrf6310 \
                              nucleo-f334 pca10005 stm32f0discovery telosb \
-                             weio yunjia-nrf51822 z1 nucleo-f030
+                             weio yunjia-nrf51822 z1 nucleo-f030 nucleo-f072
 
 # including lwip_ipv6_mld would currently break this test on at86rf2xx radios
 USEMODULE += lwip lwip_ipv6_autoconfig lwip_conn_ip lwip_netdev2
diff --git a/tests/periph_spi/Makefile b/tests/periph_spi/Makefile
index 7f3aae67c4c8998aa0e7d95c80b975d41804d898..70ea313087884d3b65b24052bd731f8955b573fe 100644
--- a/tests/periph_spi/Makefile
+++ b/tests/periph_spi/Makefile
@@ -3,6 +3,7 @@ include ../Makefile.tests_common
 
 FEATURES_REQUIRED = periph_spi
 
+USEMODULE += xtimer
 USEMODULE += shell
 USEMODULE += shell_commands
 
diff --git a/tests/periph_spi/main.c b/tests/periph_spi/main.c
index b251ef946bf1d7b82b638de7bb85b5741678a7c6..6bf46d92f198327a86bc4282ceaddcb3464d7e54 100644
--- a/tests/periph_spi/main.c
+++ b/tests/periph_spi/main.c
@@ -24,307 +24,402 @@
 #include <string.h>
 #include <stdlib.h>
 
-#include "board.h"
+#include "xtimer.h"
 #include "shell.h"
 #include "periph/spi.h"
-#include "periph/gpio.h"
-
-enum {
-    READ = 0,
-    WRITE,
-    INIT
-} rw;
-
-static int spi_dev = -1;
-static gpio_t spi_cs = -1;
-static int spi_mode_int = -1;
-static spi_conf_t spi_mode = -1;
-static int spi_speed_int = -1;
-static spi_speed_t spi_speed = -1;
-
-/* 0 for slave, 1 for master, -1 for not initialized */
-static int spi_master = -1;
-static int port = -1;
-static int pin = -1;
-
-static char buffer[256];       /* temporary buffer */
-static char rx_buffer[256];    /* global receive buffer */
-static int rx_counter = 0;
-
-static volatile int state;
-static char* mem = "Hello Master! abcdefghijklmnopqrstuvwxyz 0123456789 "
-                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-int parse_spi_dev(int argc, char **argv)
-{
-    /* reset default values */
-    spi_dev = SPI_0;
-    spi_mode = SPI_CONF_FIRST_RISING;
-    spi_speed = SPI_SPEED_1MHZ;
-
-    if (argc < 4) {
-        printf("usage: %s <dev> <cs port> <cs pin> [mode [speed]]\n", argv[0]);
-        puts("        DEV is the SPI device to use:");
-        for (int i = 0; i < SPI_NUMOF; i++) {
-            printf("             %i - SPI_%i\n", i, i);
-        }
-        puts("        cs port:  port to use as the chip select line");
-        puts("        cs pin:   pin to use on th given port as cs line");
-        puts("        mode: must be one of the following options (* marks "
-                      "default value):");
-        puts("            *0 - POL:0, PHASE:0 - ON FIRST RISING EDGE");
-        puts("             1 - POL:0, PHASE:1 - ON SECOND RISING EDGE");
-        puts("             2 - POL:1, PHASE:0 - ON FIRST FALLING EDGE");
-        puts("             3 - POL:1, PHASE:1 - on second falling edge");
-        puts("        speed: must be one of the following options (only used "
-                      "in master mode):");
-        puts("             0 - 100 KHz");
-        puts("             1 - 400 KHz");
-        puts("            *2 - 1 MHz");
-        puts("             3 - 5 MHz");
-        puts("             4 - 10 MHz\n");
-        return -4;
-    }
-    spi_dev = atoi(argv[1]);
-    if (spi_dev < 0 || spi_dev >= SPI_NUMOF) {
-        puts("error: invalid DEV value given");
-        return -1;
-    }
-    port = atoi(argv[2]);
-    pin = atoi(argv[3]);
-    spi_cs = GPIO_PIN(port,pin);
-    if (argc >= 5) {
-        spi_mode_int = argv[4][0] - '0';
-        if (spi_mode_int < 0 || spi_mode_int > 3) {
-            puts("error: invalid MODE value given");
-            return -2;
-        } else {
-            switch (spi_mode_int) {
-                case 0:
-                    spi_mode = SPI_CONF_FIRST_RISING;
-                    break;
-                case 1:
-                    spi_mode = SPI_CONF_SECOND_RISING;
-                    break;
-                case 2:
-                    spi_mode = SPI_CONF_FIRST_FALLING;
-                    break;
-                case 3:
-                    spi_mode = SPI_CONF_SECOND_FALLING;
-                    break;
-            }
-        }
-    }
-    if (argc >= 6) {
-        spi_speed_int = argv[5][0] - '0';
-        if (spi_speed_int < 0 || spi_speed_int > 4) {
-            puts("error: invalid SPEED value given");
-            return -3;
-        } else {
-            switch (spi_speed_int) {
-                case 0:
-                    spi_speed = SPI_SPEED_100KHZ;
-                    break;
-                case 1:
-                    spi_speed = SPI_SPEED_400KHZ;
-                    break;
-                case 2:
-                    spi_speed = SPI_SPEED_1MHZ;
-                    break;
-                case 3:
-                    spi_speed = SPI_SPEED_5MHZ;
-                    break;
-                case 4:
-                    spi_speed = SPI_SPEED_10MHZ;
-                    break;
-            }
-        }
-    }
-    return 0;
-}
 
-void print_bytes(char* title, char* chars, int length)
+/**
+ * @brief   Some parameters used for benchmarking
+ */
+#define BENCH_REDOS             (1000)
+#define BENCH_SMALL             (2)
+#define BENCH_LARGE             (100)
+#define BENCH_PAYLOAD           ('b')
+#define BENCH_REGADDR           (0x23)
+
+#define BUF_SIZE                (512U)
+
+/**
+ * @brief   Benchmark buffers
+ */
+static uint8_t bench_wbuf[BENCH_LARGE];
+static uint8_t bench_rbuf[BENCH_LARGE];
+
+/**
+ * @brief   Generic buffer used for receiving
+ */
+static uint8_t buf[BUF_SIZE];
+
+static struct {
+    spi_t dev;
+    spi_mode_t mode;
+    spi_clk_t clk;
+    spi_cs_t cs;
+} spiconf;
+
+void print_bytes(char* title, uint8_t* data, size_t len)
 {
-    printf("%4s", title);
-    for (int i = 0; i < length; i++) {
-        printf("  %2i ", i);
+    printf("%4s\n", title);
+    for (size_t i = 0; i < len; i++) {
+        printf("  %2i ", (int)i);
     }
-    printf("\n    ");
-    for (int i = 0; i < length; i++) {
-        printf(" 0x%02x", (int)chars[i]);
+    printf("\n ");
+    for (size_t i = 0; i < len; i++) {
+        printf(" 0x%02x", (int)data[i]);
     }
-    printf("\n    ");
-    for (int i = 0; i < length; i++) {
-        if (chars[i] < ' ' || chars[i] > '~') {
+    printf("\n ");
+    for (size_t i = 0; i < len; i++) {
+        if (data[i] < ' ' || data[i] > '~') {
             printf("  ?? ");
         }
         else {
-            printf("   %c ", chars[i]);
+            printf("   %c ", (char)data[i]);
         }
     }
     printf("\n\n");
 }
 
-void slave_on_cs(void *arg)
+int cmd_init(int argc, char **argv)
 {
-    (void)arg;
+    int dev, mode, clk, port, pin, tmp;
 
-    spi_transmission_begin(spi_dev, 'F');
-    state = 0;
-    rw = INIT;
-}
+    if (argc < 5) {
+        printf("usage: %s <dev> <mode> <clk> <cs port> <cs pin>\n", argv[0]);
+        puts("\tdev:");
+        for (int i = 0; i < (int)SPI_NUMOF; i++) {
+            printf("\t\t%i: SPI_DEV(%i)\n", i, i);
+        }
+        puts("\tmode:");
+        puts("\t\t0: POL:0, PHASE:0 - on first rising edge");
+        puts("\t\t1: POL:0, PHASE:1 - on second rising edge");
+        puts("\t\t2: POL:1, PHASE:0 - on first falling edge");
+        puts("\t\t3: POL:1, PHASE:1 - on second falling edge");
+        puts("\tclk:");
+        puts("\t\t0: 100 KHz");
+        puts("\t\t1: 400 KHz");
+        puts("\t\t2: 1 MHz");
+        puts("\t\t3: 5 MHz");
+        puts("\t\t4: 10 MHz");
+        puts("\tcs port:");
+        puts("\t\tPort of the CS pin, set to -1 for hardware chip select");
+        puts("\tcs pin:");
+        puts("\t\tPin used for chip select. If hardware chip select is enabled,\n"
+             "\t\tthis value specifies the internal HWCS line");
+        return 1;
+    }
 
-char slave_on_data(char data)
-{
-    rx_buffer[rx_counter] = data;
-    rx_counter++;
-    if (rx_counter >= 256) {
-        rx_counter = 0;
-    }
-
-    switch (rw) {
-        case READ:
-            return mem[state++];
-        case WRITE:
-            mem[state++] = data;
-            return 'o';
-        case INIT:
-            if (data == ' ') {
-                rw = READ;
-                return mem[state++];
-            } else if (data & 0x80) {
-                rw = WRITE;
-                state = (data & 0x7f);
-                return 'W';
-            } else {
-                rw = READ;
-                state = data;
-                return mem[state++];
-            }
-    }
-    return 'e';
-}
+    /* parse the given SPI device */
+    dev = atoi(argv[1]);
+    if (dev < 0 || dev >= SPI_NUMOF) {
+        puts("error: invalid SPI device specified");
+        return 1;
+    }
+    spiconf.dev = SPI_DEV(dev);
 
-int cmd_init_master(int argc, char **argv)
-{
-    int res;
-    spi_master = -1;
-    if (parse_spi_dev(argc, argv) < 0) {
+    /* parse the SPI mode */
+    mode = atoi(argv[2]);
+    switch (mode) {
+        case 0: spiconf.mode = SPI_MODE_0; break;
+        case 1: spiconf.mode = SPI_MODE_1; break;
+        case 2: spiconf.mode = SPI_MODE_2; break;
+        case 3: spiconf.mode = SPI_MODE_3; break;
+        default:
+            puts("error: invalid SPI mode specified");
+            return 1;
+    }
+
+    /* parse the targeted clock speed */
+    clk = atoi(argv[3]);
+    switch (clk) {
+        case 0: spiconf.clk = SPI_CLK_100KHZ; break;
+        case 1: spiconf.clk = SPI_CLK_400KHZ; break;
+        case 2: spiconf.clk = SPI_CLK_1MHZ;   break;
+        case 3: spiconf.clk = SPI_CLK_5MHZ;   break;
+        case 4: spiconf.clk = SPI_CLK_10MHZ;  break;
+        default:
+            puts("error: invalid bus speed specified");
+            return 1;
+    }
+
+    /* parse chip select port and pin */
+    port = atoi(argv[4]);
+    pin = atoi(argv[5]);
+    if (pin < 0 || port < -1) {
+        puts("error: invalid CS port/pin combination specified");
+    }
+    if (port == -1) {                    /* hardware chip select line */
+        spiconf.cs = SPI_HWCS(pin);
+    }
+    else {
+        spiconf.cs = (spi_cs_t)GPIO_PIN(port, pin);
+    }
+
+    /* test setup */
+    tmp = spi_init_cs(spiconf.dev, spiconf.cs);
+    if (tmp != SPI_OK) {
+        puts("error: unable to initialize the given chip select line");
+        return 1;
+    }
+    tmp = spi_acquire(spiconf.dev, spiconf.cs, spiconf.mode, spiconf.clk);
+    if (tmp == SPI_NOMODE) {
+        puts("error: given SPI mode is not supported");
         return 1;
     }
-    spi_acquire(spi_dev);
-    res = spi_init_master(spi_dev, spi_mode, spi_speed);
-    spi_release(spi_dev);
-    if (res < 0) {
-        printf("spi_init_master: error initializing SPI_%i device (code %i)\n",
-                spi_dev, res);
+    else if (tmp == SPI_NOCLK) {
+        puts("error: targeted clock speed is not supported");
         return 1;
     }
-    res = gpio_init(spi_cs, GPIO_OUT);
-    if (res < 0){
-        printf("gpio_init: error initializing GPIO_PIN(%i, %i) as CS line (code %i)\n",
-                port, pin, res);
+    else if (tmp != SPI_OK) {
+        puts("error: unable to acquire bus with given parameters");
         return 1;
     }
-    gpio_set(spi_cs);
-    spi_master = 1;
-    printf("SPI_%i successfully initialized as master, cs: GPIO_PIN(%i, %i), mode: %i, speed: %i\n",
-            spi_dev, port, pin, spi_mode_int, spi_speed_int);
+    spi_release(spiconf.dev);
+
+    printf("SPI_DEV(%i) initialized: mode: %i, clk: %i, cs_port: %i, cs_pin: %i\n",
+           dev, mode, clk, port, pin);
+
     return 0;
 }
 
-int cmd_init_slave(int argc, char **argv)
+int cmd_transfer(int argc, char **argv)
 {
-    int res;
-    spi_master = -1;
-    if (parse_spi_dev(argc, argv) < 0) {
+    size_t len;
+
+    if (argc < 2) {
+        printf("usage: %s <data>\n", argv[0]);
         return 1;
     }
-    spi_acquire(spi_dev);
-    res = spi_init_slave(spi_dev, spi_mode, slave_on_data);
-    spi_release(spi_dev);
-    if (res < 0) {
-        printf("spi_init_slave: error initializing SPI_%i device (code: %i)\n",
-                spi_dev, res);
+
+    if (spiconf.dev == SPI_UNDEF) {
+        puts("error: SPI is not initialized, please initialize bus first");
         return 1;
     }
-    res = gpio_init_int(spi_cs, GPIO_IN, GPIO_FALLING, slave_on_cs, 0);
-    if (res < 0){
-        printf("gpio_init_int: error initializing GPIO_PIN(%i, %i) as CS line (code %i)\n",
-                port, pin, res);
+
+    /* get bus access */
+    if (spi_acquire(spiconf.dev, spiconf.cs,
+                    spiconf.mode, spiconf.clk) != SPI_OK) {
+        puts("error: unable to acquire the SPI bus");
         return 1;
     }
-    spi_master = 0;
-    printf("SPI_%i successfully initialized as slave, cs: GPIO_PIN(%i, %i), mode: %i\n",
-            spi_dev, port, pin, spi_mode_int);
+
+    /* transfer data */
+    len = strlen(argv[1]);
+    memset(buf, 0, sizeof(buf));
+    spi_transfer_bytes(spiconf.dev, spiconf.cs, false, argv[1], buf, len);
+
+    /* release the bus */
+    spi_release(spiconf.dev);
+
+    /* print results */
+    print_bytes("Sent bytes", (uint8_t *)argv[1], len);
+    print_bytes("Received bytes", buf, len);
+
     return 0;
 }
 
-int cmd_transfer(int argc, char **argv)
+int cmd_bench(int argc, char **argv)
 {
-    int res;
-    char *hello = "Hello";
+    uint32_t start, stop;
+    uint32_t sum = 0;
+    uint8_t in;
+    uint8_t out = (uint8_t)BENCH_PAYLOAD;
 
-    if (spi_master != 1) {
-        puts("error: node is not initialized as master, please do so first");
+    if (spiconf.dev == SPI_UNDEF) {
+        puts("error: SPI is not initialized, please initialize bus first");
         return 1;
     }
 
-    if (argc < 2) {
-        puts("No data to transfer given, will transfer 'Hello' to device");
+    /* prepare buffer */
+    memset(bench_wbuf, BENCH_PAYLOAD, BENCH_LARGE);
+
+    /* get access to the bus */
+    if (spi_acquire(spiconf.dev, spiconf.cs,
+                    spiconf.mode, spiconf.clk) != SPI_OK) {
+        puts("error: unable to acquire the SPI bus");
+        return 1;
     }
-    else {
-        hello = argv[1];
+
+    puts("### Running some benchmarks, all values in [us] ###\n");
+
+    /* 1 - write 1000 times 1 byte */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        in = spi_transfer_byte(spiconf.dev, spiconf.cs, false, out);
+        (void)in;
     }
+    stop = xtimer_now_usec();
+    printf(" 1 - write %i times %i byte:", BENCH_REDOS, 1);
+    printf("\t\t\t%i\n", (int)(stop - start));
+    sum += (stop - start);
 
-    /* do the actual data transfer */
-    spi_acquire(spi_dev);
-    gpio_clear(spi_cs);
-    res = spi_transfer_bytes(spi_dev, hello, buffer, strlen(hello));
-    gpio_set(spi_cs);
-    spi_release(spi_dev);
+    /* 2 - write 1000 times 2 byte */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+                           bench_wbuf, NULL, BENCH_SMALL);
+    }
+    stop = xtimer_now_usec();
+    printf(" 2 - write %i times %i byte:", BENCH_REDOS, BENCH_SMALL);
+    printf("\t\t\t%i\n", (int)(stop - start));
+    sum += (stop - start);
 
-    /* look at the results */
-    if (res < 0) {
-        printf("error: unable to transfer data to slave (code: %i)\n", res);
-        return 1;
+    /* 3 - write 1000 times 100 byte */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+                           bench_wbuf, NULL, BENCH_LARGE);
     }
-    else {
-        printf("Transfered %i bytes:\n", res);
-        print_bytes("MOSI", hello, res);
-        print_bytes("MISO", buffer, res);
-        return 0;
+    stop = xtimer_now_usec();
+    printf(" 3 - write %i times %i byte:", BENCH_REDOS, BENCH_LARGE);
+    printf("\t\t%i\n", (int)(stop - start));
+    sum += (stop - start);
+
+    /* 4 - write 1000 times 1 byte to register */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        in = spi_transfer_reg(spiconf.dev, spiconf.cs, BENCH_REGADDR, out);
+        (void)in;
     }
-}
+    stop = xtimer_now_usec();
+    printf(" 4 - write %i times %i byte to register:", BENCH_REDOS, 1);
+    printf("\t%i\n", (int)(stop - start));
+    sum += (stop - start);
 
-int cmd_print(int argc, char **argv)
-{
-    if (spi_master != 0) {
-        puts("error: node is not initialized as slave");
-        return 1;
+    /* 5 - write 1000 times 2 byte to register */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+                          bench_wbuf, NULL, BENCH_SMALL);
     }
-    else {
-        printf("Received %i bytes:\n", rx_counter);
-        print_bytes("MOSI", rx_buffer, rx_counter);
+    stop = xtimer_now_usec();
+    printf(" 5 - write %i times %i byte to register:", BENCH_REDOS, BENCH_SMALL);
+    printf("\t%i\n", (int)(stop - start));
+    sum += (stop - start);
+
+    /* 6 - write 1000 times 100 byte to register */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+                          bench_wbuf, NULL, BENCH_LARGE);
     }
-    rx_counter = 0;
-    memset(&rx_buffer, 0, 256);
+    stop = xtimer_now_usec();
+    printf(" 6 - write %i times %i byte to register:", BENCH_REDOS, BENCH_LARGE);
+    printf("\t%i\n", (int)(stop - start));
+    sum += (stop - start);
+
+    /* 7 - read 1000 times 2 byte */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+                           NULL, bench_rbuf, BENCH_SMALL);
+    }
+    stop = xtimer_now_usec();
+    printf(" 7 - read %i times %i byte:", BENCH_REDOS, BENCH_SMALL);
+    printf("\t\t\t%i\n", (int)(stop - start));
+    sum += (stop - start);
+
+    /* 8 - read 1000 times 100 byte */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+                           NULL, bench_rbuf, BENCH_LARGE);
+    }
+    stop = xtimer_now_usec();
+    printf(" 8 - read %i times %i byte:", BENCH_REDOS, BENCH_LARGE);
+    printf("\t\t\t%i\n", (int)(stop - start));
+    sum += (stop - start);
+
+    /* 9 - read 1000 times 2 byte from register */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+                          NULL, bench_rbuf, BENCH_SMALL);
+    }
+    stop = xtimer_now_usec();
+    printf(" 9 - read %i times %i byte from register:", BENCH_REDOS, BENCH_SMALL);
+    printf("\t%i\n", (int)(stop - start));
+    sum += (stop - start);
+
+    /* 10 - read 1000 times 100 byte from register */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+                          NULL, bench_rbuf, BENCH_LARGE);
+    }
+    stop = xtimer_now_usec();
+    printf("10 - read %i times %i byte from register:", BENCH_REDOS, BENCH_LARGE);
+    printf("\t%i\n", (int)(stop - start));
+    sum += (stop - start);
+
+    /* 11 - transfer 1000 times 2 byte */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+                           bench_wbuf, bench_rbuf, BENCH_SMALL);
+    }
+    stop = xtimer_now_usec();
+    printf("11 - transfer %i times %i byte:", BENCH_REDOS, BENCH_SMALL);
+    printf("\t\t%i\n", (int)(stop - start));
+    sum += (stop - start);
+
+    /* 12 - transfer 1000 times 100 byte */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+                           bench_wbuf, bench_rbuf, BENCH_LARGE);
+    }
+    stop = xtimer_now_usec();
+    printf("12 - transfer %i times %i byte:", BENCH_REDOS, BENCH_LARGE);
+    printf("\t\t%i\n", (int)(stop - start));
+    sum += (stop - start);
+
+    /* 13 - transfer 1000 times 2 byte from/to register */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+                          bench_wbuf, bench_rbuf, BENCH_SMALL);
+    }
+    stop = xtimer_now_usec();
+    printf("13 - transfer %i times %i byte to register:", BENCH_REDOS, BENCH_SMALL);
+    printf("\t%i\n", (int)(stop - start));
+    sum += (stop - start);
+
+    /* 14 - transfer 1000 times 100 byte from/to register */
+    start = xtimer_now_usec();
+    for (int i = 0; i < BENCH_REDOS; i++) {
+        spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+                          bench_wbuf, bench_rbuf, BENCH_LARGE);
+    }
+    stop = xtimer_now_usec();
+    printf("14 - transfer %i times %i byte to register:", BENCH_REDOS, BENCH_LARGE);
+    printf("\t%i\n", (int)(stop - start));
+    sum += (stop - start);
+
+    printf("-- - SUM:\t\t\t\t\t%i\n", (int)sum);
+
+    spi_release(spiconf.dev);
+    puts("\n### All runs complete ###");
+
     return 0;
 }
 
 static const shell_command_t shell_commands[] = {
-    { "init_master", "Initialize node as SPI master", cmd_init_master },
-    { "init_slave", "Initialize node as SPI slave", cmd_init_slave },
-    { "send", "Transfer string to slave (only in master mode)", cmd_transfer },
-    { "print_rx", "Print the received string (only in slave mode)", cmd_print },
+    { "init", "Setup a particular SPI configuration", cmd_init },
+    { "send", "Transfer string to slave", cmd_transfer },
+    { "bench", "Runs some benchmarks", cmd_bench },
     { NULL, NULL, NULL }
 };
 
 int main(void)
 {
-    puts("\nRIOT low-level SPI driver test");
-    puts("This application enables you to test a platforms SPI driver implementation.");
-    puts("Enter 'help' to get started\n");
+    puts("Manual SPI peripheral driver test");
+    puts("Refer to the README.md file for more information.\n");
+
+    printf("There are %i SPI devices configured for your platform.\n",
+           (int)SPI_NUMOF);
+
+    /* reset local SPI configuration */
+    spiconf.dev = SPI_UNDEF;
 
     /* run the shell */
     char line_buf[SHELL_DEFAULT_BUFSIZE];
diff --git a/tests/warn_conflict/Makefile b/tests/warn_conflict/Makefile
index e3c6cd2750c2c2b50a608159b182c411966df47f..b83cc4411cfd8519759173c8977d869d66c1981c 100644
--- a/tests/warn_conflict/Makefile
+++ b/tests/warn_conflict/Makefile
@@ -5,8 +5,9 @@ include ../Makefile.tests_common
 # so using this compile test on other boards will not provide the expected warning.
 BOARD_WHITELIST := stm32f4discovery
 
-# These features have a chance to use/access the shared `SPI_0` on stm32f4discovery,
-# which would probably produce an unexpected behaviour in the user application.
+# These features have a chance to use/access the shared `SPI_DEV(0)` on
+# stm32f4discovery, which would probably produce an unexpected behavior in the
+# user application.
 FEATURES_REQUIRED = periph_dac periph_spi
 
 include $(RIOTBASE)/Makefile.include
diff --git a/tests/warn_conflict/README.md b/tests/warn_conflict/README.md
index 0169964a842272fdad67ea1ed8c2ca0c0a9cc373..b274230efd3359c1a447d2a5c7b4b3a8f31004e6 100644
--- a/tests/warn_conflict/README.md
+++ b/tests/warn_conflict/README.md
@@ -9,7 +9,7 @@ It is expected to be presented with a warning on the conflicts with a short desc
 ```
 $ make BOARD=stm32f4discovery
 The following features may conflict: periph_dac periph_spi
-Rationale: On stm32f4discovery boards there are the same pins for the DAC and/or SPI_0.
+Rationale: On stm32f4discovery boards there are the same pins for the DAC and/or SPI_DEV(0).
 
 EXPECT undesired behaviour!
 ```
@@ -23,7 +23,7 @@ Whenever an application, such as this test, requires board features that match a
 
 * Conflicting features are described in groups separated by a `:` (doublecolon) for each feature, e.g.:
 `FEATURES_CONFLICT = periph_spi:periph_dac`, which states that `periph_spi` conflicts with `periph_dac`.
-As seen above, this is the conflict of `SPI_0` pinout is shared with `DAC` on the [stm32f4discovery](https://github.com/RIOT-OS/RIOT/wiki/Board%3A-STM32F4discovery) board.
+As seen above, this is the conflict of `SPI_DEV(0)` pinout is shared with `DAC` on the [stm32f4discovery](https://github.com/RIOT-OS/RIOT/wiki/Board%3A-STM32F4discovery) board.
 
 * Distinct groups of conflicts are whitespace separated, e.g.:
 `featureA:featureB featureC:featureD`, which states that `featureA` conflicts with `featureB`, and `featureC` conflicts with `featureD`.
diff --git a/tests/warn_conflict/test.py b/tests/warn_conflict/test.py
index 65a2b2568d6e999cbaea7edb9bd030c6a67f4973..1f3bfb2d1288795abf1e5fd2e12caf38f0e03180 100755
--- a/tests/warn_conflict/test.py
+++ b/tests/warn_conflict/test.py
@@ -9,7 +9,7 @@ try:
     output = subprocess.Popen(["make", "BOARD=stm32f4discovery"], stderr=subprocess.PIPE, stdout=subprocess.PIPE )
     out,err = output.communicate()
 
-    compare = b'\x1b[1;33mThe following features may conflict:\x1b[0m \x1b[1;32mperiph_dac periph_spi\x1b[0m\n\x1b[1;33mRationale: \x1b[0mOn stm32f4discovery boards there are the same pins for the DAC and/or SPI_0.\n\n\x1b[1;33mEXPECT undesired behaviour!\x1b[0m\n'
+    compare = b'\x1b[1;33mThe following features may conflict:\x1b[0m \x1b[1;32mperiph_dac periph_spi\x1b[0m\n\x1b[1;33mRationale: \x1b[0mOn stm32f4discovery boards there are the same pins for the DAC and/or SPI_DEV(0).\n\n\x1b[1;33mEXPECT undesired behaviour!\x1b[0m\n'
     if err == compare:
         print("Test SUCCEEDED! Compile time output is as expected!\n")
     else: