diff --git a/boards/frdm-k22f/include/periph_conf.h b/boards/frdm-k22f/include/periph_conf.h
index 18d9d07d7195e61d5b9da1c3297c8dda0e65035a..ea8e753bfa3e0d5b142a79ebf87c4b6f6df69103 100644
--- a/boards/frdm-k22f/include/periph_conf.h
+++ b/boards/frdm-k22f/include/periph_conf.h
@@ -106,6 +106,7 @@ static const uart_conf_t uart_config[] = {
         .scgc_addr = &SIM->SCGC4,
         .scgc_bit = SIM_SCGC4_UART1_SHIFT,
         .mode   = UART_MODE_8N1,
+        .type   = KINETIS_UART,
     },
 };
 
diff --git a/boards/frdm-k64f/include/periph_conf.h b/boards/frdm-k64f/include/periph_conf.h
index 1ead19eb72257457850d01e0bfa368fb44e254c5..ba79176c59f7e4b7cf50296fbc88cf637c009b70 100644
--- a/boards/frdm-k64f/include/periph_conf.h
+++ b/boards/frdm-k64f/include/periph_conf.h
@@ -102,7 +102,8 @@ static const uart_conf_t uart_config[] = {
         .irqn   = UART0_RX_TX_IRQn,
         .scgc_addr = &SIM->SCGC4,
         .scgc_bit = SIM_SCGC4_UART0_SHIFT,
-        .mode   = UART_MODE_8N1
+        .mode   = UART_MODE_8N1,
+        .type   = KINETIS_UART,
     },
 };
 
diff --git a/boards/mulle/include/periph_conf.h b/boards/mulle/include/periph_conf.h
index cad1b39f21f652e5fdfc7007191dc20d12e7abaa..8be821e34390198527a0756414423b1683c5ddc0 100644
--- a/boards/mulle/include/periph_conf.h
+++ b/boards/mulle/include/periph_conf.h
@@ -117,7 +117,8 @@ static const uart_conf_t uart_config[] = {
         .irqn   = UART0_RX_TX_IRQn,
         .scgc_addr = &SIM->SCGC4,
         .scgc_bit = SIM_SCGC4_UART0_SHIFT,
-        .mode   = UART_MODE_8N1
+        .mode   = UART_MODE_8N1,
+        .type   = KINETIS_UART,
     },
     {
         .dev    = UART1,
@@ -129,7 +130,8 @@ static const uart_conf_t uart_config[] = {
         .irqn   = UART1_RX_TX_IRQn,
         .scgc_addr = &SIM->SCGC4,
         .scgc_bit = SIM_SCGC4_UART1_SHIFT,
-        .mode   = UART_MODE_8N1
+        .mode   = UART_MODE_8N1,
+        .type   = KINETIS_UART,
     },
 };
 
diff --git a/boards/pba-d-01-kw2x/include/periph_conf.h b/boards/pba-d-01-kw2x/include/periph_conf.h
index 1c2670572601ac2be7ffb781f9072db277998591..25ea7dbdb1f234d90f53c7a40359f8dbc1d557ef 100644
--- a/boards/pba-d-01-kw2x/include/periph_conf.h
+++ b/boards/pba-d-01-kw2x/include/periph_conf.h
@@ -103,7 +103,8 @@ static const uart_conf_t uart_config[] = {
         .irqn   = UART2_RX_TX_IRQn,
         .scgc_addr = &SIM->SCGC4,
         .scgc_bit = SIM_SCGC4_UART2_SHIFT,
-        .mode   = UART_MODE_8N1
+        .mode   = UART_MODE_8N1,
+        .type   = KINETIS_UART,
     },
     {
         .dev    = UART0,
@@ -115,7 +116,8 @@ static const uart_conf_t uart_config[] = {
         .irqn   = UART0_RX_TX_IRQn,
         .scgc_addr = &SIM->SCGC4,
         .scgc_bit = SIM_SCGC4_UART0_SHIFT,
-        .mode   = UART_MODE_8N1
+        .mode   = UART_MODE_8N1,
+        .type   = KINETIS_UART,
     }
 };
 
