diff --git a/cpu/lpc2387/include/lpc23xx.h b/cpu/lpc2387/include/lpc23xx.h
index b6de1a990f872c165b9cbae880d39ff328c1ce39..dac007043730aabba916c01e4ae169e6c656ad90 100644
--- a/cpu/lpc2387/include/lpc23xx.h
+++ b/cpu/lpc2387/include/lpc23xx.h
@@ -12,13 +12,20 @@
  *
 ******************************************************************************/
 
-#ifndef __LPC23xx_H
-#define __LPC23xx_H
+#ifndef LPC23XX_H
+#define LPC23XX_H
+
+#include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/**
+ * @brief   Type for 32-bit registers
+ */
+#define REG32       volatile uint32_t
+
 /* Vectored Interrupt Controller (VIC) */
 #define VIC_BASE_ADDR   0xFFFFF000
 #define VICIRQStatus   (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x000))
@@ -496,8 +503,27 @@ are for LPC24xx only. */
 
 #define EMC_STA_EXT_WAIT  (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x880))
 
+/**
+ * @brief   Generic timer register map
+ */
+typedef struct {
+    REG32   IR;             /**< interrupt register */
+    REG32   TCR;            /**< timer control register */
+    REG32   TC;             /**< timer counter */
+    REG32   PR;             /**< prescale register */
+    REG32   PC;             /**< prescale counter */
+    REG32   MCR;            /**< match control register */
+    REG32   MR[4];          /**< match registers 1-4 */
+    REG32   CCR;            /**< capture control register */
+    REG32   CR[4];          /**< capture register 1-4 */
+    REG32   EMR;            /**< external match register */
+    REG32   reserved[12];   /**< reserved */
+    REG32   CTCR;           /**< count control register */
+} lpc23xx_timer_t;
+
 /* Timer 0 */
 #define TMR0_BASE_ADDR      0xE0004000
+#define TMR0                ((lpc23xx_timer_t *)TMR0_BASE_ADDR)
 #define T0IR           (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x00))
 #define T0TCR          (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x04))
 #define T0TC           (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x08))
@@ -518,6 +544,7 @@ are for LPC24xx only. */
 
 /* Timer 1 */
 #define TMR1_BASE_ADDR      0xE0008000
+#define TMR1                ((lpc23xx_timer_t *)TMR1_BASE_ADDR)
 #define T1IR           (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x00))
 #define T1TCR          (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x04))
 #define T1TC           (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x08))
@@ -538,6 +565,7 @@ are for LPC24xx only. */
 
 /* Timer 2 */
 #define TMR2_BASE_ADDR      0xE0070000
+#define TMR2                ((lpc23xx_timer_t *)TMR2_BASE_ADDR)
 #define T2IR           (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x00))
 #define T2TCR          (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x04))
 #define T2TC           (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x08))
@@ -558,6 +586,7 @@ are for LPC24xx only. */
 
 /* Timer 3 */
 #define TMR3_BASE_ADDR      0xE0074000
+#define TMR3                ((lpc23xx_timer_t *)TMR3_BASE_ADDR)
 #define T3IR           (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x00))
 #define T3TCR          (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x04))
 #define T3TC           (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x08))
@@ -1134,4 +1163,4 @@ with the spec. update in USB Device Section. */
 }
 #endif
 
-#endif  // __LPC23xx_H
+#endif  /* LPC23XX_H */
diff --git a/cpu/lpc2387/include/periph_cpu.h b/cpu/lpc2387/include/periph_cpu.h
index 47a07255fd301ec0c771158f304fcc917d2e02d7..8fccc27687ed8b5725dae9602f3861c2f6860902 100644
--- a/cpu/lpc2387/include/periph_cpu.h
+++ b/cpu/lpc2387/include/periph_cpu.h
@@ -71,7 +71,12 @@ typedef enum {
 } gpio_flank_t;
 
 /**
- * @brief declare needed generic SPI functions
+ * @brief   Number of available timer channels
+ */
+#define TIMER_CHAN_NUMOF        (4U)
+
+/**
+ * @brief   Declare needed generic SPI functions
  * @{
  */
 #define PERIPH_SPI_NEEDS_TRANSFER_BYTES
