From 0edef2a0e142f9ea38cab61a5de32f7b186d9e0b Mon Sep 17 00:00:00 2001
From: Hauke Petersen <hauke.petersen@fu-berlin.de>
Date: Tue, 8 Nov 2016 18:28:32 +0100
Subject: [PATCH] cpu/stm32*+boards: adapted to new SPI API

- adapted the SPI driver
- adapted all boards using the CPU
---
 boards/fox/include/board.h                    |   4 +-
 boards/fox/include/periph_conf.h              |  47 +-
 boards/iotlab-a8-m3/include/periph_conf.h     |  25 +-
 boards/iotlab-common/include/board_common.h   |   8 +-
 .../include/periph_conf_common.h              |  23 +
 boards/iotlab-m3/include/board.h              |   2 +-
 boards/iotlab-m3/include/periph_conf.h        |  33 +-
 boards/limifrog-v1/include/periph_conf.h      |  77 +--
 boards/msbiot/include/board.h                 |   2 +-
 boards/msbiot/include/periph_conf.h           |  61 ++-
 boards/nucleo-f072/Makefile.features          |   1 +
 boards/nucleo-f072/include/periph_conf.h      |  40 ++
 boards/nucleo-f091/Makefile.features          |   1 +
 boards/nucleo-f091/include/periph_conf.h      |  42 ++
 boards/nucleo-f103/include/periph_conf.h      |  73 +--
 boards/nucleo-f207/include/periph_conf.h      |  89 ++--
 boards/nucleo-f303/include/periph_conf.h      |  90 ++--
 boards/nucleo-f334/include/periph_conf.h      |  59 ++-
 boards/nucleo-f401/include/periph_conf.h      |  60 ++-
 boards/nucleo-f446/include/periph_conf.h      |  60 ++-
 boards/nucleo-l1/include/periph_conf.h        |  58 ++-
 boards/spark-core/Makefile.features           |   1 +
 boards/spark-core/include/board.h             |   4 +-
 boards/spark-core/include/periph_conf.h       |  47 +-
 boards/stm32f0discovery/include/periph_conf.h |  73 +--
 boards/stm32f3discovery/include/periph_conf.h |  85 ++--
 boards/stm32f4discovery/include/periph_conf.h |  88 ++--
 cpu/stm32_common/include/periph_cpu_common.h  |  34 +-
 cpu/stm32_common/periph/spi.c                 | 211 ++++++++
 cpu/stm32f0/periph/spi.c                      | 256 ----------
 cpu/stm32f0/periph/spi.cold                   | 165 +++++++
 cpu/stm32f1/include/periph_cpu.h              |  11 +-
 cpu/stm32f1/periph/spi.c                      | 309 ------------
 cpu/stm32f1/periph/spi.cold                   | 138 ++++++
 cpu/stm32f2/include/periph_cpu.h              |   7 -
 cpu/stm32f2/periph/spi.c                      | 451 ------------------
 cpu/stm32f2/periph/spi.cold                   | 174 +++++++
 cpu/stm32f3/periph/spi.c                      | 420 ----------------
 cpu/stm32f3/periph/spi.cold                   | 165 +++++++
 cpu/stm32f4/Makefile.include                  |   1 +
 cpu/stm32f4/include/periph_cpu.h              |   9 -
 cpu/stm32f4/periph/spi.c                      | 451 ------------------
 cpu/stm32l1/include/periph_cpu.h              |  10 +
 cpu/stm32l1/periph/spi.c                      | 261 ----------
 cpu/stm32l1/periph/spi.cold                   | 166 +++++++
 45 files changed, 1765 insertions(+), 2627 deletions(-)
 create mode 100644 cpu/stm32_common/periph/spi.c
 delete mode 100644 cpu/stm32f0/periph/spi.c
 create mode 100644 cpu/stm32f0/periph/spi.cold
 delete mode 100644 cpu/stm32f1/periph/spi.c
 create mode 100644 cpu/stm32f1/periph/spi.cold
 delete mode 100644 cpu/stm32f2/periph/spi.c
 create mode 100644 cpu/stm32f2/periph/spi.cold
 delete mode 100644 cpu/stm32f3/periph/spi.c
 create mode 100644 cpu/stm32f3/periph/spi.cold
 delete mode 100644 cpu/stm32f4/periph/spi.c
 delete mode 100644 cpu/stm32l1/periph/spi.c
 create mode 100644 cpu/stm32l1/periph/spi.cold