diff --git a/cpu/kinetis_common/include/periph_cpu.h b/cpu/kinetis_common/include/periph_cpu.h
index bf49c6ffb971d6a69affcd06b6ef59cbd527bf70..246fb0e87d142d0ba65fa82a3d9d93d5a18285c4 100644
--- a/cpu/kinetis_common/include/periph_cpu.h
+++ b/cpu/kinetis_common/include/periph_cpu.h
@@ -199,16 +199,28 @@ typedef enum {
 #endif /* ndef DOXYGEN */
 
 /**
- * @name    CPU specific UART modes values
- * @{
+ * @brief    UART transmission modes
  */
-/** @brief 8 data bits, no parity, 1 stop bit */
-#define UART_MODE_8N1       (0)
-/** @brief 8 data bits, even parity, 1 stop bit */
-#define UART_MODE_8E1       (UART_C1_PE_MASK | UART_C1_M_MASK)
-/** @brief 8 data bits, odd parity, 1 stop bit */
-#define UART_MODE_8O1       (UART_C1_PE_MASK | UART_C1_M_MASK | UART_C1_PT_MASK)
-/** @} */
+typedef enum {
+    /** @brief 8 data bits, no parity, 1 stop bit */
+    UART_MODE_8N1 = 0,
+    /** @brief 8 data bits, even parity, 1 stop bit */
+#if defined(UART_C1_M_MASK)
+    /* LPUART and UART mode bits coincide, so the same setting for UART works on
+     * the LPUART as well */
+    UART_MODE_8E1 = (UART_C1_M_MASK | UART_C1_PE_MASK),
+#elif defined(LPUART_CTRL_M_MASK)
+    /* For CPUs which only have the LPUART */
+    UART_MODE_8E1 = (LPUART_CTRL_M_MASK | LPUART_CTRL_PE_MASK),
+#endif
+    /** @brief 8 data bits, odd parity, 1 stop bit */
+#if defined(UART_C1_M_MASK)
+    UART_MODE_8O1 = (UART_C1_M_MASK | UART_C1_PE_MASK | UART_C1_PT_MASK),
+#elif defined(LPUART_CTRL_M_MASK)
+    /* For CPUs which only have the LPUART */
+    UART_MODE_8O1 = (LPUART_CTRL_M_MASK | LPUART_CTRL_PE_MASK | LPUART_CTRL_PT_MASK),
+#endif
+} uart_mode_t;
 
 #ifndef DOXYGEN
 /**
@@ -309,11 +321,19 @@ enum {
 #define TIMER_LPTMR_DEV(x) (TIMER_DEV(PIT_NUMOF + (x)))
 /** @} */
 
+/**
+ * @brief UART hardware module types
+ */
+typedef enum {
+    KINETIS_UART,   /**< Kinetis UART module type */
+    KINETIS_LPUART, /**< Kinetis Low-power UART (LPUART) module type */
+} uart_type_t;
+
 /**
  * @brief UART module configuration options
  */
 typedef struct {
-    UART_Type *dev;               /**< Pointer to module hardware registers */
+    void *dev;                    /**< Pointer to module hardware registers */
     uint32_t freq;                /**< Module clock frequency, usually CLOCK_CORECLOCK or CLOCK_BUSCLOCK */
     gpio_t pin_rx;                /**< RX pin, GPIO_UNDEF disables RX */
     gpio_t pin_tx;                /**< TX pin */
@@ -322,7 +342,8 @@ typedef struct {
     IRQn_Type irqn;               /**< IRQ number for this module */
     volatile uint32_t *scgc_addr; /**< Clock enable register, in SIM module */
     uint8_t scgc_bit;             /**< Clock enable bit, within the register */
-    uint8_t mode;                 /**< UART mode: data bits, parity, stop bits */
+    uart_mode_t mode;             /**< UART mode: data bits, parity, stop bits */
+    uart_type_t type;             /**< Hardware module type (KINETIS_UART or KINETIS_LPUART)*/
 } uart_conf_t;
 
 #if !defined(KINETIS_HAVE_PLL)
diff --git a/cpu/kinetis_common/periph/uart.c b/cpu/kinetis_common/periph/uart.c
index 820d33f643af210f3fb85f5c3121642d0160df38..40b153ad09de09c72e28f99078781e7fe565a563 100644
--- a/cpu/kinetis_common/periph/uart.c
+++ b/cpu/kinetis_common/periph/uart.c
@@ -24,13 +24,30 @@
  * @}
  */
 
-#include <math.h>
-
 #include "cpu.h"
 #include "bit.h"
 #include "periph_conf.h"
 #include "periph/uart.h"
 
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+#ifndef KINETIS_HAVE_LPUART
+#ifdef LPUART0
+#define KINETIS_HAVE_LPUART      1
+#else
+#define KINETIS_HAVE_LPUART      0
+#endif
+#endif /* KINETIS_HAVE_LPUART */
+
+#ifndef KINETIS_HAVE_UART
+#ifdef UART0
+#define KINETIS_HAVE_UART      1
+#else
+#define KINETIS_HAVE_UART      0
+#endif
+#endif /* KINETIS_HAVE_LPUART */
+
 #ifndef KINETIS_UART_ADVANCED
 /**
  * Attempts to determine the type of the UART,
@@ -41,51 +58,90 @@
 #endif
 #endif
 
+#ifndef LPUART_OVERSAMPLING_RATE
+/* Use 16x oversampling by default (hardware defaults) */
+#define LPUART_OVERSAMPLING_RATE (16)
+#endif
+
 /**
- * @brief Allocate memory to store the callback functions.
+ * @brief Runtime configuration space, holds pointers to callback functions for RX
  */
 static uart_isr_ctx_t config[UART_NUMOF];
 
-static inline void kinetis_set_brfa(UART_Type *dev, uint32_t baudrate, uint32_t clk)
-{
-#if KINETIS_UART_ADVANCED
-    /* set baudrate fine adjust (brfa) */
-    uint8_t brfa = ((((4 * clk) / baudrate) + 1) / 2) % 32;
-    dev->C4 = UART_C4_BRFA(brfa);
+static inline void uart_init_pins(uart_t uart);
+
+#if KINETIS_HAVE_UART
+static inline void uart_init_uart(uart_t uart, uint32_t baudrate);
+#endif
+#if KINETIS_HAVE_LPUART
+static inline void uart_init_lpuart(uart_t uart, uint32_t baudrate);
 #endif
-}
 
-static int init_base(uart_t uart, uint32_t baudrate);
+/* Only use the dispatch function for uart_write if both UART and LPUART are
+ * available at the same time */
+#if KINETIS_HAVE_UART && KINETIS_HAVE_LPUART
+#define KINETIS_UART_WRITE_INLINE static inline
+KINETIS_UART_WRITE_INLINE void uart_write_uart(uart_t uart, const uint8_t *data, size_t len);
+KINETIS_UART_WRITE_INLINE void uart_write_lpuart(uart_t uart, const uint8_t *data, size_t len);
+#else
+#define KINETIS_UART_WRITE_INLINE
+#if KINETIS_HAVE_UART
+#define uart_write_uart uart_write
+#elif KINETIS_HAVE_LPUART
+#define uart_write_lpuart uart_write
+#endif
+#endif
 
 int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
 {
     assert(uart < UART_NUMOF);
-    /* do basic initialization */
-    int res = init_base(uart, baudrate);
-    if (res != UART_OK) {
-        return res;
-    }
-    UART_Type *dev = uart_config[uart].dev;
 
     /* remember callback addresses */
     config[uart].rx_cb = rx_cb;
     config[uart].arg = arg;
 
-    /* enable receive interrupt */
-    NVIC_EnableIRQ(uart_config[uart].irqn);
-    dev->C2 |= (1 << UART_C2_RIE_SHIFT);
+    uart_init_pins(uart);
 
+    /* Turn on module clock gate */
+    bit_set32(uart_config[uart].scgc_addr, uart_config[uart].scgc_bit);
+
+    switch (uart_config[uart].type) {
+#if KINETIS_HAVE_UART
+        case KINETIS_UART:
+            uart_init_uart(uart, baudrate);
+            break;
+#endif
+#if KINETIS_HAVE_LPUART
+        case KINETIS_LPUART:
+            uart_init_lpuart(uart, baudrate);
+            break;
+#endif
+        default:
+            return UART_NODEV;
+    }
     return UART_OK;
 }
 
-static int init_base(uart_t uart, uint32_t baudrate)
+#if KINETIS_HAVE_UART && KINETIS_HAVE_LPUART
+/* Dispatch function to pass to the proper write function depending on UART type
+ * This function is only used when the CPU supports both UART and LPUART. */
+void uart_write(uart_t uart, const uint8_t *data, size_t len)
 {
-    UART_Type *dev = uart_config[uart].dev;
-    uint32_t clk;
-    uint16_t ubd;
-
-    clk = uart_config[uart].freq;
+    switch (uart_config[uart].type) {
+        case KINETIS_UART:
+            uart_write_uart(uart, data, len);
+            break;
+        case KINETIS_LPUART:
+            uart_write_lpuart(uart, data, len);
+            break;
+        default:
+            return;
+    }
+}
+#endif
 
+static inline void uart_init_pins(uart_t uart)
+{
     /* initialize pins */
     if (uart_config[uart].pin_rx != GPIO_UNDEF) {
         gpio_init_port(uart_config[uart].pin_rx, uart_config[uart].pcr_rx);
@@ -93,13 +149,23 @@ static int init_base(uart_t uart, uint32_t baudrate)
     if (uart_config[uart].pin_tx != GPIO_UNDEF) {
         gpio_init_port(uart_config[uart].pin_tx, uart_config[uart].pcr_tx);
     }
+}
 
-    /* Turn on module clock gate */
-    bit_set32(uart_config[uart].scgc_addr, uart_config[uart].scgc_bit);
+#if KINETIS_HAVE_UART
+static inline void uart_init_uart(uart_t uart, uint32_t baudrate)
+{
+    /* do basic initialization */
+    UART_Type *dev = uart_config[uart].dev;
+
+    uint32_t clk;
+    uint16_t ubd;
+
+    clk = uart_config[uart].freq;
 
     /* disable transmitter and receiver */
     dev->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK);
-    /* set defaults, 8-bit mode, no parity */
+
+    /* Select mode */
     dev->C1 = uart_config[uart].mode;
 
     /* calculate baudrate */
@@ -108,9 +174,12 @@ static int init_base(uart_t uart, uint32_t baudrate)
     /* set baudrate */
     dev->BDH = (uint8_t)UART_BDH_SBR(ubd >> 8);
     dev->BDL = (uint8_t)UART_BDL_SBR(ubd);
-    kinetis_set_brfa(dev, baudrate, clk);
 
 #if KINETIS_UART_ADVANCED
+    /* set baudrate fine adjust (brfa) */
+    uint8_t brfa = ((((4 * clk) / baudrate) + 1) / 2) % 32;
+    dev->C4 = UART_C4_BRFA(brfa);
+
     /* Enable FIFO buffers */
     dev->PFIFO |= UART_PFIFO_RXFE_MASK | UART_PFIFO_TXFE_MASK;
     /* Set level to trigger TDRE flag whenever there is space in the TXFIFO */
@@ -118,8 +187,8 @@ static int init_base(uart_t uart, uint32_t baudrate)
      * TXFIFOSIZE == 0 means size = 1 (i.e. only one byte, no hardware FIFO) */
     if ((dev->PFIFO & UART_PFIFO_TXFIFOSIZE_MASK) != 0) {
         uint8_t txfifo_size =
-            (2 << ((dev->PFIFO & UART_PFIFO_TXFIFOSIZE_MASK) >>
-                    UART_PFIFO_TXFIFOSIZE_SHIFT));
+        (2 << ((dev->PFIFO & UART_PFIFO_TXFIFOSIZE_MASK) >>
+        UART_PFIFO_TXFIFOSIZE_SHIFT));
         dev->TWFIFO = UART_TWFIFO_TXWATER(txfifo_size - 1);
     }
     else {
@@ -131,14 +200,18 @@ static int init_base(uart_t uart, uint32_t baudrate)
     /* Clear all hardware buffers now, this must be done whenever the FIFO
      * enable flags are modified. */
     dev->CFIFO = UART_CFIFO_RXFLUSH_MASK | UART_CFIFO_TXFLUSH_MASK;
-#endif
+#endif /* KINETIS_UART_ADVANCED */
 
-    /* enable transmitter and receiver */
-    dev->C2 |= UART_C2_TE_MASK | UART_C2_RE_MASK;
-    return UART_OK;
+    /* enable transmitter and receiver + RX interrupt */
+    dev->C2 |= UART_C2_TE_MASK | UART_C2_RE_MASK | UART_C2_RIE_MASK;
+
+    /* enable receive interrupt */
+    NVIC_EnableIRQ(uart_config[uart].irqn);
 }
+#endif /* KINETIS_HAVE_UART */
 
-void uart_write(uart_t uart, const uint8_t *data, size_t len)
+#if KINETIS_HAVE_UART
+KINETIS_UART_WRITE_INLINE void uart_write_uart(uart_t uart, const uint8_t *data, size_t len)
 {
     UART_Type *dev = uart_config[uart].dev;
 
@@ -148,7 +221,7 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len)
     }
 }
 
