microbuilder closed pull request #1237: Initial TSL2591 driver
URL: https://github.com/apache/mynewt-core/pull/1237
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/hw/drivers/sensors/tsl2591/include/tsl2591/tsl2591.h 
b/hw/drivers/sensors/tsl2591/include/tsl2591/tsl2591.h
new file mode 100644
index 0000000000..514007ae27
--- /dev/null
+++ b/hw/drivers/sensors/tsl2591/include/tsl2591/tsl2591.h
@@ -0,0 +1,221 @@
+/**************************************************************************/
+/*!
+    @file     tsl2591.h
+    @author   Kevin Townsend
+
+    @section LICENSE
+
+    Software License Agreement (BSD License)
+
+    Copyright (c) 2018, Kevin Townsend
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+    1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+    3. Neither the name of the copyright holders nor the
+    names of its contributors may be used to endorse or promote products
+    derived from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES;
+    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/**************************************************************************/
+
+#ifndef __TSL2591_H__
+#define __TSL2591_H__
+
+#include "os/mynewt.h"
+#include "sensor/sensor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum tsl2591_light_gain {
+    TSL2591_LIGHT_GAIN_LOW        = 0x00, /* 1X     */
+    TSL2591_LIGHT_GAIN_MED        = 0x10, /* ~25X   */
+    TSL2591_LIGHT_GAIN_HIGH       = 0x20, /* ~428X  */
+    TSL2591_LIGHT_GAIN_MAX        = 0x30  /* ~9876X */
+};
+
+enum tsl2591_light_itime {
+    TSL2591_LIGHT_ITIME_100MS     = 0x00, /* 100ms */
+    TSL2591_LIGHT_ITIME_200MS     = 0x01, /* 200ms */
+    TSL2591_LIGHT_ITIME_300MS     = 0x02, /* 300ms */
+    TSL2591_LIGHT_ITIME_400MS     = 0x03, /* 400ms */
+    TSL2591_LIGHT_ITIME_500MS     = 0x04, /* 500ms */
+    TSL2591_LIGHT_ITIME_600MS     = 0x05  /* 600ms */
+};
+
+struct tsl2591_cfg {
+    uint8_t gain;
+    uint8_t integration_time;
+    sensor_type_t mask;
+};
+
+struct tsl2591 {
+    struct os_dev dev;
+    struct sensor sensor;
+    struct tsl2591_cfg cfg;
+    os_time_t last_read_time;
+};
+
+/**
+ * Expects to be called back through os_dev_create().
+ *
+ * @param ptr to the device object associated with this luminosity sensor
+ * @param argument passed to OS device init
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int tsl2591_init(struct os_dev *dev, void *arg);
+
+/**
+ * Enable or disables the sensor to save power
+ *
+ * @param The sensor interface
+ * @param state  1 to enable the sensor, 0 to disable it
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int tsl2591_enable(struct sensor_itf *itf, uint8_t state);
+
+/**
+ * Gets the current 'enabled' state for the IC
+ *
+ * @param The sensor interface
+ * @param ptr to the enabled variable to be filled up
+ * @return 0 on success, non-zero on failure
+ */
+int tsl2591_get_enable(struct sensor_itf *itf, uint8_t *enabled);
+
+/**
+ * Gets a new data sample from the light sensor.
+ *
+ * @param The sensor interface
+ * @param broadband The full (visible + ir) sensor output
+ * @param ir        The ir sensor output
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int tsl2591_get_data(struct sensor_itf *itf, uint16_t *broadband, uint16_t 
*ir);
+
+/**
+ * Sets the integration time used when sampling light values.
+ *
+ * @param The sensor interface
+ * @param int_time The integration time which can be one of:
+ *                  - 0x00: 100ms
+ *                  - 0x01: 200ms
+ *                  - 0x02: 300ms
+ *                  - 0x03: 400ms
+ *                  - 0x04: 500ms
+ *                  - 0x05: 600ms
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int tsl2591_set_integration_time(struct sensor_itf *itf, uint8_t int_time);
+
+/**
+ * Gets the current integration time used when sampling light values.
+ *
+ * @param The sensor interface
+ * @param ptr to the integration time which can be one of:
+ *                  - 0x00: 100ms
+ *                  - 0x01: 200ms
+ *                  - 0x02: 300ms
+ *                  - 0x03: 400ms
+ *                  - 0x04: 500ms
+ *                  - 0x05: 600ms
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int tsl2591_get_integration_time(struct sensor_itf *itf, uint8_t *int_time);
+
+/**
+ * Sets the gain increment used when sampling light values.
+ *
+ * @param The sensor interface
+ * @param gain The gain increment which can be one of:
+ *                  - 0x00: Low (no gain)
+ *                  - 0x10: Medium (~25x gain)
+ *                  - 0x20: High (~428x gain)
+ *                  - 0x30: Max (~9876x gain)
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int tsl2591_set_gain(struct sensor_itf *itf, uint8_t gain);
+
+/**
+ * Gets the current gain increment used when sampling light values.
+ *
+ * @param The sensor interface
+ * @param ptr to the gain increment which can be one of:
+ *                  - 0x00: Low (no gain)
+ *                  - 0x10: Medium (~25x gain)
+ *                  - 0x20: High (~428x gain)
+ *                  - 0x30: Max (~9876x gain)
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int tsl2591_get_gain(struct sensor_itf *itf, uint8_t *gain);
+
+/**
+ * Configure the sensor
+ *
+ * @param ptr to sensor driver
+ * @param ptr to sensor driver config
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int tsl2591_config(struct tsl2591 *, struct tsl2591_cfg *);
+
+/**
+ * Calculate light level in lux based on the full spectrum and IR readings
+ *
+ * NOTE: This function assumes that the gain and integration time used when
+ *       reading the full spectrum and IR readings are the same as when this
+ *       function gets called. If gain or integration time have changed, a
+ *       fresh sample should be read before calling this function.
+ *
+ * @param ptr to sensor driver
+ * @param Full spectrum (broadband) light reading
+ * @param IR light reading
+ * @param ptr to the sensor driver config
+ *
+ * @return 0 on failure, otherwise the converted light level in lux
+ */
+uint32_t tsl2591_calculate_lux(struct sensor_itf *itf, uint16_t broadband,
+  uint16_t ir, struct tsl2591_cfg *cfg);
+
+#if MYNEWT_VAL(TSL2591_CLI)
+int tsl2591_shell_init(void);
+#endif
+
+#ifdef ARCH_sim
+/**
+ * Registers the sim driver with the hal_i2c simulation layer
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int tsl2591_sim_init(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TSL2591_H__ */
diff --git a/hw/drivers/sensors/tsl2591/pkg.yml 
b/hw/drivers/sensors/tsl2591/pkg.yml
new file mode 100644
index 0000000000..33bd8f7f39
--- /dev/null
+++ b/hw/drivers/sensors/tsl2591/pkg.yml
@@ -0,0 +1,46 @@
+# The BSD License (BSD)
+#
+# Copyright (c) 2018 Kevin Townsend
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in 
all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+pkg.name: hw/drivers/sensors/tsl2591
+pkg.description: Driver for the TSL2591 light to digital sensor
+pkg.author: "Kevin Townsend"
+pkg.homepage: "https://www.adafruit.com/product/1980";
+pkg.keywords:
+    - adafruit
+    - tsl2591
+    - i2c
+    - sensor
+
+pkg.deps:
+    - "@apache-mynewt-core/kernel/os"
+    - "@apache-mynewt-core/hw/hal"
+    - "@apache-mynewt-core/hw/sensor"
+
+pkg.req_apis:
+    - stats
+    - log
+
+pkg.deps.TSL2591_CLI:
+    - "@apache-mynewt-core/util/parse"
+
+pkg.deps.TSL2591_CONFIG:
+    - '@apache-mynewt-core/sys/config'
diff --git a/hw/drivers/sensors/tsl2591/src/tsl2591.c 
b/hw/drivers/sensors/tsl2591/src/tsl2591.c
new file mode 100644
index 0000000000..02b8261d5b
--- /dev/null
+++ b/hw/drivers/sensors/tsl2591/src/tsl2591.c
@@ -0,0 +1,609 @@
+/*****************************************************************************/
+/*!
+    @file     tsl2591.c
+    @author   Kevin Townsend
+    @section LICENSE
+    Software License Agreement (BSD License)
+    Copyright (c) 2018, Kevin Townsend
+    All rights reserved.
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+    1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+    3. Neither the name of the copyright holders nor the
+    names of its contributors may be used to endorse or promote products
+    derived from this software without specific prior written permission.
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES;
+    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*****************************************************************************/
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include "os/mynewt.h"
+#include "hal/hal_i2c.h"
+#include "sensor/sensor.h"
+#include "sensor/light.h"
+#include "tsl2591/tsl2591.h"
+#include "tsl2591_priv.h"
+#include "log/log.h"
+#if MYNEWT_VAL(TSL2591_STATS)
+#include "stats/stats.h"
+#endif
+#if MYNEWT_VAL(TSL2591_CONFIG)
+#include "config/config.h"
+#endif
+
+#if MYNEWT_VAL(TSL2591_STATS)
+/* Define the stats section and records */
+STATS_SECT_START(tsl2591_stat_section)
+    STATS_SECT_ENTRY(polled)
+    STATS_SECT_ENTRY(gain_changed)
+    STATS_SECT_ENTRY(timing_changed)
+    STATS_SECT_ENTRY(ints_cleared)
+    STATS_SECT_ENTRY(errors)
+STATS_SECT_END
+
+/* Define stat names for querying */
+STATS_NAME_START(tsl2591_stat_section)
+    STATS_NAME(tsl2591_stat_section, polled)
+    STATS_NAME(tsl2591_stat_section, gain_changed)
+    STATS_NAME(tsl2591_stat_section, timing_changed)
+    STATS_NAME(tsl2591_stat_section, ints_cleared)
+    STATS_NAME(tsl2591_stat_section, errors)
+STATS_NAME_END(tsl2591_stat_section)
+
+/* Global variable used to hold stats data */
+STATS_SECT_DECL(tsl2591_stat_section) g_tsl2591stats;
+#endif
+
+#define LOG_MODULE_TSL2591    (2591)
+#define TSL2591_INFO(...)     LOG_INFO(&_log, LOG_MODULE_TSL2591, __VA_ARGS__)
+#define TSL2591_ERR(...)      LOG_ERROR(&_log, LOG_MODULE_TSL2591, __VA_ARGS__)
+static struct log _log;
+
+#if MYNEWT_VAL(TSL2591_ITIME_DELAY)
+static int tsl2591_itime_delay_ms;
+#endif
+
+/* Exports for the sensor API */
+static int tsl2591_sensor_read(struct sensor *, sensor_type_t,
+        sensor_data_func_t, void *, uint32_t);
+static int tsl2591_sensor_get_config(struct sensor *, sensor_type_t,
+        struct sensor_cfg *);
+
+static const struct sensor_driver g_tsl2591_sensor_driver = {
+    tsl2591_sensor_read,
+    tsl2591_sensor_get_config
+};
+
+int
+tsl2591_write8(struct sensor_itf *itf, uint8_t reg, uint32_t value)
+{
+    int rc;
+    uint8_t payload[2] = { reg, value & 0xFF };
+
+    struct hal_i2c_master_data data_struct = {
+        .address = itf->si_addr,
+        .len = 2,
+        .buffer = payload
+    };
+
+    rc = hal_i2c_master_write(itf->si_num, &data_struct,
+                              OS_TICKS_PER_SEC / 10, 1);
+    if (rc) {
+        TSL2591_ERR("Failed to write 0x%02X:0x%02X with value 0x%02lX\n",
+                    data_struct.address, reg, value);
+#if MYNEWT_VAL(TSL2591_STATS)
+        STATS_INC(g_tsl2591stats, errors);
+#endif
+    }
+
+    return rc;
+}
+
+int
+tsl2591_write16(struct sensor_itf *itf, uint8_t reg, uint16_t value)
+{
+    int rc;
+    uint8_t payload[3] = { reg, value & 0xFF, (value >> 8) & 0xFF };
+
+    struct hal_i2c_master_data data_struct = {
+        .address = itf->si_addr,
+        .len = 3,
+        .buffer = payload
+    };
+
+    rc = hal_i2c_master_write(itf->si_num, &data_struct,
+                              OS_TICKS_PER_SEC / 10, 1);
+    if (rc) {
+        TSL2591_ERR("Failed to write @0x%02X with value 0x%02X 0x%02X\n",
+                    reg, payload[0], payload[1]);
+    }
+
+    return rc;
+}
+
+int
+tsl2591_read8(struct sensor_itf *itf, uint8_t reg, uint8_t *value)
+{
+    int rc;
+    uint8_t payload;
+
+    struct hal_i2c_master_data data_struct = {
+        .address = itf->si_addr,
+        .len = 1,
+        .buffer = &payload
+    };
+
+    /* Register write */
+    payload = reg;
+    rc = hal_i2c_master_write(itf->si_num, &data_struct,
+                              OS_TICKS_PER_SEC / 10, 1);
+    if (rc) {
+        TSL2591_ERR("Failed to address sensor\n");
+        goto err;
+    }
+
+    /* Read one byte back */
+    payload = 0;
+    rc = hal_i2c_master_read(itf->si_num, &data_struct,
+                             OS_TICKS_PER_SEC / 10, 1);
+    *value = payload;
+    if (rc) {
+        TSL2591_ERR("Failed to read @0x%02X\n", reg);
+    }
+
+    return 0;
+err:
+    return rc;
+}
+
+int
+tsl2591_read16(struct sensor_itf *itf, uint8_t reg, uint16_t *value)
+{
+    int rc;
+    uint8_t payload[2] = { reg, 0 };
+
+    struct hal_i2c_master_data data_struct = {
+        .address = itf->si_addr,
+        .len = 1,
+        .buffer = payload
+    };
+
+    /* Register write */
+    rc = hal_i2c_master_write(itf->si_num, &data_struct,
+                              OS_TICKS_PER_SEC / 10, 1);
+    if (rc) {
+        TSL2591_ERR("Failed to address sensor\n");
+        goto err;
+    }
+
+    /* Read two bytes back */
+    memset(payload, 0, 2);
+    data_struct.len = 2;
+    rc = hal_i2c_master_read(itf->si_num, &data_struct,
+                             OS_TICKS_PER_SEC / 10, 1);
+    *value = (uint16_t)payload[0] | ((uint16_t)payload[1] << 8);
+    if (rc) {
+        TSL2591_ERR("Failed to read @0x%02X\n", reg);
+        goto err;
+    }
+
+    return 0;
+err:
+    return rc;
+}
+
+int
+tsl2591_enable(struct sensor_itf *itf, uint8_t state)
+{
+    /* Enable the device by setting the PON and AEN bits */
+    return tsl2591_write8(itf, TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE,
+                          state ? TSL2591_ENABLE_POWERON | TSL2591_ENABLE_AEN :
+                          TSL2591_ENABLE_POWEROFF);
+}
+
+int
+tsl2591_get_enable(struct sensor_itf *itf, uint8_t *enabled)
+{
+    int rc;
+    uint8_t reg;
+
+    /* Check the two enable bits (PON and AEN) */
+    rc =  tsl2591_read8(itf, TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE,
+                        &reg);
+    if (rc) {
+        goto err;
+    }
+
+    *enabled = reg & (TSL2591_ENABLE_POWERON | TSL2591_ENABLE_AEN) ? 1 : 0;
+
+    return 0;
+err:
+    return rc;
+}
+
+int
+tsl2591_set_integration_time(struct sensor_itf *itf,
+                             uint8_t int_time)
+{
+    int rc;
+    uint8_t gain;
+
+    if (int_time > TSL2591_LIGHT_ITIME_600MS) {
+      int_time = TSL2591_LIGHT_ITIME_600MS;
+    }
+
+    rc = tsl2591_get_gain(itf, &gain);
+    if (rc) {
+        goto err;
+    }
+
+    rc = tsl2591_write8(itf, TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL,
+                        int_time | gain);
+    if (rc) {
+        goto err;
+    }
+
+    #if MYNEWT_VAL(TSL2591_ITIME_DELAY)
+    /* Assume a +/-1% margin of error in timing values */
+    tsl2591_itime_delay_ms = (int_time + 1) * 101;
+    #endif
+
+    /* Increment the timing changed counter */
+#if MYNEWT_VAL(TSL2591_STATS)
+    STATS_INC(g_tsl2591stats, timing_changed);
+#endif
+
+    return 0;
+err:
+    return rc;
+}
+
+int
+tsl2591_get_integration_time(struct sensor_itf *itf, uint8_t *itime)
+{
+    int rc;
+    uint8_t reg;
+
+    rc = tsl2591_read8(itf, TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL,
+                       &reg);
+    if (rc) {
+        goto err;
+    }
+
+    *itime = reg & 0x07;
+
+    return 0;
+err:
+    return rc;
+}
+
+int
+tsl2591_set_gain(struct sensor_itf *itf, uint8_t gain)
+{
+    int rc;
+    uint8_t int_time;
+
+    if ((gain != TSL2591_LIGHT_GAIN_LOW)
+        && (gain != TSL2591_LIGHT_GAIN_MED)
+        && (gain != TSL2591_LIGHT_GAIN_HIGH)
+        && (gain != TSL2591_LIGHT_GAIN_MAX)) {
+            TSL2591_ERR("Invalid gain value\n");
+            rc = SYS_EINVAL;
+            goto err;
+    }
+
+    rc = tsl2591_get_integration_time(itf, &int_time);
+    if (rc) {
+        goto err;
+    }
+
+    rc = tsl2591_write8(itf, TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL,
+                        int_time | gain);
+    if (rc) {
+        goto err;
+    }
+
+    /* Increment the gain change counter */
+#if MYNEWT_VAL(TSL2591_STATS)
+    STATS_INC(g_tsl2591stats, gain_changed);
+#endif
+
+    return 0;
+err:
+    return rc;
+}
+
+int
+tsl2591_get_gain(struct sensor_itf *itf, uint8_t *gain)
+{
+    int rc;
+    uint8_t reg;
+
+    rc = tsl2591_read8(itf, TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL,
+                       &reg);
+    if (rc) {
+        goto err;
+    }
+
+    *gain = reg & 0x30;
+
+    return 0;
+err:
+    return rc;
+}
+
+int
+tsl2591_get_data(struct sensor_itf *itf, uint16_t *broadband, uint16_t *ir)
+{
+    int rc;
+
+    #if MYNEWT_VAL(TSL2591_ITIME_DELAY)
+    /* Insert a delay of integration time + 1% to ensure valid sample */
+    os_time_delay((OS_TICKS_PER_SEC / 1000) * tsl2591_itime_delay_ms);
+    #endif
+
+    /* CHAN0 must be read before CHAN1 */
+    /* See: https://forums.adafruit.com/viewtopic.php?f=19&t=124176 */
+    *broadband = *ir = 0;
+    rc = tsl2591_read16(itf, TSL2591_COMMAND_BIT |
+                        TSL2591_REGISTER_CHAN1_LOW, ir);
+    if (rc) {
+        goto err;
+    }
+    rc = tsl2591_read16(itf, TSL2591_COMMAND_BIT |
+                        TSL2591_REGISTER_CHAN0_LOW, broadband);
+    if (rc) {
+        goto err;
+    }
+
+    /* Increment the polling counter */
+#if MYNEWT_VAL(TSL2591_STATS)
+    STATS_INC(g_tsl2591stats, polled);
+#endif
+
+    return 0;
+err:
+    return rc;
+}
+
+int
+tsl2591_init(struct os_dev *dev, void *arg)
+{
+    struct tsl2591 *tsl2591;
+    struct sensor *sensor;
+    int rc;
+
+    if (!arg || !dev) {
+        rc = SYS_ENODEV;
+        goto err;
+    }
+
+    tsl2591 = (struct tsl2591 *) dev;
+
+    tsl2591->cfg.mask = SENSOR_TYPE_ALL;
+
+    log_register(dev->od_name, &_log, &log_console_handler, NULL, 
LOG_SYSLEVEL);
+
+    sensor = &tsl2591->sensor;
+
+#if MYNEWT_VAL(TSL2591_STATS)
+    /* Initialise the stats entry */
+    rc = stats_init(
+        STATS_HDR(g_tsl2591stats),
+        STATS_SIZE_INIT_PARMS(g_tsl2591stats, STATS_SIZE_32),
+        STATS_NAME_INIT_PARMS(tsl2591_stat_section));
+    SYSINIT_PANIC_ASSERT(rc == 0);
+    /* Register the entry with the stats registry */
+    rc = stats_register(dev->od_name, STATS_HDR(g_tsl2591stats));
+    SYSINIT_PANIC_ASSERT(rc == 0);
+#endif
+
+#ifdef ARCH_sim
+    /* Register the sim driver */
+    tsl2591_sim_init();
+#endif
+
+    rc = sensor_init(sensor, dev);
+    if (rc) {
+        goto err;
+    }
+
+    /* Add the light driver */
+    rc = sensor_set_driver(sensor, SENSOR_TYPE_LIGHT,
+            (struct sensor_driver *) &g_tsl2591_sensor_driver);
+    if (rc) {
+        goto err;
+    }
+
+    /* Set the interface */
+    rc = sensor_set_interface(sensor, arg);
+    if (rc) {
+        goto err;
+    }
+
+    rc = sensor_mgr_register(sensor);
+    if (rc) {
+        goto err;
+    }
+
+    return 0;
+err:
+    return rc;
+}
+
+uint32_t
+tsl2591_calculate_lux(struct sensor_itf *itf, uint16_t broadband, uint16_t ir,
+  struct tsl2591_cfg *cfg)
+{
+    int      rc;
+    uint8_t  itime;
+    uint8_t  gain;
+    float    again;
+    float    cpl;
+    float    lux;
+
+    /* Check for overflow conditions */
+    if ((broadband == 0xFFFF) | (ir == 0xFFFF)) {
+        return 0;
+    }
+
+    rc = tsl2591_get_gain(itf, &gain);
+    if (rc) {
+        return 0;
+    }
+
+    switch (gain)
+    {
+      case TSL2591_LIGHT_GAIN_MED :
+        again = 25.0F;
+        break;
+      case TSL2591_LIGHT_GAIN_HIGH :
+        again = 428.0F;
+        break;
+      case TSL2591_LIGHT_GAIN_MAX :
+        again = 9876.0F;
+        break;
+      case TSL2591_LIGHT_GAIN_LOW :
+      default:
+        again = 1.0F;
+        break;
+    }
+
+    rc = tsl2591_get_integration_time(itf, &itime);
+    if (rc) {
+        return 0;
+    }
+
+    cpl = ((float)((itime+1)*101) * again) / TSL2591_LUX_DF;
+
+    lux = (((float)broadband - (float)ir)) *
+      (1.0F - ((float)ir/(float)broadband)) / cpl;
+
+    /* Note that this implementation will truncate values < 1.0 lux! */
+    return (uint32_t)lux;
+}
+
+static int
+tsl2591_sensor_read(struct sensor *sensor, sensor_type_t type,
+        sensor_data_func_t data_func, void *data_arg, uint32_t timeout)
+{
+    struct tsl2591 *tsl2591;
+    struct sensor_light_data sld;
+    struct sensor_itf *itf;
+    uint16_t full;
+    uint16_t ir;
+    uint32_t lux;
+    int rc;
+
+    /* If the read isn't looking for light data, don't do anything. */
+    if (!(type & SENSOR_TYPE_LIGHT)) {
+        rc = SYS_EINVAL;
+        goto err;
+    }
+
+    itf = SENSOR_GET_ITF(sensor);
+    tsl2591 = (struct tsl2591 *)SENSOR_GET_DEVICE(sensor);
+
+    /* Get a new light sample */
+    if (type & SENSOR_TYPE_LIGHT) {
+        full = ir = 0;
+
+        rc = tsl2591_get_data(itf, &full, &ir);
+        if (rc) {
+            goto err;
+        }
+
+        lux = tsl2591_calculate_lux(itf, full, ir, &(tsl2591->cfg));
+        sld.sld_full = full;
+        sld.sld_ir = ir;
+        sld.sld_lux = lux;
+
+        sld.sld_full_is_valid = 1;
+        sld.sld_ir_is_valid   = 1;
+        sld.sld_lux_is_valid  = 1;
+
+        /* Call data function */
+        rc = data_func(sensor, data_arg, &sld, SENSOR_TYPE_LIGHT);
+        if (rc != 0) {
+            goto err;
+        }
+    }
+
+    return 0;
+err:
+    return rc;
+}
+
+static int
+tsl2591_sensor_get_config(struct sensor *sensor, sensor_type_t type,
+        struct sensor_cfg *cfg)
+{
+    int rc;
+
+    if ((type != SENSOR_TYPE_LIGHT)) {
+        rc = SYS_EINVAL;
+        goto err;
+    }
+
+    cfg->sc_valtype = SENSOR_VALUE_TYPE_INT32;
+
+    return 0;
+err:
+    return rc;
+}
+
+int
+tsl2591_config(struct tsl2591 *tsl2591, struct tsl2591_cfg *cfg)
+{
+    int rc;
+    struct sensor_itf *itf;
+
+    itf = SENSOR_GET_ITF(&(tsl2591->sensor));
+
+    rc = tsl2591_enable(itf, 1);
+    if (rc) {
+        goto err;
+    }
+
+    rc = tsl2591_set_integration_time(itf, cfg->integration_time);
+    if (rc) {
+        goto err;
+    }
+
+    tsl2591->cfg.integration_time = cfg->integration_time;
+
+    rc = tsl2591_set_gain(itf, cfg->gain);
+    if (rc) {
+        goto err;
+    }
+
+    tsl2591->cfg.gain = cfg->gain;
+
+    rc = sensor_set_type_mask(&(tsl2591->sensor), cfg->mask);
+    if (rc) {
+        goto err;
+    }
+
+    tsl2591->cfg.mask = cfg->mask;
+
+    return 0;
+err:
+    return rc;
+}
diff --git a/hw/drivers/sensors/tsl2591/src/tsl2591_priv.h 
b/hw/drivers/sensors/tsl2591/src/tsl2591_priv.h
new file mode 100644
index 0000000000..2ae9db5ad2
--- /dev/null
+++ b/hw/drivers/sensors/tsl2591/src/tsl2591_priv.h
@@ -0,0 +1,89 @@
+/*****************************************************************************/
+/*!
+    @file     tsl2591_priv.h
+    @author   Kevin Townsend
+    @section LICENSE
+    Software License Agreement (BSD License)
+    Copyright (c) 2018, Kevin Townsend
+    All rights reserved.
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+    1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+    3. Neither the name of the copyright holders nor the
+    names of its contributors may be used to endorse or promote products
+    derived from this software without specific prior written permission.
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES;
+    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*****************************************************************************/
+#ifndef __ADAFRUIT_TSL2591_PRIV_H__
+#define __ADAFRUIT_TSL2591_PRIV_H__
+
+#define TSL2591_REGISTER_ENABLE             (0x00) /*< Enable register */
+#define TSL2591_REGISTER_CONTROL            (0x01) /*< Control register */
+#define TSL2591_REGISTER_THRESHOLD_AILTL    (0x04) /*< ALS low threshold lower 
byte */
+#define TSL2591_REGISTER_THRESHOLD_AILTH    (0x05) /*< ALS low threshold upper 
byte */
+#define TSL2591_REGISTER_THRESHOLD_AIHTL    (0x06) /*< ALS high threshold 
lower byte */
+#define TSL2591_REGISTER_THRESHOLD_AIHTH    (0x07) /*< ALS high threshold 
upper byte */
+#define TSL2591_REGISTER_THRESHOLD_NPAILTL  (0x08) /*< No Persist ALS low 
threshold lower byte */
+#define TSL2591_REGISTER_THRESHOLD_NPAILTH  (0x09) /*< No Persist ALS low 
threshold higher byte */
+#define TSL2591_REGISTER_THRESHOLD_NPAIHTL  (0x0A) /*< No Persist ALS high 
threshold lower byte */
+#define TSL2591_REGISTER_THRESHOLD_NPAIHTH  (0x0B) /*< No Persist ALS high 
threshold higher byte */
+#define TSL2591_REGISTER_PERSIST_FILTER     (0x0C) /*< Interrupt persistence 
filter */
+#define TSL2591_REGISTER_PACKAGE_PID        (0x11) /*< Package Identification 
*/
+#define TSL2591_REGISTER_DEVICE_ID          (0x12) /*< Device Identification */
+#define TSL2591_REGISTER_DEVICE_STATUS      (0x13) /*< Internal Status */
+#define TSL2591_REGISTER_CHAN0_LOW          (0x14) /*< Channel 0 data, low 
byte */
+#define TSL2591_REGISTER_CHAN0_HIGH         (0x15) /*< Channel 0 data, high 
byte */
+#define TSL2591_REGISTER_CHAN1_LOW          (0x16) /*< Channel 1 data, low 
byte */
+#define TSL2591_REGISTER_CHAN1_HIGH         (0x17) /*< Channel 1 data, high 
byte */
+
+#define TSL2591_VISIBLE           (2)      /*< (channel 0) - (channel 1) */
+#define TSL2591_INFRARED          (1)      /*< channel 1 */
+#define TSL2591_FULLSPECTRUM      (0)      /*< channel 0 */
+
+#define TSL2591_COMMAND_BIT       (0xA0)   /*< 1010 0000: bits 7 and 5 for 
'command normal' */
+
+#define TSL2591_CLEAR_INT         (0xE7)   /*! Special Function Command for 
"Clear ALS and no persist ALS interrupt" */
+#define TSL2591_TEST_INT          (0xE4)   /*! Special Function Command for 
"Interrupt set - forces an interrupt" */
+
+#define TSL2591_WORD_BIT          (0x20)   /*< 1 = read/write word (rather 
than byte) */
+#define TSL2591_BLOCK_BIT         (0x10)   /*< 1 = using block read/write */
+
+#define TSL2591_ENABLE_POWEROFF   (0x00)   /*< Flag for ENABLE register to 
disable */
+#define TSL2591_ENABLE_POWERON    (0x01)   /*< Flag for ENABLE register to 
enable */
+#define TSL2591_ENABLE_AEN        (0x02)   /*< ALS Enable. This field 
activates ALS function. Writing a one activates the ALS. Writing a zero 
disables the ALS. */
+#define TSL2591_ENABLE_AIEN       (0x10)   /*< ALS Interrupt Enable. When 
asserted permits ALS interrupts to be generated, subject to the persist filter. 
*/
+#define TSL2591_ENABLE_NPIEN      (0x80)   /*< No Persist Interrupt Enable. 
When asserted NP Threshold conditions will generate an interrupt, bypassing the 
persist filter */
+
+#define TSL2591_LUX_DF            (408.0F) /*< Lux cooefficient */
+#define TSL2591_LUX_COEFB         (1.64F)  /*< CH0 coefficient */
+#define TSL2591_LUX_COEFC         (0.59F)  /*< CH1 coefficient A */
+#define TSL2591_LUX_COEFD         (0.86F)  /*< CH2 coefficient B */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int tsl2591_write8(struct sensor_itf *itf, uint8_t reg, uint32_t value);
+int tsl2591_write16(struct sensor_itf *itf, uint8_t reg, uint16_t value);
+int tsl2591_read8(struct sensor_itf *itf, uint8_t reg, uint8_t *value);
+int tsl2591_read16(struct sensor_itf *itf, uint8_t reg, uint16_t *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ADAFRUIT_TSL2591_PRIV_H_ */
diff --git a/hw/drivers/sensors/tsl2591/src/tsl2591_shell.c 
b/hw/drivers/sensors/tsl2591/src/tsl2591_shell.c
new file mode 100644
index 0000000000..e81c9962cb
--- /dev/null
+++ b/hw/drivers/sensors/tsl2591/src/tsl2591_shell.c
@@ -0,0 +1,461 @@
+/**************************************************************************/
+/*!
+    @file     tsl2591_shell.c
+    @author   Kevin Townsend
+    @section LICENSE
+    Software License Agreement (BSD License)
+    Copyright (c) 2018, Kevin Townsend
+    All rights reserved.
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+    1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+    3. Neither the name of the copyright holders nor the
+    names of its contributors may be used to endorse or promote products
+    derived from this software without specific prior written permission.
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES;
+    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/**************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include "os/mynewt.h"
+#include "console/console.h"
+#include "shell/shell.h"
+#include "hal/hal_gpio.h"
+#include "tsl2591/tsl2591.h"
+#include "tsl2591_priv.h"
+#include "parse/parse.h"
+
+#if MYNEWT_VAL(TSL2591_CLI)
+
+static int tsl2591_shell_cmd(int argc, char **argv);
+
+static struct shell_cmd tsl2591_shell_cmd_struct = {
+    .sc_cmd = "tsl2591",
+    .sc_cmd_func = tsl2591_shell_cmd
+};
+
+static struct sensor_itf g_sensor_itf = {
+    .si_type = MYNEWT_VAL(TSL2591_SHELL_ITF_TYPE),
+    .si_num = MYNEWT_VAL(TSL2591_SHELL_ITF_NUM),
+    .si_addr = MYNEWT_VAL(TSL2591_SHELL_ITF_ADDR),
+};
+
+static int
+tsl2591_shell_err_too_many_args(char *cmd_name)
+{
+    console_printf("Error: too many arguments for command \"%s\"\n",
+                   cmd_name);
+    return EINVAL;
+}
+
+static int
+tsl2591_shell_err_unknown_arg(char *cmd_name)
+{
+    console_printf("Error: unknown argument \"%s\"\n",
+                   cmd_name);
+    return EINVAL;
+}
+
+static int
+tsl2591_shell_err_invalid_arg(char *cmd_name)
+{
+    console_printf("Error: invalid argument \"%s\"\n",
+                   cmd_name);
+    return EINVAL;
+}
+
+static int
+tsl2591_shell_help(void)
+{
+    console_printf("%s cmd [flags...]\n", tsl2591_shell_cmd_struct.sc_cmd);
+    console_printf("cmd:\n");
+    console_printf("\tr    [n_samples]\n");
+    console_printf("\tgain [0|1|2|3]\n");
+    console_printf("\ttime [100|200|300|400|500|600]\n");
+    console_printf("\ten   [0|1]\n");
+    console_printf("\tdump\n");
+
+    return 0;
+}
+
+static int
+tsl2591_shell_cmd_read(int argc, char **argv)
+{
+    uint16_t full;
+    uint16_t ir;
+    uint16_t samples = 1;
+    uint16_t val;
+    int rc;
+
+    if (argc > 3) {
+        return tsl2591_shell_err_too_many_args(argv[1]);
+    }
+
+    /* Check if more than one sample requested */
+    if (argc == 3) {
+        val = parse_ll_bounds(argv[2], 1, UINT16_MAX, &rc);
+        if (rc) {
+            return tsl2591_shell_err_invalid_arg(argv[2]);
+        }
+        samples = val;
+    }
+
+    while(samples--) {
+        rc = tsl2591_get_data(&g_sensor_itf, &full, &ir);
+        if (rc) {
+            console_printf("Read failed: %d\n", rc);
+            return rc;
+        }
+        console_printf("Full:  %u\n", full);
+        console_printf("IR:    %u\n", ir);
+    }
+
+    return 0;
+}
+
+static int
+tsl2591_shell_cmd_gain(int argc, char **argv)
+{
+    uint8_t val;
+    uint8_t gain;
+    int rc;
+
+    if (argc > 3) {
+        return tsl2591_shell_err_too_many_args(argv[1]);
+    }
+
+    /* Display the gain */
+    if (argc == 2) {
+        rc = tsl2591_get_gain(&g_sensor_itf, &gain);
+        if (rc) {
+            console_printf("Getting gain failed rc:%d", rc);
+            goto err;
+        }
+        switch (gain) {
+            case TSL2591_LIGHT_GAIN_LOW:
+                console_printf("0 (1x)\n");
+            break;
+            case TSL2591_LIGHT_GAIN_MED:
+                console_printf("1 (25x)\n");
+            break;
+            case TSL2591_LIGHT_GAIN_HIGH:
+                console_printf("2 (428x)\n");
+            break;
+            case TSL2591_LIGHT_GAIN_MAX:
+                console_printf("3 (9876x)\n");
+            break;
+            default:
+                console_printf("ERROR!\n");
+            break;
+        }
+    }
+
+    /* Update the gain */
+    if (argc == 3) {
+        val = parse_ll_bounds(argv[2], 0, 3, &rc);
+        /* Make sure gain is valid */
+        if (rc) {
+            return tsl2591_shell_err_invalid_arg(argv[2]);
+        }
+        rc = tsl2591_set_gain(&g_sensor_itf, val << 4);
+        if (rc) {
+            console_printf("Setting gain failed rc:%d", rc);
+        }
+    }
+
+err:
+    return rc;
+}
+
+static int
+tsl2591_shell_cmd_time(int argc, char **argv)
+{
+    uint8_t time;
+    long val;
+    int rc;
+
+    if (argc > 3) {
+        return tsl2591_shell_err_too_many_args(argv[1]);
+    }
+
+    /* Display the integration time */
+    if (argc == 2) {
+        rc = tsl2591_get_integration_time(&g_sensor_itf, &time);
+        if (rc) {
+            console_printf("Getting integration time failed rc:%d", rc);
+            goto err;
+        }
+
+        switch (time) {
+            case TSL2591_LIGHT_ITIME_100MS:
+                console_printf("100\n");
+            break;
+            case TSL2591_LIGHT_ITIME_200MS:
+                console_printf("200\n");
+            break;
+            case TSL2591_LIGHT_ITIME_300MS:
+                console_printf("300\n");
+            break;
+            case TSL2591_LIGHT_ITIME_400MS:
+                console_printf("400\n");
+            break;
+            case TSL2591_LIGHT_ITIME_500MS:
+                console_printf("500\n");
+            break;
+            case TSL2591_LIGHT_ITIME_600MS:
+                console_printf("600\n");
+            break;
+        }
+    }
+
+    /* Set the integration time */
+    if (argc == 3) {
+        val = parse_ll_bounds(argv[2], 100, 600, &rc);
+        /* Make sure val is 100, 200, 300, 400, 500 or 600 */
+        if (rc || ((val != 100) && (val != 200) && (val != 300) &&
+            (val != 400) && (val != 500) && (val != 600))) {
+                return tsl2591_shell_err_invalid_arg(argv[2]);
+        }
+        switch(val) {
+            case 100:
+                rc = tsl2591_set_integration_time(&g_sensor_itf, 
TSL2591_LIGHT_ITIME_100MS);
+            break;
+            case 200:
+                rc = tsl2591_set_integration_time(&g_sensor_itf, 
TSL2591_LIGHT_ITIME_200MS);
+            break;
+            case 300:
+                rc = tsl2591_set_integration_time(&g_sensor_itf, 
TSL2591_LIGHT_ITIME_300MS);
+            break;
+            case 400:
+                rc = tsl2591_set_integration_time(&g_sensor_itf, 
TSL2591_LIGHT_ITIME_400MS);
+            break;
+            case 500:
+                rc = tsl2591_set_integration_time(&g_sensor_itf, 
TSL2591_LIGHT_ITIME_500MS);
+            break;
+            case 600:
+                rc = tsl2591_set_integration_time(&g_sensor_itf, 
TSL2591_LIGHT_ITIME_600MS);
+            break;
+        }
+
+        if (rc) {
+            console_printf("Setting integration time failed rc:%d", rc);
+        }
+    }
+
+err:
+    return rc;
+}
+
+static int
+tsl2591_shell_cmd_en(int argc, char **argv)
+{
+    char *endptr;
+    long lval;
+    int rc;
+    uint8_t enabled;
+
+    if (argc > 3) {
+        return tsl2591_shell_err_too_many_args(argv[1]);
+    }
+
+    /* Display current enable state */
+    if (argc == 2) {
+        rc = tsl2591_get_enable(&g_sensor_itf, &enabled);
+        if (rc) {
+            console_printf("Enable read failure rc:%d", rc);
+            goto err;
+        }
+
+        console_printf("%u\n", enabled);
+    }
+
+    /* Update the enable state */
+    if (argc == 3) {
+        lval = strtol(argv[2], &endptr, 10); /* Base 10 */
+        if (argv[2] != '\0' && *endptr == '\0' &&
+            lval >= 0 && lval <= 1) {
+            rc = tsl2591_enable(&g_sensor_itf, lval);
+            if (rc) {
+                console_printf("Could not enable sensor rc:%d", rc);
+                goto err;
+            }
+        } else {
+            return tsl2591_shell_err_invalid_arg(argv[2]);
+        }
+    }
+
+    return 0;
+err:
+    return rc;
+}
+
+static int
+tsl2591_shell_print_reg(int reg, char *name)
+{
+    uint8_t val;
+    int rc;
+
+    val = 0;
+    rc = tsl2591_read8(&g_sensor_itf,
+                      TSL2591_COMMAND_BIT | reg,
+                      &val);
+    if (rc) {
+       goto err;
+    }
+    console_printf("0x%02X (%s): 0x%02X\n", reg, name, val);
+
+    return 0;
+err:
+    return rc;
+}
+
+static int
+tsl2591_shell_cmd_dump(int argc, char **argv)
+{
+    int rc;
+
+    if (argc > 3) {
+        return tsl2591_shell_err_too_many_args(argv[1]);
+    }
+
+    /* Dump all the register values for debug purposes */
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_ENABLE, "ENABLE");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_CONTROL, "CONTROL");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_THRESHOLD_AILTL, "AILTL");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_THRESHOLD_AILTH, "AILTH");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_THRESHOLD_AIHTL, "AIHTL");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_THRESHOLD_AIHTH, "AIHTH");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_THRESHOLD_NPAILTL, 
"NPAILTL");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_THRESHOLD_NPAILTH, 
"NPAILTH");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_THRESHOLD_NPAIHTL, 
"NPAIHTL");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_THRESHOLD_NPAIHTH, 
"NPAIHTH");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_PERSIST_FILTER, "FILTER");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_PACKAGE_PID, "PACKAGEID");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_DEVICE_ID, "DEVICEID");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_DEVICE_STATUS, "STATUS");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_CHAN0_LOW, "CHAN0_LOW");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_CHAN0_HIGH, "CHAN0_HIGH");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_CHAN1_LOW, "CHAN1_LOW");
+    if (rc) {
+       goto err;
+    }
+    rc = tsl2591_shell_print_reg(TSL2591_REGISTER_CHAN1_HIGH, "CHAN1_HIGH");
+    if (rc) {
+       goto err;
+    }
+
+    return 0;
+err:
+    console_printf("Read failed rc:%d", rc);
+    return rc;
+}
+
+static int
+tsl2591_shell_cmd(int argc, char **argv)
+{
+    if (argc == 1) {
+        return tsl2591_shell_help();
+    }
+
+    /* Read command (get a new data sample) */
+    if (argc > 1 && strcmp(argv[1], "r") == 0) {
+        return tsl2591_shell_cmd_read(argc, argv);
+    }
+
+    /* Gain command */
+    if (argc > 1 && strcmp(argv[1], "gain") == 0) {
+        return tsl2591_shell_cmd_gain(argc, argv);
+    }
+
+    /* Integration time command */
+    if (argc > 1 && strcmp(argv[1], "time") == 0) {
+        return tsl2591_shell_cmd_time(argc, argv);
+    }
+
+    /* Enable */
+    if (argc > 1 && strcmp(argv[1], "en") == 0) {
+        return tsl2591_shell_cmd_en(argc, argv);
+    }
+
+    /* Debug */
+    if (argc > 1 && strcmp(argv[1], "dump") == 0) {
+        return tsl2591_shell_cmd_dump(argc, argv);
+    }
+
+    return tsl2591_shell_err_unknown_arg(argv[1]);
+}
+
+int
+tsl2591_shell_init(void)
+{
+    int rc;
+
+    rc = shell_cmd_register(&tsl2591_shell_cmd_struct);
+    SYSINIT_PANIC_ASSERT(rc == 0);
+
+    return rc;
+}
+
+#endif
diff --git a/hw/drivers/sensors/tsl2591/src/tsl2591_sim.c 
b/hw/drivers/sensors/tsl2591/src/tsl2591_sim.c
new file mode 100644
index 0000000000..7669fc0896
--- /dev/null
+++ b/hw/drivers/sensors/tsl2591/src/tsl2591_sim.c
@@ -0,0 +1,130 @@
+/**************************************************************************/
+/*!
+    @file     tsl2591_sim.c
+    @author   Kevin Townsend
+    @section LICENSE
+    Software License Agreement (BSD License)
+    Copyright (c) 2018, Kevin Townsend
+    All rights reserved.
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+    1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+    3. Neither the name of the copyright holders nor the
+    names of its contributors may be used to endorse or promote products
+    derived from this software without specific prior written permission.
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES;
+    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/**************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include "os/mynewt.h"
+#include "tsl2591/tsl2591.h"
+#include "tsl2591_priv.h"
+#include "hal/hal_i2c_sim.h"
+
+/* Default register values for this sensor */
+static uint8_t g_tsl2591_sim_regs[TSL2591_REGISTER_CHAN1_HIGH] = {
+  /* 0x00 = TSL2591_REGISTER_ENABLE */
+  0x00,
+  /* 0x01 = TSL2591_REGISTER_CONTROL */
+  0x00,
+  /* 0x02 = RESERVED */
+  0x00,
+  /* 0x03 = RESERVED */
+  0x00,
+  /* 0x04 = TSL2591_REGISTER_THRESHOLD_AILTL */
+  0x00,
+  /* 0x05 = TSL2591_REGISTER_THRESHOLD_AILTH */
+  0x00,
+  /* 0x06 = TSL2591_REGISTER_THRESHOLD_AIHTL */
+  0x00,
+  /* 0x07 = TSL2591_REGISTER_THRESHOLD_AIHTH */
+  0x00,
+  /* 0x08 = TSL2591_REGISTER_THRESHOLD_NPAILTL */
+  0x00,
+  /* 0x09 = TSL2591_REGISTER_THRESHOLD_NPAILTH */
+  0x00,
+  /* 0x0A = TSL2591_REGISTER_THRESHOLD_NPAIHTL */
+  0x00,
+  /* 0x0B = TSL2591_REGISTER_THRESHOLD_NPAIHTH */
+  0x00,
+  /* 0x0C = TSL2591_REGISTER_PERSIST_FILTER */
+  0x00,
+  /* 0x11 = TSL2591_REGISTER_PACKAGE_PID */
+  0x00,
+  /* 0x12 = TSL2591_REGISTER_DEVICE_ID */
+  0x50,
+  /* 0x13 = TSL2591_REGISTER_DEVICE_STATUS */
+  0x00,
+  /* 0x14 = TSL2591_REGISTER_CHAN0_LOW */
+  0x00,
+  /* 0x15 = TSL2591_REGISTER_CHAN0_HIGH */
+  0x00,
+  /* 0x16 = TSL2591_REGISTER_CHAN1_LOW */
+  0x00,
+  /* 0x17 = TSL2591_REGISTER_CHAN1_HIGH */
+  0x00
+};
+
+int
+tsl2591_sensor_sim_write(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
+                         uint32_t timeout, uint8_t last_op)
+{
+    printf("TSL2591 wrote %d byte(s):", pdata->len);
+    for (uint16_t i=0; i<pdata->len; i++) {
+        printf(" 0x%02X", pdata->buffer[i]);
+    }
+    printf("\n");
+    fflush(stdout);
+
+    return 0;
+}
+
+int
+tsl2591_sensor_sim_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
+                            uint32_t timeout, uint8_t last_op)
+{
+    printf("TSL2591  read %d byte(s):", pdata->len);
+    for (uint16_t i=0; i<pdata->len; i++) {
+        printf(" 0x%02X", pdata->buffer[i]);
+    }
+    printf("\n");
+    fflush(stdout);
+
+    return 0;
+}
+
+static const struct hal_i2c_sim_driver g_tsl2591_sensor_sim_driver = {
+    .sd_write = tsl2591_sensor_sim_write,
+    .sd_read = tsl2591_sensor_sim_read,
+    .addr = MYNEWT_VAL(TSL2591_SHELL_ITF_ADDR)
+};
+
+int
+tsl2591_sim_init(void)
+{
+    printf("Registering TSL2591 sim driver\n");
+    fflush(stdout);
+
+    (void)g_tsl2591_sim_regs;
+
+    /* Register this sim driver with the hal_i2c simulator */
+    hal_i2c_sim_register((struct hal_i2c_sim_driver *)
+                         &g_tsl2591_sensor_sim_driver);
+
+    return 0;
+}
diff --git a/hw/drivers/sensors/tsl2591/syscfg.yml 
b/hw/drivers/sensors/tsl2591/syscfg.yml
new file mode 100644
index 0000000000..293fbf5494
--- /dev/null
+++ b/hw/drivers/sensors/tsl2591/syscfg.yml
@@ -0,0 +1,44 @@
+# The BSD License (BSD)
+#
+# Copyright (c) 2018 Kevin Townsend
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in 
all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+syscfg.defs:
+    TSL2591_CLI:
+        description: 'Enable shell support for the TSL2591'
+        value: 0
+    TSL2591_CONFIG:
+        description: 'Persist TSL2591 settings using sys/config'
+        value: 0
+    TSL2591_STATS:
+        description: 'Enable stats collection for TSL2591'
+        value: 0
+    TSL2591_SHELL_ITF_TYPE:
+        description: 'Select interface type'
+        value: 1
+    TSL2591_SHELL_ITF_NUM:
+        description: 'Select interface number'
+        value: 0
+    TSL2591_SHELL_ITF_ADDR:
+        description: 'TSL2591 I2C Addresss'
+        value: 0x29
+    TSL2591_ITIME_DELAY:
+        description: 'Enable an internal read delay based on integration time'
+        value: 0
diff --git a/hw/sensor/creator/pkg.yml b/hw/sensor/creator/pkg.yml
index ce66660b3c..23548249e1 100644
--- a/hw/sensor/creator/pkg.yml
+++ b/hw/sensor/creator/pkg.yml
@@ -54,5 +54,7 @@ pkg.deps.LIS2DW12_OFB:
     - hw/drivers/sensors/lis2dw12
 pkg.deps.LIS2DS12_OFB:
     - hw/drivers/sensors/lis2ds12