diff --git a/boards/fox/include/board.h b/boards/fox/include/board.h
index 24316d18ef..d87e492d07 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 13565ad619..ffe99f22e2 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/iotlab-a8-m3/include/periph_conf.h b/boards/iotlab-a8-m3/include/periph_conf.h
index 8b4db8ecbc..ac4ba9c338 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 ed9b988378..f0161d7b84 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 3e1aa028ba..b0d104c970 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 a88fca79a6..37618a3860 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 ae7d37b4b0..4cf77ad22b 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 457ec3580f..bec60ee54b 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/msbiot/include/board.h b/boards/msbiot/include/board.h
index 5199702afb..38b7eff4f0 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 acfb0caf49..80bc37a542 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/nucleo-f072/Makefile.features b/boards/nucleo-f072/Makefile.features
index 5942339b26..4a5c8488bc 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 5bf6742b7c..014db5e4af 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 5942339b26..4a5c8488bc 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 5052e1c22e..d80a092856 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 335c15ffe2..7a4a898db6 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 664f183fd5..9c0432165e 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, 5),
+        .miso_pin = GPIO_PIN(PORT_B, 4),
+        .sclk_pin = GPIO_PIN(PORT_B, 3),
+        .cs_pin   = GPIO_PIN(PORT_B, 2),
+        .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
  * @{
diff --git a/boards/nucleo-f303/include/periph_conf.h b/boards/nucleo-f303/include/periph_conf.h
index 5b81d5b5c9..ccab5c0e3f 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 d7b602d0ba..06bd731cd3 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 5ff2e339c8..f011f1bbfc 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 b6738f5941..47ed25898c 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 409a8e1bc7..dbec32fe24 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/spark-core/Makefile.features b/boards/spark-core/Makefile.features
index 1442fd8e7e..3de96ca4b3 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 0d46ed3e5d..6b9bae98d3 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 77697481e3..2843246635 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 cb2f3c72e0..5b27791769 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 fda093ae63..cf658a87e9 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 0263c03ee1..a41819bc54 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/cpu/stm32_common/include/periph_cpu_common.h b/cpu/stm32_common/include/periph_cpu_common.h
index c2040ad6b7..2422473b03 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 0000000000..60f0a85924
--- /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/periph/spi.c b/cpu/stm32f0/periph/spi.c
deleted file mode 100644
index 4bfce9ba45..0000000000
--- 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 0000000000..894e4603ff
--- /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/include/periph_cpu.h b/cpu/stm32f1/include/periph_cpu.h
index 035eec70f4..b9bbe757b9 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
+ */
+#define TIMER_CHANNELS      (4U)
+
+/**
+ * @brief   All timers have a width of 16-bit
  */
-#undef PERIPH_SPI_NEEDS_TRANSFER_BYTES
-#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
+#define TIMER_MAXVAL        (0xffff)
 
 /**
  * @brief   Generate GPIO mode bitfields
diff --git a/cpu/stm32f1/periph/spi.c b/cpu/stm32f1/periph/spi.c
deleted file mode 100644
index 005e547dad..0000000000
--- 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 0000000000..9fb51dabe8
--- /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/include/periph_cpu.h b/cpu/stm32f2/include/periph_cpu.h
index d9197f3895..82d740cbf8 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
  *
diff --git a/cpu/stm32f2/periph/spi.c b/cpu/stm32f2/periph/spi.c
deleted file mode 100644
index 3da216b944..0000000000
--- 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 0000000000..d7a9cd5bbd
--- /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/periph/spi.c b/cpu/stm32f3/periph/spi.c
deleted file mode 100644
index d128a4f84c..0000000000
--- 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 0000000000..1f12f893b9
--- /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 8d5704e1c3..bf4156f52d 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/include/periph_cpu.h b/cpu/stm32f4/include/periph_cpu.h
index e71b75b59c..141620483d 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 89809a90b7..0000000000
--- 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/include/periph_cpu.h b/cpu/stm32l1/include/periph_cpu.h
index d8b06ee2a2..94880fed64 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 f9e7f40e58..0000000000
--- 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 0000000000..f664b6bd4b
--- /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 */
-- 
GitLab