-static inline void irq_handler(uart_t uart)
+static inline void irq_handler_uart(uart_t uart)
 {
     UART_Type *dev = uart_config[uart].dev;
 
@@ -183,34 +256,145 @@ static inline void irq_handler(uart_t uart)
 #ifdef UART_0_ISR
 void UART_0_ISR(void)
 {
-    irq_handler(UART_DEV(0));
+    irq_handler_uart(UART_DEV(0));
 }
 #endif
 
 #ifdef UART_1_ISR
 void UART_1_ISR(void)
 {
-    irq_handler(UART_DEV(1));
+    irq_handler_uart(UART_DEV(1));
 }
 #endif
 
 #ifdef UART_2_ISR
 void UART_2_ISR(void)
 {
-    irq_handler(UART_DEV(2));
+    irq_handler_uart(UART_DEV(2));
 }
 #endif
 
 #ifdef UART_3_ISR
 void UART_3_ISR(void)
 {
-    irq_handler(UART_DEV(3));
+    irq_handler_uart(UART_DEV(3));
 }
 #endif
 
 #ifdef UART_4_ISR
 void UART_4_ISR(void)
 {
-    irq_handler(UART_DEV(4));
+    irq_handler_uart(UART_DEV(4));
 }
 #endif
+
+#endif /* KINETIS_HAVE_UART */
+
+#if KINETIS_HAVE_LPUART
+static inline void uart_init_lpuart(uart_t uart, uint32_t baudrate)
+{
+    LPUART_Type *dev = uart_config[uart].dev;
+    uint32_t clk = uart_config[uart].freq;
+
+    /* Remember to select a module clock in board_init! (SIM->SOPT2[LPUART0SRC]) */
+
+    /* Select mode */
+    /* transmitter and receiver disabled */
+    dev->CTRL = uart_config[uart].mode;
+
+    /* calculate baud rate divisor */
+    uint32_t div = clk / (baudrate * LPUART_OVERSAMPLING_RATE);
+
+    /* set baud rate */
+    dev->BAUD = LPUART_BAUD_OSR(LPUART_OVERSAMPLING_RATE - 1) | LPUART_BAUD_SBR(div);
+
+    /* enable transmitter and receiver + RX interrupt */
+    dev->CTRL |= LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK | LPUART_CTRL_RIE_MASK;
+
+    /* enable receive interrupt */
+    NVIC_EnableIRQ(uart_config[uart].irqn);
+}
+
+KINETIS_UART_WRITE_INLINE void uart_write_lpuart(uart_t uart, const uint8_t *data, size_t len)
+{
+    LPUART_Type *dev = uart_config[uart].dev;
+
+    for (size_t i = 0; i < len; i++) {
+        while ((dev->STAT & LPUART_STAT_TDRE_MASK) == 0) {}
+        dev->DATA = data[i];
+    }
+}
+
+static inline void irq_handler_lpuart(uart_t uart)
+{
+    LPUART_Type *dev = uart_config[uart].dev;
+    uint32_t stat = dev->STAT;
+    /* Clear all IRQ flags */
+    dev->STAT = stat;
+
+    if (stat & LPUART_STAT_RDRF_MASK) {
+        /* RDRF flag will be cleared when LPUART_DATA is read */
+        uint8_t data = dev->DATA;
+        if (stat & (LPUART_STAT_FE_MASK | LPUART_STAT_PF_MASK)) {
+            if (stat & LPUART_STAT_FE_MASK) {
+                DEBUG("LPUART framing error %08" PRIx32 "\n", stat);
+            }
+            if (stat & LPUART_STAT_PF_MASK) {
+                DEBUG("LPUART parity error %08" PRIx32 "\n", stat);
+            }
+            /* FE is set whenever the next character to be read from LPUART_DATA
+             * was received with logic 0 detected where a stop bit was expected. */
+            /* PF is set whenever the next character to be read from LPUART_DATA
+             * was received when parity is enabled (PE = 1) and the parity bit in
+             * the received character does not agree with the expected parity value. */
+        }
+        /* Only run callback if no error occurred */
+        else if (config[uart].rx_cb != NULL) {
+            config[uart].rx_cb(config[uart].arg, data);
+        }
+    }
+    if (stat & LPUART_STAT_OR_MASK) {
+        /* Input buffer overflow, means that the software was too slow to
+         * receive the data */
+        DEBUG("LPUART overrun %08" PRIx32 "\n", stat);
+    }
+
+    cortexm_isr_end();
+}
+
+#ifdef LPUART_0_ISR
+void LPUART_0_ISR(void)
+{
+    irq_handler_lpuart(UART_DEV(0));
+}
+#endif
+
+#ifdef LPUART_1_ISR
+void LPUART_1_ISR(void)
+{
+    irq_handler_lpuart(UART_DEV(1));
+}
+#endif
+
+#ifdef LPUART_2_ISR
+void LPUART_2_ISR(void)
+{
+    irq_handler_lpuart(UART_DEV(2));
+}
+#endif
+
+#ifdef LPUART_3_ISR
+void LPUART_3_ISR(void)
+{
+    irq_handler_lpuart(UART_DEV(3));
+}
+#endif
+
+#ifdef LPUART_4_ISR
+void LPUART_4_ISR(void)
+{
+    irq_handler_lpuart(UART_DEV(4));
+}
+#endif
+
+#endif /* KINETIS_HAVE_LPUART */