diff --git a/cpu/saml21/include/periph_cpu.h b/cpu/saml21/include/periph_cpu.h
index 1067842fe68976556f0fa28daa9049b777d6a7b4..3da96d183eaea6af94c85d18a7e9b5bf494aaa74 100644
--- a/cpu/saml21/include/periph_cpu.h
+++ b/cpu/saml21/include/periph_cpu.h
@@ -33,6 +33,31 @@ enum {
     PB = 1,                 /**< port B */
 };
 
+/**
+ * @brief   Generate GPIO mode bitfields
+ *
+ * We use 3 bit to determine the pin functions:
+ * - bit 0: PU or PU
+ * - bit 1: input enable
+ * - bit 2: pull enable
+ */
+#define GPIO_MODE(pr, ie, pe)   (pr | (ie << 1) | (pe << 2))
+
+/**
+ * @brief   Override GPIO modes
+ * @{
+ */
+#define HAVE_GPIO_MODE_T
+typedef enum {
+    GPIO_IN    = GPIO_MODE(0, 1, 0),    /**< IN */
+    GPIO_IN_PD = GPIO_MODE(0, 1, 1),    /**< IN with pull-down */
+    GPIO_IN_PU = GPIO_MODE(1, 1, 1),    /**< IN with pull-up */
+    GPIO_OUT   = GPIO_MODE(0, 0, 0),    /**< OUT (push-pull) */
+    GPIO_OD    = 0xfe,                  /**< not supported by HW */
+    GPIO_OD_PU = 0xff                   /**< not supported by HW */
+} gpio_mode_t;
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/cpu/saml21/periph/gpio.c b/cpu/saml21/periph/gpio.c
index 74f6bce3e698149635f4eb8de71961f460d4c571..29d10bf826993d1dc4dad94236f8c0dc0b555594 100644
--- a/cpu/saml21/periph/gpio.c
+++ b/cpu/saml21/periph/gpio.c
@@ -41,6 +41,11 @@
  */
 #define NUMOF_IRQS                  (16U)
 
+/**
+ * @brief   Mask to get PINCFG reg value from mode value
+ */
+#define MODE_PINCFG_MASK            (0x06)
+
 /**
  * @brief   Mapping of pins to EXTI lines, -1 means not EXTI possible
  */
@@ -89,42 +94,38 @@ void gpio_init_mux(gpio_t pin, gpio_mux_t mux)
     port->PMUX[pin_pos >> 1].reg |=  (mux << (4 * (pin_pos & 0x1)));
 }
 
-int gpio_init(gpio_t pin, gpio_dir_t dir, gpio_pp_t pushpull)
+int gpio_init(gpio_t pin, gpio_mode_t mode)
 {
     PortGroup* port = _port(pin);
     int pin_pos = _pin_pos(pin);
     int pin_mask = _pin_mask(pin);
 
-    /* configure the pin's pull resistor and reset all other configuration */
-    switch (pushpull) {
-        case GPIO_PULLDOWN:
-            port->OUTCLR.reg = pin_mask;
-            port->PINCFG[pin_pos].reg = PORT_PINCFG_PULLEN;
-            break;
-        case GPIO_PULLUP:
-            port->OUTSET.reg = pin_mask;
-            port->PINCFG[pin_pos].reg = PORT_PINCFG_PULLEN;
-            break;
-        case GPIO_NOPULL:
-            port->PINCFG[pin_pos].reg = 0;
-            break;
+    /* make sure pin mode is applicable */
+    if (mode > 0x7) {
+        return -1;
     }
-    /* set pin_pos direction */
-    if (dir == GPIO_DIR_OUT) {
-        if (pushpull == GPIO_PULLDOWN) {
-            return -1;
-        }
-        port->DIRSET.reg = pin_mask;            /* configure as output */
-        port->OUTCLR.reg = pin_mask;            /* set pin LOW on init */
+
+    /* set pin direction */
+    if (mode & 0x2) {
+        port->DIRCLR.reg = pin_mask;
     }
     else {
-        port->DIRCLR.reg = pin_mask;            /* configure as input */
-        port->PINCFG[pin_pos].reg |= PORT_PINCFG_INEN;
+        port->DIRSET.reg = pin_mask;
     }
+
+    /* configure the pin cfg and clear output register */
+    port->PINCFG[pin_pos].reg = (mode & MODE_PINCFG_MASK);
+    port->OUTCLR.reg = pin_mask;
+
+    /* and set pull-up/pull-down if applicable */
+    if (mode == 0x7) {
+        port->OUTSET.reg = pin_mask;
+    }
+
     return 0;
 }
 
-int gpio_init_int(gpio_t pin, gpio_pp_t pullup, gpio_flank_t flank,
+int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
                   gpio_cb_t cb, void *arg)
 {
     int exti = _exti(pin);
@@ -138,7 +139,7 @@ int gpio_init_int(gpio_t pin, gpio_pp_t pullup, gpio_flank_t flank,
     gpio_config[exti].cb = cb;
     gpio_config[exti].arg = arg;
     /* configure pin as input and set MUX to peripheral function A */
-    gpio_init(pin, GPIO_DIR_IN, pullup);
+    gpio_init(pin, mode);
     gpio_init_mux(pin, GPIO_MUX_A);
     /* enable clocks for the EIC module */
     MCLK->APBAMASK.reg |= MCLK_APBAMASK_EIC;
diff --git a/cpu/saml21/periph/spi.c b/cpu/saml21/periph/spi.c
index 38c12cebcb1df4911f049241ff4898c326237d3f..617024308a0ad9b0eca4396734782904e65cde4f 100644
--- a/cpu/saml21/periph/spi.c
+++ b/cpu/saml21/periph/spi.c
@@ -134,10 +134,10 @@ int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
     while (!(GCLK->PCHCTRL[spi[dev].gclk_id].reg & GCLK_PCHCTRL_CHEN)) {}
 
     /* SCLK+MOSI = output */
-    gpio_init(spi[dev].sclk.pin, GPIO_DIR_OUT, GPIO_NOPULL);
-    gpio_init(spi[dev].mosi.pin, GPIO_DIR_OUT, GPIO_NOPULL);
+    gpio_init(spi[dev].sclk.pin, GPIO_OUT);
+    gpio_init(spi[dev].mosi.pin, GPIO_OUT);
     /* MISO = input */
-    gpio_init(spi[dev].miso.pin, GPIO_DIR_IN, GPIO_PULLUP);
+    gpio_init(spi[dev].miso.pin, GPIO_IN);
 
     /*
      * Set alternate funcion (PMUX) for our ports.