diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep
index 692af1fdb4d1fbbde17ceee13a803e695eaf10c7..fc00e9f0b1a24b4efc95e5ffac8a7dcb822573e3 100644
--- a/drivers/Makefile.dep
+++ b/drivers/Makefile.dep
@@ -273,6 +273,16 @@ ifneq (,$(filter lsm6dsl,$(USEMODULE)))
   USEMODULE += xtimer
 endif
 
+ifneq (,$(filter ltc4150_bidirectional,$(USEMODULE)))
+  USEMODULE += ltc4150
+endif
+
+ifneq (,$(filter ltc4150,$(USEMODULE)))
+  FEATURES_REQUIRED += periph_gpio
+  FEATURES_REQUIRED += periph_gpio_irq
+  USEMODULE += xtimer
+endif
+
 ifneq (,$(filter mag3110,$(USEMODULE)))
   FEATURES_REQUIRED += periph_i2c
 endif
diff --git a/drivers/Makefile.include b/drivers/Makefile.include
index 33f3006526adf55e5430f41fe5b7a0df94447a9d..d4ab792e104fecc4b30ff98eb0a87bf37e49ba7b 100644
--- a/drivers/Makefile.include
+++ b/drivers/Makefile.include
@@ -162,6 +162,10 @@ ifneq (,$(filter lsm6dsl,$(USEMODULE)))
   USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lsm6dsl/include
 endif
 
+ifneq (,$(filter ltc4150,$(USEMODULE)))
+  USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ltc4150/include
+endif
+
 ifneq (,$(filter mag3110,$(USEMODULE)))
   USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mag3110/include
 endif