+pkg.deps.TSL2591_OFB:
+    - hw/drivers/sensors/tsl2591
 pkg.init:
     sensor_dev_create: 500
diff --git a/hw/sensor/creator/src/sensor_creator.c 
b/hw/sensor/creator/src/sensor_creator.c
index 8b7f39c975..9e351222f2 100644
--- a/hw/sensor/creator/src/sensor_creator.c
+++ b/hw/sensor/creator/src/sensor_creator.c
@@ -37,6 +37,9 @@
 #if MYNEWT_VAL(TSL2561_OFB)
 #include <tsl2561/tsl2561.h>
 #endif
+#if MYNEWT_VAL(TSL2591_OFB)
+#include <tsl2591/tsl2591.h>
+#endif
 #if MYNEWT_VAL(TCS34725_OFB)
 #include <tcs34725/tcs34725.h>
 #endif
@@ -102,6 +105,10 @@ static struct bno055 bno055;
 static struct tsl2561 tsl2561;
 #endif
 
+#if MYNEWT_VAL(TSL2591_OFB)
+static struct tsl2591 tsl2591;
+#endif
+
 #if MYNEWT_VAL(TCS34725_OFB)
 static struct tcs34725 tcs34725;
 #endif
@@ -224,6 +231,15 @@ static struct sensor_itf i2c_0_itf_tsl = {
 };
 #endif
 
