diff --git a/sys/include/div.h b/sys/include/div.h
new file mode 100644
index 0000000000000000000000000000000000000000..3b83aad628d62af7d067d5d23f828c415061c9b0
--- /dev/null
+++ b/sys/include/div.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/**
+ * @brief     Provides integer division functions
+ *
+ * This header provides some integer division functions that can be used
+ * to prevent linking in compiler-generated ones, which are often larger.
+ *
+ * @file
+ * @ingroup   sys_util
+ * @author  Kaspar Schleiser <kaspar@schleiser.de>
+ * @{
+ */
+
+#ifndef DIV_H
+#define DIV_H
+
+#include <assert.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Integer divide val by 15625
+ *
+ * @pre val <= 16383999997
+ *
+ * @param[in]   val     dividend
+ * @return      (val / 15625)
+ */
+static inline uint64_t div_u64_by_15625(uint64_t val)
+{
+    /* a higher value would overflow 2^64 in the multiplication that follows */
+    assert(val <= 16383999997LLU);
+
+    return (val * 0x431bde83UL) >> (12 + 32);
+}
+
+/**
+ * @brief Integer divide val by 1000000
+ *
+ * @pre val <= 1048575999808
+ *
+ * @param[in]   val     dividend
+ * @return      (val / 1000000)
+ */
+static inline uint64_t div_u64_by_1000000(uint64_t val)
+{
+    /* a higher value would overflow 2^64 in the multiplication that follows */
+    assert(val <= 1048575999808LLU);
+
+    return div_u64_by_15625(val>>6);
+}
+
+/**
+ * @brief Divide val by (15625/512)
+ *
+ * This is used to quantize a 1MHz value to the closest 32768Hz value,
+ * e.g., for timers.
+ *
+ * The algorithm actually multiplies by 512 first, then divides by 15625,
+ * keeping the result closer to a floored floating point division.
+ *
+ * @param[in]   val     dividend
+ * @return      (val / (15625/512))
+ */
+static inline uint32_t div_u32_by_15625div512(uint32_t val)
+{
+    return ((uint64_t)(val) * 0x431bde83ul) >> (12 + 32 - 9);
+}
+
+/**
+ * @brief Integer divide val by 10
+ *
+ * @param[in]   n     dividend
+ * @return      (n / 10)
+ */
+static inline uint32_t div_u32_by_10(uint32_t n) {
+    uint32_t q, r;
+    q = (n >> 1) + (n >> 2);
+    q = q + (q >> 4);
+    q = q + (q >> 8);
+    q = q + (q >> 16);
+    q = q >> 3;
+    r = n - (((q << 2) + q) << 1);
+    return q + (r > 9);
+}
+
+/**
+ * @brief Modulo 10
+ *
+ * @param[in]   n     dividend
+ * @return      (n % 10)
+ */
+static inline uint32_t div_u32_mod_10(uint32_t n)
+{
+    return n - (div_u32_by_10(n)*10);
+}
+
+#ifdef __cplusplus
+}
+#endif
+/** @} */
+#endif /* DIV_H */
diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c
index a03cb55bd96733b467f65a9bec0372f9c3771245..c9993aae2b7280bcd1f70fb6fd3f91409b03d0a8 100644
--- a/sys/xtimer/xtimer.c
+++ b/sys/xtimer/xtimer.c
@@ -21,6 +21,7 @@
 #include "mutex.h"
 #include "thread.h"
 #include "irq.h"
+#include "div.h"
 
 #include "timex.h"
 
@@ -150,21 +151,11 @@ void xtimer_set_wakeup64(xtimer_t *timer, uint64_t offset, kernel_pid_t pid)
     _xtimer_set64(timer, offset, offset >> 32);
 }
 
-/**
- * see http://www.hackersdelight.org/magic.htm.
- * This is to avoid using long integer division functions
- * the compiler otherwise links in.
- */
-static inline uint64_t _us_to_sec(uint64_t us)
-{
-    return (unsigned long long)(us * 0x431bde83) >> (0x12 + 32);
-}
-
 void xtimer_now_timex(timex_t *out)
 {
     uint64_t now = xtimer_now64();
 
-    out->seconds = _us_to_sec(now);
+    out->seconds = div_u64_by_1000000(now);
     out->microseconds = now - (out->seconds * SEC_IN_USEC);
 }
 
