diff --git a/boards/cc2538dk/include/board.h b/boards/cc2538dk/include/board.h
index e10c371235e44cc141bd0c84b463f54f5f8765a8..137d4076bb1c60ea8b70042941868389f4c9850b 100644
--- a/boards/cc2538dk/include/board.h
+++ b/boards/cc2538dk/include/board.h
@@ -76,9 +76,9 @@ extern "C" {
  * @name xtimer configuration
  * @{
  */
-#define XTIMER_DEV          TIMER_0
+#define XTIMER_DEV          (0)
 #define XTIMER_CHAN         (0)
-#define XTIMER_SHIFT        (-4)
+#define XTIMER_WIDTH        (16)
 #define XTIMER_BACKOFF      (50)
 #define XTIMER_ISR_BACKOFF  (40)
 /** @} */
diff --git a/boards/cc2538dk/include/periph_conf.h b/boards/cc2538dk/include/periph_conf.h
index 81dd78c9ba701fd4af748f6808de8e70cb589def..2fa453802f892a30a8bcb69f6047aa3e03f181e8 100644
--- a/boards/cc2538dk/include/periph_conf.h
+++ b/boards/cc2538dk/include/periph_conf.h
@@ -30,49 +30,32 @@ extern "C" {
  * @name Timer peripheral configuration
  * @{
  */
-#define TIMER_NUMOF         GPTIMER_NUMOF
-#define TIMER_0_EN          1
-#define TIMER_1_EN          1
-#define TIMER_2_EN          1
-#define TIMER_3_EN          1
+static const timer_conf_t timer_config[] = {
+    {
+        .dev      = GPTIMER0,
+        .channels = 2,
+        .cfg      = GPTMCFG_16_BIT_TIMER, /* required for XTIMER */
+    },
+    {
+        .dev      = GPTIMER1,
+        .channels = 1,
+        .cfg      = GPTMCFG_32_BIT_TIMER,
+    },
+    {
+        .dev      = GPTIMER2,
+        .channels = 1,
+        .cfg      = GPTMCFG_32_BIT_TIMER,
+    },
+    {
+        .dev      = GPTIMER3,
+        .channels = 1,
+        .cfg      = GPTMCFG_32_BIT_TIMER,
+    },
+};
 
-#define TIMER_IRQ_PRIO      1
+#define TIMER_NUMOF         (sizeof(timer_config) / sizeof(timer_config[0]))
 
-/* Timer 0 configuration */
-#define TIMER_0_DEV         GPTIMER0
-#define TIMER_0_CHANNELS    1
-#define TIMER_0_MAX_VALUE   0xffffffff
-#define TIMER_0_IRQn_1      GPTIMER_0A_IRQn
-#define TIMER_0_IRQn_2      GPTIMER_0B_IRQn
-#define TIMER_0_ISR_1       isr_timer0_chan0
-#define TIMER_0_ISR_2       isr_timer0_chan1
-
-/* Timer 1 configuration */
-#define TIMER_1_DEV         GPTIMER1
-#define TIMER_1_CHANNELS    1
-#define TIMER_1_MAX_VALUE   0xffffffff
-#define TIMER_1_IRQn_1      GPTIMER_1A_IRQn
-#define TIMER_1_IRQn_2      GPTIMER_1B_IRQn
-#define TIMER_1_ISR_1       isr_timer1_chan0
-#define TIMER_1_ISR_2       isr_timer1_chan1
-
-/* Timer 2 configuration */
-#define TIMER_2_DEV         GPTIMER2
-#define TIMER_2_CHANNELS    1
-#define TIMER_2_MAX_VALUE   0xffffffff
-#define TIMER_2_IRQn_1      GPTIMER_2A_IRQn
-#define TIMER_2_IRQn_2      GPTIMER_2B_IRQn
-#define TIMER_2_ISR_1       isr_timer2_chan0
-#define TIMER_2_ISR_2       isr_timer2_chan1
-
-/* Timer 3 configuration */
-#define TIMER_3_DEV         GPTIMER3
-#define TIMER_3_CHANNELS    1
-#define TIMER_3_MAX_VALUE   0xffffffff
-#define TIMER_3_IRQn_1      GPTIMER_3A_IRQn
-#define TIMER_3_IRQn_2      GPTIMER_3B_IRQn
-#define TIMER_3_ISR_1       isr_timer3_chan0
-#define TIMER_3_ISR_2       isr_timer3_chan1
+#define TIMER_IRQ_PRIO      1
 /** @} */
 
 
diff --git a/boards/openmote-cc2538/include/board.h b/boards/openmote-cc2538/include/board.h
index 53f06cff3b0a3780d9a86c1fb1a142ad6b80fe56..cd58a4f510b325dadbbfd437af736de847c34293 100644
--- a/boards/openmote-cc2538/include/board.h
+++ b/boards/openmote-cc2538/include/board.h
@@ -64,9 +64,9 @@
  * @name xtimer configuration
  * @{
  */
-#define XTIMER_DEV          TIMER_0
+#define XTIMER_DEV          (0)
 #define XTIMER_CHAN         (0)
-#define XTIMER_SHIFT        (-4)
+#define XTIMER_WIDTH        (16)
 #define XTIMER_BACKOFF      (50)
 #define XTIMER_ISR_BACKOFF  (40)
 /** @} */
diff --git a/boards/openmote-cc2538/include/periph_conf.h b/boards/openmote-cc2538/include/periph_conf.h
index d65c08b0e5597e082cde5a3370734b78badc2b9f..a53eb7a07a1aca7c4bf3b27d229dc5e7af79fbd0 100644
--- a/boards/openmote-cc2538/include/periph_conf.h
+++ b/boards/openmote-cc2538/include/periph_conf.h
@@ -37,48 +37,31 @@
  * @name Timer configuration
  * @{
  */
-#define TIMER_NUMOF         (4U)
-#define TIMER_0_EN          1
-#define TIMER_1_EN          1
-#define TIMER_2_EN          1
-#define TIMER_3_EN          1
-#define TIMER_IRQ_PRIO      1
+static const timer_conf_t timer_config[] = {
+    {
+        .dev      = GPTIMER0,
+        .channels = 2,
+        .cfg      = GPTMCFG_16_BIT_TIMER, /* required for XTIMER */
+    },
+    {
+        .dev      = GPTIMER1,
+        .channels = 1,
+        .cfg      = GPTMCFG_32_BIT_TIMER,
+    },
+    {
+        .dev      = GPTIMER2,
+        .channels = 1,
+        .cfg      = GPTMCFG_32_BIT_TIMER,
+    },
+    {
+        .dev      = GPTIMER3,
+        .channels = 1,
+        .cfg      = GPTMCFG_32_BIT_TIMER,
+    },
+};
 
-/* Timer 0 configuration */
-#define TIMER_0_DEV         GPTIMER0
-#define TIMER_0_CHANNELS    1
-#define TIMER_0_MAX_VALUE   0xffffffff
-#define TIMER_0_IRQn_1      GPTIMER_0A_IRQn
-#define TIMER_0_IRQn_2      GPTIMER_0B_IRQn
-#define TIMER_0_ISR_1       isr_timer0_chan0
-#define TIMER_0_ISR_2       isr_timer0_chan1
-
-/* Timer 1 configuration */
-#define TIMER_1_DEV         GPTIMER1
-#define TIMER_1_CHANNELS    1
-#define TIMER_1_MAX_VALUE   0xffffffff
-#define TIMER_1_IRQn_1      GPTIMER_1A_IRQn
-#define TIMER_1_IRQn_2      GPTIMER_1B_IRQn
-#define TIMER_1_ISR_1       isr_timer1_chan0
-#define TIMER_1_ISR_2       isr_timer1_chan1
-
-/* Timer 2 configuration */
-#define TIMER_2_DEV         GPTIMER2
-#define TIMER_2_CHANNELS    1
-#define TIMER_2_MAX_VALUE   0xffffffff
-#define TIMER_2_IRQn_1      GPTIMER_2A_IRQn
-#define TIMER_2_IRQn_2      GPTIMER_2B_IRQn
-#define TIMER_2_ISR_1       isr_timer2_chan0
-#define TIMER_2_ISR_2       isr_timer2_chan1
-
-/* Timer 3 configuration */
-#define TIMER_3_DEV         GPTIMER3
-#define TIMER_3_CHANNELS    1
-#define TIMER_3_MAX_VALUE   0xffffffff
-#define TIMER_3_IRQn_1      GPTIMER_3A_IRQn
-#define TIMER_3_IRQn_2      GPTIMER_3B_IRQn
-#define TIMER_3_ISR_1       isr_timer3_chan0
-#define TIMER_3_ISR_2       isr_timer3_chan1
+#define TIMER_NUMOF         (sizeof(timer_config) / sizeof(timer_config[0]))
+#define TIMER_IRQ_PRIO      1
 /** @} */
 
 /**
diff --git a/boards/remote-common/include/board_common.h b/boards/remote-common/include/board_common.h
index 42ec7ed82e9eb7bfdf17facac518d24aee9550c4..47b317aa617e349a62a122d3c565f32b75c6bf50 100644
--- a/boards/remote-common/include/board_common.h
+++ b/boards/remote-common/include/board_common.h
@@ -77,9 +77,9 @@
  * @name xtimer configuration
  * @{
  */
-#define XTIMER_DEV          TIMER_0
+#define XTIMER_DEV          (0)
 #define XTIMER_CHAN         (0)
-#define XTIMER_SHIFT        (-4)
+#define XTIMER_WIDTH        (16)
 #define XTIMER_BACKOFF      (50)
 #define XTIMER_ISR_BACKOFF  (40)
 /** @} */
diff --git a/boards/remote-common/include/periph_common.h b/boards/remote-common/include/periph_common.h
index 583d49627da33b40a5ca7ea95b3fa4515b0b1f7b..2a83f262bd17995bd372f8ae086148928c2e0abb 100644
--- a/boards/remote-common/include/periph_common.h
+++ b/boards/remote-common/include/periph_common.h
@@ -39,49 +39,32 @@
  * @name Timer configuration
  * @{
  */
-#define TIMER_NUMOF         (4U)
-#define TIMER_0_EN          1
-#define TIMER_1_EN          1
-#define TIMER_2_EN          1
-#define TIMER_3_EN          1
+static const timer_conf_t timer_config[] = {
+    {
+        .dev      = GPTIMER0,
+        .channels = 2,
+        .cfg      = GPTMCFG_16_BIT_TIMER, /* required for XTIMER */
+    },
+    {
+        .dev      = GPTIMER1,
+        .channels = 1,
+        .cfg      = GPTMCFG_32_BIT_TIMER,
+    },
+    {
+        .dev      = GPTIMER2,
+        .channels = 1,
+        .cfg      = GPTMCFG_32_BIT_TIMER,
+    },
+    {
+        .dev      = GPTIMER3,
+        .channels = 1,
+        .cfg      = GPTMCFG_32_BIT_TIMER,
+    },
+};
 
-#define TIMER_IRQ_PRIO      1
-
-/* Timer 0 configuration */
-#define TIMER_0_DEV         GPTIMER0
-#define TIMER_0_CHANNELS    1
-#define TIMER_0_MAX_VALUE   0xffffffff
-#define TIMER_0_IRQn_1      GPTIMER_0A_IRQn
-#define TIMER_0_IRQn_2      GPTIMER_0B_IRQn
-#define TIMER_0_ISR_1       isr_timer0_chan0
-#define TIMER_0_ISR_2       isr_timer0_chan1
-
-/* Timer 1 configuration */
-#define TIMER_1_DEV         GPTIMER1
-#define TIMER_1_CHANNELS    1
-#define TIMER_1_MAX_VALUE   0xffffffff
-#define TIMER_1_IRQn_1      GPTIMER_1A_IRQn
-#define TIMER_1_IRQn_2      GPTIMER_1B_IRQn
-#define TIMER_1_ISR_1       isr_timer1_chan0
-#define TIMER_1_ISR_2       isr_timer1_chan1
+#define TIMER_NUMOF         (sizeof(timer_config) / sizeof(timer_config[0]))
 
-/* Timer 2 configuration */
-#define TIMER_2_DEV         GPTIMER2
-#define TIMER_2_CHANNELS    1
-#define TIMER_2_MAX_VALUE   0xffffffff
-#define TIMER_2_IRQn_1      GPTIMER_2A_IRQn
-#define TIMER_2_IRQn_2      GPTIMER_2B_IRQn
-#define TIMER_2_ISR_1       isr_timer2_chan0
-#define TIMER_2_ISR_2       isr_timer2_chan1
-
-/* Timer 3 configuration */
-#define TIMER_3_DEV         GPTIMER3
-#define TIMER_3_CHANNELS    1
-#define TIMER_3_MAX_VALUE   0xffffffff
-#define TIMER_3_IRQn_1      GPTIMER_3A_IRQn
-#define TIMER_3_IRQn_2      GPTIMER_3B_IRQn
-#define TIMER_3_ISR_1       isr_timer3_chan0
-#define TIMER_3_ISR_2       isr_timer3_chan1
+#define TIMER_IRQ_PRIO      1
 /** @} */
 
 /**
diff --git a/cpu/cc2538/include/periph_cpu.h b/cpu/cc2538/include/periph_cpu.h
index bbb17a2862d330e07cca77a08f4e2e39bb6f003d..81fc4b2ef0337947a4ba1a491703c80f58407011 100644
--- a/cpu/cc2538/include/periph_cpu.h
+++ b/cpu/cc2538/include/periph_cpu.h
@@ -21,6 +21,7 @@
 
 #include <stdint.h>
 
+#include "cc2538_gptimer.h"
 #include "cc2538_ssi.h"
 #include "cc2538_gpio.h"
 
@@ -73,6 +74,15 @@ typedef struct {
     gpio_t cs_pin;          /**< pin used for CS */
 } periph_spi_conf_t;
 
+/**
+ * @brief   Timer configuration data
+ */
+typedef struct {
+    cc2538_gptimer_t *dev;  /**< timer device */
+    uint_fast8_t channels;  /**< number of channels */
+    uint_fast8_t cfg;       /**< timer config word */
+} timer_conf_t;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/cpu/cc2538/periph/timer.c b/cpu/cc2538/periph/timer.c
index d4ba03db9b831416b729ef8c5fd7e16fdfcbbec0..9e0444989caa624e547ca4b7456d778b1e8962a3 100644
--- a/cpu/cc2538/periph/timer.c
+++ b/cpu/cc2538/periph/timer.c
@@ -18,8 +18,8 @@
  * @}
  */
 
-#include <stdlib.h>
-#include <stdio.h>
+#include <assert.h>
+#include <stdint.h>
 
 #include "board.h"
 #include "cpu.h"
@@ -28,17 +28,44 @@
 #include "periph/timer.h"
 #include "periph_conf.h"
 
-#define TIMER_A_IRQ_MASK 0x000000ff
-#define TIMER_B_IRQ_MASK 0x0000ff00
+#define ENABLE_DEBUG (0)
+#include "debug.h"
 
-#define NUM_CHANNELS     1
+#define LOAD_VALUE               0xffff
+
+#define TIMER_A_IRQ_MASK         0x000000ff
+#define TIMER_B_IRQ_MASK         0x0000ff00
+
+#define BIT(n)                   ( 1UL << (n) )
+
+/* GPTIMER_CTL Bits: */
+#define TBEN                     BIT(8)
+#define TAEN                     BIT(0)
+
+/* GPTIMER_TnMR Bits: */
+#define TnCMIE                   BIT(5)
+#define TnCDIR                   BIT(4)
+
+/* GPTIMER_IMR Bits: */
+#define TBMIM                    BIT(11)
+#define TAMIM                    BIT(4)
+
+/* Convert a gptimer instance pointer to a GPTimer number */
+#define GPTIMER_GET_NUM(gptimer) ( ((uintptr_t)(gptimer) >> 12) & 0x3 )
+
+#define match_bit(chan)          ( (chan)? TBMIM : TAMIM )
 
 /**
  * @brief Timer state memory
  */
-static timer_isr_ctx_t config[TIMER_NUMOF];
-static unsigned long config_freq[TIMER_NUMOF];
+static timer_isr_ctx_t config[GPTIMER_NUMOF];
 
+static const int IRQn_lut[GPTIMER_NUMOF] = {
+    GPTIMER_0A_IRQn,
+    GPTIMER_1A_IRQn,
+    GPTIMER_2A_IRQn,
+    GPTIMER_3A_IRQn
+};
 
 /**
  * @brief Setup the given timer
@@ -46,43 +73,22 @@ static unsigned long config_freq[TIMER_NUMOF];
  */
 int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
 {
-    cc2538_gptimer_t *gptimer;
+    cc2538_gptimer_t *gptimer = timer_config[dev].dev;
     unsigned int gptimer_num;
+    uint32_t chan_mode;
 
-    /* select the timer and enable the timer specific peripheral clocks */
-    switch (dev) {
-#if TIMER_0_EN
-        case TIMER_0:
-            gptimer = TIMER_0_DEV;
-            break;
-#endif
-#if TIMER_1_EN
-        case TIMER_1:
-            gptimer = TIMER_1_DEV;
-            break;
-#endif
-#if TIMER_2_EN
-        case TIMER_2:
-            gptimer = TIMER_2_DEV;
-            break;
-#endif
-#if TIMER_3_EN
-        case TIMER_3:
-            gptimer = TIMER_3_DEV;
-            break;
-#endif
+    DEBUG("%s(%u, %lu, %p, %p)\n", __FUNCTION__, dev, freq, cb, arg);
 
-        case TIMER_UNDEFINED:
-        default:
-            return -1;
+    if (dev >= TIMER_NUMOF) {
+        return -1;
     }
 
-    gptimer_num = ((uintptr_t)gptimer - (uintptr_t)GPTIMER0) / 0x1000;
+    gptimer_num = GPTIMER_GET_NUM(gptimer);
 
     /* Save the callback function: */
-    config[dev].cb = cb;
-    config[dev].arg = arg;
-    config_freq[dev] = freq;
+    assert(gptimer_num < GPTIMER_NUMOF);
+    config[gptimer_num].cb  = cb;
+    config[gptimer_num].arg = arg;
 
     /* Enable the clock for this timer: */
     SYS_CTRL_RCGCGPT |= (1 << gptimer_num);
@@ -90,155 +96,134 @@ int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
     /* Disable this timer before configuring it: */
     gptimer->cc2538_gptimer_ctl.CTL = 0;
 
-    gptimer->CFG  = GPTMCFG_32_BIT_TIMER;
-    gptimer->cc2538_gptimer_tamr.TAMR = GPTIMER_PERIODIC_MODE;
-    gptimer->cc2538_gptimer_tamr.TAMRbits.TACDIR = 1; /**< Count up */
-    gptimer->cc2538_gptimer_tamr.TAMRbits.TAMIE  = 1; /**< Enable the Timer A Match Interrupt */
+    if (timer_config[dev].cfg == GPTMCFG_32_BIT_TIMER) {
+        /* Count up in periodic mode */
+        chan_mode = TnCMIE | TnCDIR | GPTIMER_PERIODIC_MODE;
+
+        if (timer_config[dev].channels > 1) {
+            DEBUG("Invalid timer_config. Multiple channels are available only in 16-bit mode.");
+            return -1;
+        }
+
+        if (freq != sys_clock_freq()) {
+            DEBUG("In 32-bit mode, the GPTimer frequency must equal the system clock frequency (%u).", sys_clock_freq());
+            return -1;
+        }
+    } else {
+        /* Count down in periodic mode */
+        chan_mode = TnCMIE | GPTIMER_PERIODIC_MODE;
+    }
+
+    gptimer->CFG = timer_config[dev].cfg;
+    gptimer->cc2538_gptimer_tamr.TAMR = chan_mode;
+
+    switch (timer_config[dev].channels) {
+        case 1:
+            /* Enable the timer: */
+            gptimer->cc2538_gptimer_ctl.CTL = TAEN;
+            break;
+
+        case 2:
+            gptimer->cc2538_gptimer_tbmr.TBMR = chan_mode;
+
+            gptimer->TAILR = LOAD_VALUE;
+            gptimer->TBILR = LOAD_VALUE;
+
+            uint32_t prescaler = sys_clock_freq();
+            prescaler += freq / 2;
+            prescaler /= freq;
+            if (prescaler >   0) prescaler--;
+            if (prescaler > 255) prescaler = 255;
+
+            gptimer->TAPR = prescaler;
+            gptimer->TBPR = prescaler;
+
+            /* Enable the timer: */
+            gptimer->cc2538_gptimer_ctl.CTL = TBEN | TAEN;
+            break;
+    }
 
     /* Enable interrupts for given timer: */
     timer_irq_enable(dev);
 
-    /* Enable the timer: */
-    gptimer->cc2538_gptimer_ctl.CTLbits.TAEN = 1;
-
     return 0;
 }
 
 int timer_set(tim_t dev, int channel, unsigned int timeout)
 {
-    cc2538_gptimer_t *gptimer;
+    /* get timer base register address */
+    cc2538_gptimer_t *gptimer = timer_config[dev].dev;
 
-    if (channel >= NUM_CHANNELS) {
+    if ( (dev >= TIMER_NUMOF) || (channel >= timer_config[dev].channels) ) {
         return -1;
     }
 
-    /* get timer base register address */
-    switch (dev) {
-#if TIMER_0_EN
-        case TIMER_0:
-            gptimer = TIMER_0_DEV;
-            break;
-#endif
-#if TIMER_1_EN
-        case TIMER_1:
-            gptimer = TIMER_1_DEV;
-            break;
-#endif
-#if TIMER_2_EN
-        case TIMER_2:
-            gptimer = TIMER_2_DEV;
-            break;
-#endif
-#if TIMER_3_EN
-        case TIMER_3:
-            gptimer = TIMER_3_DEV;
-            break;
-#endif
-        case TIMER_UNDEFINED:
-        default:
-            return -1;
-    }
+    switch (channel) {
+        case 0:
+            /* clear any pending match interrupts */
+            gptimer->ICR = TAMIM;
 
-    /* set timeout value */
-    gptimer->ICR           = TIMER_A_IRQ_MASK; /**< Clear any pending interrupt status */
+            /* set timeout value */
+            gptimer->TAMATCHR = (gptimer->CFG == GPTMCFG_32_BIT_TIMER)? (gptimer->TAV + timeout) : (gptimer->TAV - timeout);
+            gptimer->cc2538_gptimer_imr.IMR |= TAMIM; /**< Enable the Timer A Match Interrupt */
+            break;
 
-    uint64_t scaled_value = timeout;
-    scaled_value *= RCOSC16M_FREQ;
-    scaled_value += config_freq[dev] / 2;
-    scaled_value /= config_freq[dev];
-    gptimer->TAMATCHR = gptimer->TAV + scaled_value;
+        case 1:
+            /* clear any pending match interrupts */
+            gptimer->ICR = TBMIM;
 
-    gptimer->cc2538_gptimer_imr.IMRbits.TAMIM = 1; /**< Enable the Timer A Match Interrupt */
+            /* set timeout value */
+            gptimer->TAMATCHR = (gptimer->CFG == GPTMCFG_32_BIT_TIMER)? (gptimer->TBV + timeout) : (gptimer->TBV - timeout);
+            gptimer->cc2538_gptimer_imr.IMR |= TBMIM; /**< Enable the Timer B Match Interrupt */
+            break;
+    }
 
     return 1;
 }
 
 int timer_set_absolute(tim_t dev, int channel, unsigned int value)
 {
-    cc2538_gptimer_t *gptimer;
+    DEBUG("%s(%u, %u, %u)\n", __FUNCTION__, dev, channel, value);
 
-    if (channel >= NUM_CHANNELS) {
+    /* get timer base register address */
+    cc2538_gptimer_t *gptimer = timer_config[dev].dev;
+
+    if ( (dev >= TIMER_NUMOF) || (channel >= timer_config[dev].channels) ) {
         return -1;
     }
 
-    /* get timer base register address */
-    switch (dev) {
-#if TIMER_0_EN
-        case TIMER_0:
-            gptimer = TIMER_0_DEV;
-            break;
-#endif
-#if TIMER_1_EN
-        case TIMER_1:
-            gptimer = TIMER_1_DEV;
-            break;
-#endif
-#if TIMER_2_EN
-        case TIMER_2:
-            gptimer = TIMER_2_DEV;
-            break;
-#endif
-#if TIMER_3_EN
-        case TIMER_3:
-            gptimer = TIMER_3_DEV;
-            break;
-#endif
-        case TIMER_UNDEFINED:
-        default:
-            return -1;
-    }
+    switch (channel) {
+    case 0:
+        /* clear any pending match interrupts */
+        gptimer->ICR = TAMIM;
 
-    /* set timeout value */
-    gptimer->ICR           = TIMER_A_IRQ_MASK; /**< Clear any pending interrupt status */
+        gptimer->TAMATCHR = (gptimer->CFG == GPTMCFG_32_BIT_TIMER)? value : (LOAD_VALUE - value);
+        gptimer->cc2538_gptimer_imr.IMR |= TAMIM; /**< Enable the Timer A Match Interrupt */
+        break;
 
-    uint64_t scaled_value = value;
-    scaled_value *= config_freq[dev];
-    scaled_value += RCOSC16M_FREQ / 2;
-    scaled_value /= RCOSC16M_FREQ;
-    gptimer->TAMATCHR = (scaled_value > UINT32_MAX)? UINT32_MAX : scaled_value;
+    case 1:
+        /* clear any pending match interrupts */
+        gptimer->ICR = TBMIM;
 
-    gptimer->cc2538_gptimer_imr.IMRbits.TAMIM = 1; /**< Enable the Timer A Match Interrupt */
+        gptimer->TBMATCHR = (gptimer->CFG == GPTMCFG_32_BIT_TIMER)? value : (LOAD_VALUE - value);
+        gptimer->cc2538_gptimer_imr.IMR |= TBMIM; /**< Enable the Timer B Match Interrupt */
+        break;
+    }
+
+    /* set timeout value */
 
     return 1;
 }
 
 int timer_clear(tim_t dev, int channel)
 {
-    cc2538_gptimer_t *gptimer;
+    DEBUG("%s(%u, %u)\n", __FUNCTION__, dev, channel);
 
-    if (channel >= NUM_CHANNELS) {
+    if ( (dev >= TIMER_NUMOF) || (channel >= timer_config[dev].channels) ) {
         return -1;
     }
 
-    /* get timer base register address */
-    switch (dev) {
-#if TIMER_0_EN
-        case TIMER_0:
-            gptimer = TIMER_0_DEV;
-            break;
-#endif
-#if TIMER_1_EN
-        case TIMER_1:
-            gptimer = TIMER_1_DEV;
-            break;
-#endif
-#if TIMER_2_EN
-        case TIMER_2:
-            gptimer = TIMER_2_DEV;
-            break;
-#endif
-#if TIMER_3_EN
-        case TIMER_3:
-            gptimer = TIMER_3_DEV;
-            break;
-#endif
-
-        case TIMER_UNDEFINED:
-        default:
-            return -1;
-    }
-
-    gptimer->cc2538_gptimer_imr.IMR = 0;
+    timer_config[dev].dev->cc2538_gptimer_imr.IMR &= ~match_bit(channel);
 
     return 1;
 }
@@ -249,27 +234,16 @@ int timer_clear(tim_t dev, int channel)
  */
 unsigned int timer_read(tim_t dev)
 {
-    switch (dev) {
-#if TIMER_0_EN
-        case TIMER_0:
-            return (uint64_t)TIMER_0_DEV->TAV * config_freq[TIMER_0] / RCOSC16M_FREQ;
-#endif
-#if TIMER_1_EN
-        case TIMER_1:
-            return (uint64_t)TIMER_1_DEV->TAV * config_freq[TIMER_1] / RCOSC16M_FREQ;
-#endif
-#if TIMER_2_EN
-        case TIMER_2:
-            return (uint64_t)TIMER_2_DEV->TAV * config_freq[TIMER_2] / RCOSC16M_FREQ;
-#endif
-#if TIMER_3_EN
-        case TIMER_3:
-            return (uint64_t)TIMER_3_DEV->TAV * config_freq[TIMER_3] / RCOSC16M_FREQ;
-#endif
-
-        case TIMER_UNDEFINED:
-        default:
-            return 0;
+    if (dev >= TIMER_NUMOF) {
+        return 0;
+    }
+
+    cc2538_gptimer_t* gptimer = timer_config[dev].dev;
+    if (gptimer->CFG == GPTMCFG_32_BIT_TIMER) {
+        return gptimer->TAV;
+    }
+    else {
+        return LOAD_VALUE - (gptimer->TAV & 0xffff);
     }
 }
 
@@ -278,200 +252,121 @@ unsigned int timer_read(tim_t dev)
  */
 void timer_stop(tim_t dev)
 {
-    switch (dev) {
-#if TIMER_0_EN
-        case TIMER_0:
-            TIMER_0_DEV->cc2538_gptimer_ctl.CTLbits.TAEN = 0;
-            break;
-#endif
-#if TIMER_1_EN
-        case TIMER_1:
-            TIMER_1_DEV->cc2538_gptimer_ctl.CTLbits.TAEN = 0;
-            break;
-#endif
-#if TIMER_2_EN
-        case TIMER_2:
-            TIMER_2_DEV->cc2538_gptimer_ctl.CTLbits.TAEN = 0;
-            break;
-#endif
-#if TIMER_3_EN
-        case TIMER_3:
-            TIMER_3_DEV->cc2538_gptimer_ctl.CTLbits.TAEN = 0;
-            break;
-#endif
+    DEBUG("%s(%u)\n", __FUNCTION__, dev);
 
-        case TIMER_UNDEFINED:
-            break;
+    if (dev < TIMER_NUMOF) {
+        timer_config[dev].dev->cc2538_gptimer_ctl.CTL = 0;
     }
 }
 
 void timer_start(tim_t dev)
 {
-    switch (dev) {
-#if TIMER_0_EN
-        case TIMER_0:
-            TIMER_0_DEV->cc2538_gptimer_ctl.CTLbits.TAEN = 1;
-            break;
-#endif
-#if TIMER_1_EN
-        case TIMER_1:
-            TIMER_1_DEV->cc2538_gptimer_ctl.CTLbits.TAEN = 1;
-            break;
-#endif
-#if TIMER_2_EN
-        case TIMER_2:
-            TIMER_2_DEV->cc2538_gptimer_ctl.CTLbits.TAEN = 1;
-            break;
-#endif
-#if TIMER_3_EN
-        case TIMER_3:
-            TIMER_3_DEV->cc2538_gptimer_ctl.CTLbits.TAEN = 1;
-            break;
-#endif
-
-        case TIMER_UNDEFINED:
-            break;
+    DEBUG("%s(%u)\n", __FUNCTION__, dev);
+
+    if (dev < TIMER_NUMOF) {
+        switch (timer_config[dev].channels) {
+            case 1:
+                timer_config[dev].dev->cc2538_gptimer_ctl.CTL = TAEN;
+                break;
+
+            case 2:
+                timer_config[dev].dev->cc2538_gptimer_ctl.CTL = TBEN | TAEN;
+                break;
+        }
     }
 }
 
 void timer_irq_enable(tim_t dev)
 {
-    switch (dev) {
-#if TIMER_0_EN
-        case TIMER_0:
-            NVIC_SetPriority(TIMER_0_IRQn_1, TIMER_IRQ_PRIO);
-            NVIC_SetPriority(TIMER_0_IRQn_2, TIMER_IRQ_PRIO);
-            NVIC_EnableIRQ(TIMER_0_IRQn_1);
-            NVIC_EnableIRQ(TIMER_0_IRQn_2);
-            break;
-#endif
-#if TIMER_1_EN
-        case TIMER_1:
-            NVIC_SetPriority(TIMER_1_IRQn_1, TIMER_IRQ_PRIO);
-            NVIC_SetPriority(TIMER_1_IRQn_2, TIMER_IRQ_PRIO);
-            NVIC_EnableIRQ(TIMER_1_IRQn_1);
-            NVIC_EnableIRQ(TIMER_1_IRQn_2);
-            break;
-#endif
-#if TIMER_2_EN
-        case TIMER_2:
-            NVIC_SetPriority(TIMER_2_IRQn_1, TIMER_IRQ_PRIO);
-            NVIC_SetPriority(TIMER_2_IRQn_2, TIMER_IRQ_PRIO);
-            NVIC_EnableIRQ(TIMER_2_IRQn_1);
-            NVIC_EnableIRQ(TIMER_2_IRQn_2);
-            break;
-#endif
-#if TIMER_3_EN
-        case TIMER_3:
-            NVIC_SetPriority(TIMER_3_IRQn_1, TIMER_IRQ_PRIO);
-            NVIC_SetPriority(TIMER_3_IRQn_2, TIMER_IRQ_PRIO);
-            NVIC_EnableIRQ(TIMER_3_IRQn_1);
-            NVIC_EnableIRQ(TIMER_3_IRQn_2);
-            break;
-#endif
+    DEBUG("%s(%u)\n", __FUNCTION__, dev);
+
+    if (dev < TIMER_NUMOF) {
+        IRQn_Type irqn = IRQn_lut[GPTIMER_GET_NUM(timer_config[dev].dev)];
 
-        case TIMER_UNDEFINED:
-        default:
-            return;
+        NVIC_SetPriority(irqn, TIMER_IRQ_PRIO);
+        NVIC_EnableIRQ(irqn);
+
+        if (timer_config[dev].channels == 2) {
+            irqn++;
+            NVIC_SetPriority(irqn, TIMER_IRQ_PRIO);
+            NVIC_EnableIRQ(irqn);
+        }
     }
 }
 
 void timer_irq_disable(tim_t dev)
 {
-    switch (dev) {
-#if TIMER_0_EN
-        case TIMER_0:
-            NVIC_DisableIRQ(TIMER_0_IRQn_1);
-            NVIC_DisableIRQ(TIMER_0_IRQn_2);
-            break;
-#endif
-#if TIMER_1_EN
-        case TIMER_1:
-            NVIC_DisableIRQ(TIMER_1_IRQn_1);
-            NVIC_DisableIRQ(TIMER_1_IRQn_2);
-            break;
-#endif
-#if TIMER_2_EN
-        case TIMER_2:
-            NVIC_DisableIRQ(TIMER_2_IRQn_1);
-            NVIC_DisableIRQ(TIMER_2_IRQn_2);
-            break;
-#endif
-#if TIMER_3_EN
-        case TIMER_3:
-            NVIC_DisableIRQ(TIMER_3_IRQn_1);
-            NVIC_DisableIRQ(TIMER_3_IRQn_2);
-            break;
-#endif
+    DEBUG("%s(%u)\n", __FUNCTION__, dev);
 
-        case TIMER_UNDEFINED:
-        default:
-            return;
+    if (dev < TIMER_NUMOF) {
+        IRQn_Type irqn = IRQn_lut[GPTIMER_GET_NUM(timer_config[dev].dev)];
+
+        NVIC_DisableIRQ(irqn);
+
+        if (timer_config[dev].channels == 2) {
+            irqn++;
+            NVIC_DisableIRQ(irqn);
+        }
     }
 }
 
-static inline void irq_handler(int tim, int chan)
-{
-    if (config[tim].cb != NULL) {
-        config[tim].cb(config[tim].arg, chan);
+static cc2538_gptimer_t* GPTIMER = GPTIMER0;
+
+static void irq_handler_a(int n) {
+    uint32_t mis;
+
+    /* Latch the active interrupt flags */
+    mis = GPTIMER[n].MIS & TIMER_A_IRQ_MASK;
+
+    /* Clear the latched interrupt flags */
+    GPTIMER[n].ICR = mis;
+
+    if (mis & TAMIM) {
+        /* This is a Timer A Match Interrupt */
+
+        /* Disable further match interrupts for this timer/channel */
+        GPTIMER[n].cc2538_gptimer_imr.IMR &= ~TAMIM;
+
+        /* Invoke the callback function */
+        assert(config[n].cb != NULL);
+        config[n].cb(config[n].arg, 0);
     }
+
     if (sched_context_switch_request) {
         thread_yield();
     }
 }
 
-#if TIMER_0_EN
-void TIMER_0_ISR_1(void)
-{
-    TIMER_0_DEV->ICR = TIMER_A_IRQ_MASK;
-    irq_handler(0, 0);
-}
+static void irq_handler_b(int n) {
+    uint32_t mis;
 
-void TIMER_0_ISR_2(void)
-{
-    TIMER_0_DEV->ICR = TIMER_B_IRQ_MASK;
-    irq_handler(0, 1);
-}
-#endif /* TIMER_0_EN */
+    /* Latch the active interrupt flags */
+    mis = GPTIMER[n].MIS & TIMER_B_IRQ_MASK;
 
-#if TIMER_1_EN
-void TIMER_1_ISR_1(void)
-{
-    TIMER_1_DEV->ICR = TIMER_A_IRQ_MASK;
-    irq_handler(1, 0);
-}
+    /* Clear the latched interrupt flags */
+    GPTIMER[n].ICR = mis;
 
-void TIMER_1_ISR_2(void)
-{
-    TIMER_1_DEV->ICR = TIMER_B_IRQ_MASK;
-    irq_handler(1, 1);
-}
-#endif /* TIMER_1_EN */
+    if (mis & TBMIM) {
+        /* This is a Timer B Match Interrupt */
 
-#if TIMER_2_EN
-void TIMER_2_ISR_1(void)
-{
-    TIMER_2_DEV->ICR = TIMER_A_IRQ_MASK;
-    irq_handler(2, 0);
-}
+        /* Disable further match interrupts for this timer/channel */
+        GPTIMER[n].cc2538_gptimer_imr.IMR &= ~TBMIM;
 
-void TIMER_2_ISR_2(void)
-{
-    TIMER_2_DEV->ICR = TIMER_B_IRQ_MASK;
-    irq_handler(2, 1);
-}
-#endif /* TIMER_2_EN */
+        /* Invoke the callback function */
+        assert(config[n].cb != NULL);
+        config[n].cb(config[n].arg, 1);
+    }
 
-#if TIMER_3_EN
-void TIMER_3_ISR_1(void)
-{
-    TIMER_3_DEV->ICR = TIMER_A_IRQ_MASK;
-    irq_handler(3, 0);
+    if (sched_context_switch_request) {
+        thread_yield();
+    }
 }
 
-void TIMER_3_ISR_2(void)
-{
-    TIMER_3_DEV->ICR = TIMER_B_IRQ_MASK;
-    irq_handler(3, 1);
-}
-#endif /* TIMER_3_EN */
+void isr_timer0_chan0(void) {irq_handler_a(0);}
+void isr_timer0_chan1(void) {irq_handler_b(0);}
+void isr_timer1_chan0(void) {irq_handler_a(1);}
+void isr_timer1_chan1(void) {irq_handler_b(1);}
+void isr_timer2_chan0(void) {irq_handler_a(2);}
+void isr_timer2_chan1(void) {irq_handler_b(2);}
+void isr_timer3_chan0(void) {irq_handler_a(3);}
+void isr_timer3_chan1(void) {irq_handler_b(3);}