+#if MYNEWT_VAL(I2C_0) && MYNEWT_VAL(TSL2591_OFB)
+static struct sensor_itf i2c_0_itf_tsl = {
+    .si_type = SENSOR_ITF_I2C,
+    .si_num  = 0,
+    /*  I2C address for the TSL2591 (0x29) */
+    .si_addr = 0x29
+};
+#endif
+
 #if MYNEWT_VAL(I2C_0) && MYNEWT_VAL(TCS34725_OFB)
 static struct sensor_itf i2c_0_itf_tcs = {
     .si_type = SENSOR_ITF_I2C,
@@ -531,6 +547,34 @@ config_tsl2561_sensor(void)
 }
 #endif
 
+/**
++ * TSL2591 Sensor default configuration used by the creator package
++ *
++ * @return 0 on success, non-zero on failure
++ */
+#if MYNEWT_VAL(TSL2591_OFB)
+static int
+config_tsl2591_sensor(void)
+{
+    int rc;
+    struct os_dev *dev;
+    struct tsl2591_cfg tslcfg;
+
+    dev = (struct os_dev *) os_dev_open("tsl2591_0", OS_TIMEOUT_NEVER, NULL);
+    assert(dev != NULL);
+
+    /* Gain set to 1X and Inetgration time set to 100ms */
+    tslcfg.gain = TSL2591_LIGHT_GAIN_LOW;
+    tslcfg.integration_time = TSL2591_LIGHT_ITIME_100MS;
+    tslcfg.mask = SENSOR_TYPE_LIGHT;
+
+    rc = tsl2591_config((struct tsl2591 *)dev, &tslcfg);
+
+    os_dev_close(dev);
+    return rc;
+}
+#endif
+
 /**
  * DRV2605 Actuator default configuration used by the creator package
  *
@@ -813,7 +857,7 @@ config_lis2dw12_sensor(void)
 
     cfg.filter_bw = LIS2DW12_FILTER_BW_ODR_DIV_2;
     cfg.high_pass = 0;
-    
+
     cfg.tap.en_x = 1;
     cfg.tap.en_y = 1;
     cfg.tap.en_z = 1;
@@ -853,7 +897,7 @@ config_lis2dw12_sensor(void)
     cfg.power_mode = LIS2DW12_PM_HIGH_PERF;
     cfg.inactivity_sleep_enable = 0;
     cfg.low_noise_enable = 1;
-    
+
     cfg.read_mode.mode = LIS2DW12_READ_M_POLL;
 
     cfg.mask = SENSOR_TYPE_ACCELEROMETER;
@@ -927,7 +971,7 @@ config_lis2ds12_sensor(void)
 
     rc = lis2ds12_config((struct lis2ds12 *) dev, &cfg);
     assert(rc == 0);
-    
+
     os_dev_close(dev);
     return rc;
 }
@@ -1039,6 +1083,15 @@ sensor_dev_create(void)
     assert(rc == 0);
 #endif
 
+#if MYNEWT_VAL(TSL2591_OFB)
+    rc = os_dev_create((struct os_dev *) &tsl2591, "tsl2591_0",
+      OS_DEV_INIT_PRIMARY, 0, tsl2591_init, (void *)&i2c_0_itf_tsl);
+    assert(rc == 0);
+
+    rc = config_tsl2591_sensor();
+    assert(rc == 0);
+#endif
+
 #if MYNEWT_VAL(TCS34725_OFB)
     rc = os_dev_create((struct os_dev *) &tcs34725, "tcs34725_0",
       OS_DEV_INIT_PRIMARY, 0, tcs34725_init, (void *)&i2c_0_itf_tcs);
diff --git a/hw/sensor/creator/syscfg.yml b/hw/sensor/creator/syscfg.yml
index 92502ef3b2..29089792b4 100644
--- a/hw/sensor/creator/syscfg.yml
+++ b/hw/sensor/creator/syscfg.yml
@@ -67,3 +67,6 @@ syscfg.defs:
     LIS2DS12_OFB:
         description: 'LIS2DS12 is present'
         value : 0
+    TSL2591_OFB:
+        description: 'TSL2591 is present'
+        value : 0


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to