diff --git a/tests/unittests/tests-div/Makefile b/tests/unittests/tests-div/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2
--- /dev/null
+++ b/tests/unittests/tests-div/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/tests/unittests/tests-div/tests-div.c b/tests/unittests/tests-div/tests-div.c
new file mode 100644
index 0000000000000000000000000000000000000000..824d1952a32dbb87d68094e63360c958d34239c2
--- /dev/null
+++ b/tests/unittests/tests-div/tests-div.c
@@ -0,0 +1,120 @@
+/*
+* 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.
+*/
+
+#include <string.h>
+#include "embUnit.h"
+#include "tests-div.h"
+
+#include "div.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+static uint32_t u32_test_values[] = {
+    0,
+    1,
+    10,
+    32,
+    15625,
+    15625LU*5,
+    (15625LU*5)+1,
+    0xffff,
+    0xffff<<10,
+    0xffffffff
+};
+
+static uint64_t u64_test_values[] = {
+    0xffffffffULL+1
+};
+
+#define N_U32_VALS (sizeof(u32_test_values)/sizeof(uint32_t))
+#define N_U64_VALS (sizeof(u64_test_values)/sizeof(uint64_t))
+
+static void test_div_u64_by_15625(void)
+{
+    for (unsigned i = 0; i < N_U32_VALS; i++) {
+        DEBUG("Dividing %"PRIu32" by 15625...\n", u32_test_values[i]);
+        TEST_ASSERT_EQUAL_INT(
+                div_u64_by_15625(u32_test_values[i]),
+                u32_test_values[i]/15625);
+    }
+
+    for (unsigned i = 0; i < N_U64_VALS; i++) {
+        DEBUG("Dividing %"PRIu64" by 15625...\n", u64_test_values[i]);
+        TEST_ASSERT_EQUAL_INT(
+                div_u64_by_15625(u64_test_values[i]),
+                u64_test_values[i]/15625);
+    }
+}
+
+static void test_div_u32_by_15625div512(void)
+{
+    for (unsigned i = 0; i < N_U32_VALS; i++) {
+        DEBUG("Dividing %"PRIu32" by (15625/512)...\n", u32_test_values[i]);
+        TEST_ASSERT_EQUAL_INT(
+                div_u32_by_15625div512(u32_test_values[i]),
+                (uint64_t)u32_test_values[i]*512LU/15625);
+    }
+}
+
+static void test_div_u64_by_1000000(void)
+{
+    for (unsigned i = 0; i < N_U32_VALS; i++) {
+        DEBUG("Dividing %"PRIu32" by 1000000...\n", u32_test_values[i]);
+        TEST_ASSERT_EQUAL_INT(
+                div_u64_by_1000000(u32_test_values[i]),
+                u32_test_values[i]/1000000);
+    }
+
+    for (unsigned i = 0; i < N_U64_VALS; i++) {
+        DEBUG("Dividing %"PRIu64" by 1000000...\n", u64_test_values[i]);
+        TEST_ASSERT_EQUAL_INT(
+                div_u64_by_1000000(u64_test_values[i]),
+                u64_test_values[i]/1000000U);
+    }
+}
+
+static void test_div_u32_by_10(void)
+{
+    for (unsigned i = 0; i < N_U32_VALS; i++) {
+        DEBUG("Dividing %"PRIu32" by 10...\n", u32_test_values[i]);
+        TEST_ASSERT_EQUAL_INT(
+                div_u32_by_10(u32_test_values[i]),
+                u32_test_values[i]/10);
+    }
+}
+
+static void test_div_u32_mod_10(void)
+{
+    for (unsigned i = 0; i < N_U32_VALS; i++) {
+        DEBUG("Calculating %"PRIu32" % 10...\n", u32_test_values[i]);
+        TEST_ASSERT_EQUAL_INT(
+                div_u32_mod_10(u32_test_values[i]),
+                u32_test_values[i]%10);
+    }
+}
+
+Test *tests_div_tests(void)
+{
+    EMB_UNIT_TESTFIXTURES(fixtures) {
+        new_TestFixture(test_div_u64_by_15625),
+        new_TestFixture(test_div_u32_by_15625div512),
+        new_TestFixture(test_div_u64_by_1000000),
+        new_TestFixture(test_div_u32_by_10),
+        new_TestFixture(test_div_u32_mod_10),
+    };
+
+    EMB_UNIT_TESTCALLER(div_tests, NULL, NULL, fixtures);
+
+    return (Test *)&div_tests;
+}
+
+void tests_div(void)
+{
+    TESTS_RUN(tests_div_tests());
+}
diff --git a/tests/unittests/tests-div/tests-div.h b/tests/unittests/tests-div/tests-div.h
new file mode 100644
index 0000000000000000000000000000000000000000..037ee6b0210101e920185c1aec8191d2ef8f27d5
--- /dev/null
+++ b/tests/unittests/tests-div/tests-div.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup  unittests
+ * @{
+ *
+ * @file
+ * @brief       Unittests for the ``div`` header
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ */
+#ifndef TESTS_DIV_H_
+#define TESTS_DIV_H_
+#include "embUnit/embUnit.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+*  @brief   The entry point of this test suite.
+*/
+void tests_div(void);
+
+/**
+ * @brief   Generates tests for div
+ *
+ * @return  embUnit tests if successful, NULL if not.
+ */
+Test *tests_div_tests(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TESTS_DIV_H_ */
+/** @} */