diff --git a/cpu/lpc2387/periph/timer.c b/cpu/lpc2387/periph/timer.c
new file mode 100644
index 0000000000000000000000000000000000000000..6b1e783cb9160c9c891c632c1deea24df0b563ef
--- /dev/null
+++ b/cpu/lpc2387/periph/timer.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2015 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_lpc2387
+ * @{
+ *
+ * @file
+ * @brief       Implementation of the low-level timer driver for the LPC2387
+ *
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ * @}
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "periph_conf.h"
+#include "periph_cpu.h"
+#include "periph/timer.h"
+
+/**
+ * @brief   Check the board config to make sure we do not exceed max number of
+ *          timers
+ */
+#if TIMER_NUMOF > 3
+#error "ERROR in timer configuration: too many timers defined"
+#endif
+
+/**
+ * @brief   Interrupt context information for configured timers
+ */
+static timer_isr_ctx_t isr_ctx[TIMER_NUMOF];
+
+/**
+ * @brief   Forward declarations for interrupt functions
+ * @{
+ */
+void tim_isr_0(void);
+void tim_isr_1(void);
+void tim_isr_2(void);
+void tim_isr_3(void);
+/** @} */
+
+/**
+ * @brief   Get the base pointer of a timer
+ */
+static inline lpc23xx_timer_t *get_dev(tim_t tim)
+{
+    switch (tim) {
+        case 0:
+            return TMR0;
+#if TIMER_NUMOF > 1
+        case 1:
+            return TMR1;
+#endif
+#if TIMER_NUMOF > 2
+        case 2:
+            return TMR2;
+#endif
+#if TIMER_NUMOF > 3
+        case 3:
+            return TMR3;
+#endif
+        default:
+            return NULL;
+    }
+}
+
+static inline void pwr_clk_and_isr(tim_t tim)
+{
+    switch (tim) {
+        case 0:
+            PCONP |= (1 << 1);
+            PCLKSEL0 &= ~(0x03 << 2);
+            PCLKSEL0 |=  (0x01 << 2);
+            install_irq(TIMER0_INT, &tim_isr_0, 1);
+            break;
+#if TIMER_NUMOF > 1
+        case 1:
+            PCONP |= (1 << 2);
+            PCLKSEL0 &= ~(0x03 << 4);
+            PCLKSEL0 |=  (0x01 << 4);
+            install_irq(TIMER1_INT, &tim_isr_1, 1);
+            break;
+#endif
+#if TIMER_NUMOF > 2
+        case 2:
+            PCONP |= (1 << 22);
+            PCLKSEL1 &= ~(0x03 << 12);
+            PCLKSEL1 |=  (0x01 << 12);
+            install_irq(TIMER2_INT, &tim_isr_2, 1);
+            break;
+#endif
+#if TIMER_NUMOF > 3
+        case 3:
+            PCONP |= (1 << 23);
+            PCLKSEL1 &= ~(0x03 << 14);
+            PCLKSEL1 |=  (0x01 << 14);
+            install_irq(TIMER3_INT, &tim_isr_3, 1);
+            break;
+#endif
+    }
+}
+
+int timer_init(tim_t tim, unsigned int us_per_tick, void (*callback)(int))
+{
+    /* get the timers base register */
+    lpc23xx_timer_t *dev = get_dev(tim);
+
+    /* make sure the timer device is valid */
+    if (dev == NULL) {
+        return -1;
+    }
+
+    /* save the callback */
+    isr_ctx[tim].cb = callback;
+    /* enable power, config periph clock and install ISR vector */
+    pwr_clk_and_isr(tim);
+    /* reset timer configuration (sets the timer to timer mode) */
+    dev->TCR = 0;
+    dev->CTCR = 0;
+    /* configure the prescaler */
+    dev->PR = (us_per_tick * ((CLOCK_PCLK / 1000000) - 1));
+    /* enable timer */
+    dev->TCR = 1;
+    return 0;
+}
+
+int timer_set(tim_t tim, int channel, unsigned int timeout)
+{
+    unsigned int now = timer_read(tim);
+    return timer_set_absolute(tim, channel, (timeout + now));
+}
+
+int timer_set_absolute(tim_t tim, int channel, unsigned int value)
+{
+    if (tim >= TIMER_NUMOF || channel >= TIMER_CHAN_NUMOF) {
+        return -1;
+    }
+
+    lpc23xx_timer_t *dev = get_dev(tim);
+    dev->MR[channel] = value;
+    dev->MCR |= (1 << (channel * 3));
+    return 0;
+}
+
+int timer_clear(tim_t tim, int channel)
+{
+    if (tim >= TIMER_NUMOF || channel >= TIMER_CHAN_NUMOF) {
+        return -1;
+    }
+    get_dev(tim)->MCR &= ~(1 << (channel * 3));
+    return 0;
+}
+
+unsigned int timer_read(tim_t tim)
+{
+    return (unsigned int)(get_dev(tim)->TC);
+}
+
+void timer_start(tim_t tim)
+{
+    get_dev(tim)->TCR = 1;
+}
+
+void timer_stop(tim_t tim)
+{
+    get_dev(tim)->TCR = 0;
+}
+
+void timer_reset(tim_t tim)
+{
+    lpc23xx_timer_t *dev = get_dev(tim);
+    dev->TCR |= 2;
+    asm("nop");
+    dev->TCR &= ~(2);
+}
+
+void timer_irq_enable(tim_t tim)
+{
+    /* TODO */
+}
+
+void timer_irq_disable(tim_t tim)
+{
+    /* TODO */
+}
+
+static inline void isr_handler(lpc23xx_timer_t *dev, int tim_num)
+{
+    for (int i = 0; i < TIMER_CHAN_NUMOF; i++) {
+        if (dev->IR & (1 << i)) {
+            dev->IR |= (1 << i);
+            dev->MCR &= ~(1 << (i * 3));
+            isr_ctx[tim_num].cb(i);
+        }
+    }
+    /* we must not forget to acknowledge the handling of the interrupt */
+    VICVectAddr = 0;
+}
+
+void __attribute__((interrupt("IRQ"))) tim_isr_0(void)
+{
+    isr_handler(TMR0, 0);
+}
+
+#if TIMER_NUMOF > 1
+void __attribute__((interrupt("IRQ"))) tim_isr_1(void)
+{
+    isr_handler(TMR1, 1);
+}
+#endif
+
+#if TIMER_NUMOF > 2
+void __attribute__((interrupt("IRQ"))) tim_isr_2(void)
+{
+    isr_handler(TMR2, 2);
+}
+#endif
+
+#if TIMER_NUMOF > 3
+void __attribute__((interrupt("IRQ"))) tim_isr_3(void)
+{
+    isr_handler(TMR3, 3);
+}
+#endif