diff --git a/drivers/include/ltc4150.h b/drivers/include/ltc4150.h
new file mode 100644
index 0000000000000000000000000000000000000000..e51962524bf17588229b9b229a27b67713e5cc66
--- /dev/null
+++ b/drivers/include/ltc4150.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2019 Otto-von-Guericke-Universität Magdeburg
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup    drivers_ltc4150 LTC4150 coulomb counter
+ * @ingroup     drivers_sensors
+ * @brief       Driver for the Linear Tech LTC4150 Coulomb Counter
+ *              (a.k.a. battery gauge sensor or power consumption sensor)
+ *
+ * # Wiring the LTC4150
+ * Hint: M Grusin thankfully created an
+ * [open hardware breakout board](https://cdn.sparkfun.com/datasheets/BreakoutBoards/LTC4150_BOB_v10.pdf).
+ * As a result, virtually all LTC4150 breakout boards are using this schematic.
+ * Whenever this documentation refers to a breakout board, this open hardware
+ * board is meant. Of course, this driver works with the "bare" LTC4150 as well.
+ *
+ * Please note that this driver works interrupt driven and does not clear the
+ * signal. Thus, the /CLR and /INT pins on the LTC4150 need to be connected
+ * (in case of the breakout board: close solder jumper SJ1), so that the signal
+ * is automatically cleared.
+ *
+ * Hint: The breakout board uses external pull up resistors on /INT, POL and
+ * /SHDN. Therefore /SHDN can be left unconnected and no internal pull ups are
+ * required for /INT and POL. In case your board uses 3.3V logic the solder
+ * jumpers SJ2 and SJ3 have to be closed, in case of 5V they have to remain
+ * open. Connect the VIO pin to the logic level, GND to ground, IN+ and IN- to
+ * the power supply and use OUT+ and OUT- to power your board.
+ *
+ * In the easiest case only the /INT pin needs to be connected to a GPIO,
+ * and (in case of external pull ups) /SHDN and POL can be left unconnected.
+ * The GPIO /INT is connected to support for interrupts, /SHDN and POL
+ * (if connected) do not require interrupt support.
+ *
+ * In case a battery is used the POL pin connected to another GPIO. This allows
+ * to distinguish between charge drawn from the battery and charge transferred
+ * into the battery (used to load it).
+ *
+ * In case support to power off the LTC4150 is desired, the /SHDN pin needs to
+ * be connected to a third GPIO.
+ *
+ * # Things to keep in mind
+ * The LTC4150 creates pulses with a frequency depending on the current drawn.
+ * Thus, more interrupts need to be handled when more current is drawn, which
+ * in turn increases system load (and power consumption). The interrupt service
+ * routing is quite short and even when used outside of specification less than
+ * 20 ticks per second will occur. Hence, this effect should hopefully be
+ * negligible.
+ *
+ * @{
+ *
+ * @file
+ * @brief       LTC4150 coulomb counter
+ *
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ */
+
+#ifndef LTC4150_H
+#define LTC4150_H
+
+#include <stdint.h>
+
+#include "mutex.h"
+#include "periph/gpio.h"
+#include "xtimer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Configuration flags of the LTC4150 coulomb counter
+ */
+enum {
+    /**
+     * @brief External pull on the /INT pin is present
+     */
+    LTC4150_INT_EXT_PULL_UP = 0x01,
+    /**
+     * @brief External pull on the /POL pin is present
+     */
+    LTC4150_POL_EXT_PULL_UP = 0x02,
+    /**
+     * @brief External pull on the /INT *and* the /POL pin is present
+     */
+    LTC4150_EXT_PULL_UP = LTC4150_INT_EXT_PULL_UP | LTC4150_POL_EXT_PULL_UP,
+};
+
+/**
+ * @brief Enumeration of directions in which the charge can be transferred
+ */
+typedef enum {
+    LTC4150_CHARGE,             /**< The battery is charged */
+    LTC4150_DISCHARGE,          /**< Charge is drawn from the battery */
+} ltc4150_dir_t;
+
+/**
+ * @brief LTC4150 coulomb counter
+ */
+typedef struct ltc4150_dev ltc4150_dev_t;
+
+/**
+ * @brief Interface to allow recording of the drawn current in a user defined
+ *        resolution
+ *
+ * @note  Keep in mind that the data recording may be performed by the CPU of
+ *        the system to monitor - thus keep power consumption for the recording
+ *        low!
+ *
+ * The LTC4150 driver will only track total charge transferred (separately for
+ * charging in discharging direction). However, there are use cases that
+ * required more precise data recording, e.g. a rolling average of the last
+ * minute. This interface allows application developers to implement the ideal
+ * trade-off between RAM, ROM and runtime overhead for the data recording and
+ * the level of information they require.
+ */
+typedef struct {
+    /**
+     * @brief   Function to call on every pulse received from the LTC4150
+     * @warning This function is called in interrupt context
+     *
+     * @param[in] dev       The device the pulse was received from
+     * @param[in] dir       Direction in which the charge is transferred
+     * @param[in] now_usec  The system time the pulse was received in µs
+     * @param[in] arg       (Optional) argument for this callback
+     */
+    void (*pulse)(ltc4150_dev_t *dev, ltc4150_dir_t dir, uint64_t now_usec, void *arg);
+    /**
+     * @brief   Function to call upon driver initialization or reset
+     *
+     * @see ltc4150_init
+     * @see ltc4150_reset_counters
+     *
+     * @param[in] dev       The LTC4150 device to monitor
+     * @param[in] now_usec  The system time the pulse was received in µs
+     * @param[in] arg       (Optional) argument for this callback
+     */
+    void (*reset)(ltc4150_dev_t *dev, uint64_t now_usec, void *arg);
+} ltc4150_recorder_t;
+
+/**
+ * @brief Parameters required to set up the LTC4150 coulomb counter
+ */
+typedef struct {
+    /**
+     * @brief Pin going LOW every time a specific charge is drawn, labeled INT
+     */
+    gpio_t interrupt;
+    /**
+     * @brief Pin indicating (dis-)charging, labeled POL
+     *
+     * Set this pin to `GPIO_UNDEF` to tread every pulse as discharging. This
+     * pin is pulled low by the LTC4150 in case the battery is discharging.
+     */
+    gpio_t polarity;
+    /**
+     * @brief Pin to power off the LTC4150 coulomb counter, labeled SHDN
+     *
+     * Set this pin to `GPIO_UNDEF` if the SHDN pin is not connected to the MCU
+     */
+    gpio_t shutdown;
+    /**
+     * @brief Pulse per ampere hour of charge
+     *
+     * pulses = 3600 * 32.55 * R
+     *
+     * Where R is the resistance (in Ohm) between the SENSE+ and SENSE- pins.
+     * E.g. the MSBA2 has 0.390 Ohm (==> 45700 pulses), while most breakout
+     * boards for the LTC4150 have 0.050 Ohm (==> 5859 pulses).
+     */
+    uint16_t pulses_per_ah;
+    /**
+     * @brief Configuration flags controlling if inter pull ups are required
+     *
+     * Most [breakout boards](https://cdn.sparkfun.com/datasheets/BreakoutBoards/LTC4150_BOB_v10.pdf)
+     * and the MSBA2 board use external pull up resistors, so no internal pull
+     * ups are required. Clear the flags to use internal pull ups instead.
+     */
+    uint16_t flags;
+    /**
+     * @brief `NULL` or a `NULL`-terminated array of data recorders
+     * @pre   If not `NULL`, the last element of the array must be `NULL`
+     */
+    ltc4150_recorder_t **recorders;
+    /**
+     * @brief `NULL` or an array of the user defined data for each recorder
+     * @pre   If @see ltc4150_params_t::recorders is not `NULL`, this must point
+     *        to an array of `void`-Pointers of the same length.
+     * @note  Unlike @see ltc4150_param_t::callback, this array does not need to
+     *        be `NULL`-terminated
+     */
+    void **recorder_data;
+} ltc4150_params_t;
+
+/**
+ * @brief LTC4150 coulomb counter
+ */
+struct ltc4150_dev {
+    ltc4150_params_t params;    /**< Parameter of the LTC4150 coulomb counter */
+    uint32_t start_sec;         /**< Time stamp when started counting */
+    uint32_t last_update_sec;   /**< Time stamp of last pulse */
+    uint32_t charged;           /**< # of pulses for charging (POL=high) */
+    uint32_t discharged;        /**< # of pulses for discharging (POL=low) */
+};
+
+/**
+ * @brief             Initialize the LTC4150 driver
+ *
+ * @param  dev        Device to initialize
+ * @param  params     Information on how the LTC4150 is conntected
+ *
+ * @retval  0         Success
+ * @retval -EINVAL    Called with invalid argument(s)
+ * @retval -EIO       IO failure (`gpio_init()`/`gpio_init_int()` failed)
+ */
+int ltc4150_init(ltc4150_dev_t *dev, const ltc4150_params_t *params);
+
+/**
+ * @brief             Clear current counters of the given LTC4150 device
+ * @param dev         The LTC4150 device to clear current counters from
+ *
+ * @retval 0          Success
+ * @retval -EINVAL    Called with an invalid argument
+ */
+int ltc4150_reset_counters(ltc4150_dev_t *dev);
+
+/**
+ * @brief             Disable the interrupt handler and turn the chip off
+ *
+ * @param  dev        Previously initialized device to power off
+ *
+ * @retval  0         Success
+ * @retval -EINVAL    Called with invalid argument(s)
+ *
+ * The driver can be reinitialized to power on the LTC4150 chip again
+ */
+int ltc4150_shutdown(ltc4150_dev_t *dev);
+
+/**
+ * @brief                  Get the measured charge since boot or last reset in
+ *                         millicoulomb
+ *
+ * @param dev              The LTC4150 device to read data from
+ * @param[out] charged     The charge transferred in charging direction
+ * @param[out] discharged  The charge transferred in discharging direction
+ *
+ * @retval 0                Success
+ * @retval -EINVAL          Called with an invalid argument
+ *
+ * Passing `NULL` for `charged` or `discharged` is allowed, if only one
+ * information is of interest.
+ */
+int ltc4150_charge(ltc4150_dev_t *dev, uint32_t *charged, uint32_t *discharged);
+
+/**
+ * @brief             Get the average current drawn in E-01 milliampere
+ *
+ * This will return the average current drawn since boot or last reset until the
+ * last pulse from the LTC4150 was received. The value might thus be a bit
+ * outdated (0.8 seconds for the breakout board and a current of 100mA, 79
+ * seconds for a current of 1mA).
+ *
+ * @param dev         The LTC4150 device to read data from
+ * @param[out] dest   Store the average current drawn in E-01 milliampere here
+ *
+ * @retval 0          Success
+ * @retval -EINVAL    Called with an invalid argument
+ * @retval -EAGAIN    Called before enough data samples have been acquired.
+ *                    (Wait for at least one second or one pulse from the
+                      LTC4150, whichever takes longer.)
+ */
+int ltc4150_avg_current(ltc4150_dev_t *dev, int16_t *dest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTC4150_H */
+/** @} */
diff --git a/drivers/ltc4150/Makefile b/drivers/ltc4150/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2
--- /dev/null
+++ b/drivers/ltc4150/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/drivers/ltc4150/include/ltc4150_params.h b/drivers/ltc4150/include/ltc4150_params.h
new file mode 100644
index 0000000000000000000000000000000000000000..b40414803037452bb0668cbda7a4c1cfe3871b01
--- /dev/null
+++ b/drivers/ltc4150/include/ltc4150_params.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
+ *
+ * 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     drivers_ltc4150
+ *
+ * @{
+ * @file
+ * @brief       Default configuration for LTC4150 coulomb counters
+ *
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ */
+
+#ifndef LTC4150_PARAMS_H
+#define LTC4150_PARAMS_H
+
+#include "board.h"
+#include "ltc4150.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name    Set default configuration parameters for the LTC4150
+ * @{
+ */
+#ifndef LTC4150_PARAM_INT
+#define LTC4150_PARAM_INT             (GPIO_PIN(0, 4))
+#endif
+#ifndef LTC4150_PARAM_POL
+#define LTC4150_PARAM_POL             (GPIO_UNDEF)
+#endif
+#ifndef LTC4150_PARAM_SHUTDOWN
+#define LTC4150_PARAM_SHUTDOWN        (GPIO_PIN(0, 5))
+#endif
+#ifndef LTC4150_PARAM_PULSES
+#define LTC4150_PARAM_PULSES          (45700U)
+#endif
+#ifndef LTC4150_PARAM_FLAGS
+#define LTC4150_PARAM_FLAGS           LTC4150_EXT_PULL_UP
+#endif
+#ifndef LTC4150_PARAM_RECS
+#define LTC4150_PARAM_RECS            NULL
+#define LTC4150_PARAM_RECDATA         NULL
+#endif
+#ifndef LTC4150_PARAMS
+#define LTC4150_PARAMS                { .interrupt = LTC4150_PARAM_INT,  \
+                                        .polarity = LTC4150_PARAM_POL, \
+                                        .shutdown = LTC4150_PARAM_SHUTDOWN, \
+                                        .pulses_per_ah = LTC4150_PARAM_PULSES, \
+                                        .flags = LTC4150_PARAM_FLAGS, \
+                                        .recorders = LTC4150_PARAM_RECS, \
+                                        .recorder_data = LTC4150_PARAM_RECDATA }
+#endif
+/**@}*/
+
+/**
+ * @brief   Configure LTC4150 devices
+ */
+static const ltc4150_params_t ltc4150_params[] =
+{
+    LTC4150_PARAMS
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTC4150_PARAMS_H */
+/** @} */
diff --git a/drivers/ltc4150/ltc4150.c b/drivers/ltc4150/ltc4150.c
new file mode 100644
index 0000000000000000000000000000000000000000..a702aaef6f8e62b44e2d1c9101ae3fc0f342d10d
--- /dev/null
+++ b/drivers/ltc4150/ltc4150.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2019 Otto-von-Guericke-Universität Magdeburg
+ *
+ * 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     drivers_ltc4150
+ * @{
+ *
+ * @file
+ * @brief       LTC4150 Device Driver
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ *
+ * @}
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "ltc4150.h"
+#include "xtimer.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+static void pulse_cb(void *_dev)
+{
+    uint64_t now;
+    ltc4150_dir_t dir;
+    ltc4150_dev_t *dev = _dev;
+
+    if ((dev->params.polarity == GPIO_UNDEF) ||
+        (!gpio_read(dev->params.polarity))
+        ) {
+        dev->discharged++;
+        dir = LTC4150_DISCHARGE;
+    }
+    else {
+        dev->charged++;
+        dir = LTC4150_CHARGE;
+    }
+
+    now = xtimer_now_usec64();
+
+    if (dev->params.recorders) {
+        assert(dev->params.recorder_data);
+        for (unsigned i = 0; dev->params.recorders[i] != NULL; i++) {
+            dev->params.recorders[i]->pulse(dev, dir, now,
+                                            dev->params.recorder_data[i]);
+        }
+    }
+
+    dev->last_update_sec = now / US_PER_SEC;
+}
+
+int ltc4150_init(ltc4150_dev_t *dev, const ltc4150_params_t *params)
+{
+    if (!dev || !params) {
+        return -EINVAL;
+    }
+
+    memset(dev, 0, sizeof(ltc4150_dev_t));
+    dev->params = *params;
+
+    if (dev->params.shutdown != GPIO_UNDEF) {
+        /* Activate LTC4150 */
+        if (gpio_init(dev->params.shutdown, GPIO_OUT)) {
+            DEBUG("[ltc4150] Failed to initialize shutdown pin");
+            return -EIO;
+        }
+        gpio_set(dev->params.shutdown);
+    }
+
+    if (dev->params.polarity != GPIO_UNDEF) {
+        gpio_mode_t mode = (dev->params.flags & LTC4150_POL_EXT_PULL_UP) ?
+                           GPIO_IN : GPIO_IN_PU;
+        if (gpio_init(dev->params.polarity, mode)) {
+            DEBUG("[ltc4150] Failed to initialize polarity pin");
+            return -EIO;
+        }
+    }
+
+    gpio_mode_t mode = (dev->params.flags & LTC4150_INT_EXT_PULL_UP) ?
+                       GPIO_IN : GPIO_IN_PU;
+    if (gpio_init_int(dev->params.interrupt, mode, GPIO_FALLING,
+                      pulse_cb, dev)
+        ) {
+        DEBUG("[ltc4150] Failed to initialize interrupt pin");
+        return -EIO;
+    }
+
+    ltc4150_reset_counters(dev);
+
+    DEBUG("[ltc4150] Initialized successfully");
+    return 0;
+}
+
+int ltc4150_reset_counters(ltc4150_dev_t *dev)
+{
+    uint64_t now = xtimer_now_usec64();
+
+    if (!dev) {
+        return -EINVAL;
+    }
+
+    gpio_irq_disable(dev->params.interrupt);
+
+    dev->charged = 0;
+    dev->discharged = 0;
+    dev->last_update_sec = dev->start_sec = now / US_PER_SEC;
+
+    if (dev->params.recorders) {
+        assert(dev->params.recorder_data);
+        for (unsigned i = 0; dev->params.recorders[i] != NULL; i++) {
+            dev->params.recorders[i]->reset(dev, now, dev->params.recorder_data[i]);
+        }
+    }
+
+    gpio_irq_enable(dev->params.interrupt);
+    return 0;
+}
+
+int ltc4150_shutdown(ltc4150_dev_t *dev)
+{
+    if (!dev) {
+        return -EINVAL;
+    }
+
+    gpio_irq_disable(dev->params.interrupt);
+
+    if (dev->params.shutdown != GPIO_UNDEF) {
+        gpio_clear(dev->params.shutdown);
+    }
+
+    return 0;
+}
+
+/**
+ * @brief Convert the raw data (# pulses) acquired by the LTC4150 device to
+ *        charge information in millicoulomb
+ *
+ * @param dev                 LTC4150 device the data was received from
+ * @param[out] charged        Charge in charging direction is stored here
+ * @param[out] discharged     Charge in discharging direction is stored here
+ * @param[in] raw_charged     Number of pulses in charging direction
+ * @param[in] raw_discharged  Number of pulses in discharging direction
+ */
+static void get_coulomb(const ltc4150_dev_t *dev,
+                        uint32_t *charged, uint32_t *discharged,
+                        uint32_t raw_charged,
+                        uint32_t raw_discharged)
+{
+    uint64_t tmp;
+
+    if (charged) {
+        tmp = raw_charged;
+        tmp *= 3600000;
+        tmp += dev->params.pulses_per_ah >> 1;
+        tmp /= dev->params.pulses_per_ah;
+        *charged = tmp;
+    }
+
+    if (discharged) {
+        tmp = raw_discharged;
+        tmp *= 3600000;
+        tmp += dev->params.pulses_per_ah >> 1;
+        tmp /= dev->params.pulses_per_ah;
+        *discharged = tmp;
+    }
+}
+
+int ltc4150_charge(ltc4150_dev_t *dev, uint32_t *charged, uint32_t *discharged)
+{
+    if (!dev) {
+        return -EINVAL;
+    }
+
+    gpio_irq_disable(dev->params.interrupt);
+    get_coulomb(dev, charged, discharged, dev->charged, dev->discharged);
+    gpio_irq_enable(dev->params.interrupt);
+    return 0;
+}
+
+int ltc4150_avg_current(ltc4150_dev_t *dev, int16_t *dest)
+{
+    int32_t duration, charged, discharged;;
+    int retval;
+
+    retval = ltc4150_charge(dev, (uint32_t *)&charged, (uint32_t *)&discharged);
+    if (retval) {
+        return retval;
+    }
+
+    duration = dev->last_update_sec - dev->start_sec;
+    if (!duration) {
+        /* Called before one second of date or one pulse acquired. Prevent
+         * division by zero by returning -EAGAIN.
+         */
+        return -EAGAIN;
+    }
+
+    /* From millicoloumb (=mAs) to E-01 mA */
+    *dest = ((discharged - charged) * 10) / duration;
+
+    return 0;
+}