initial commit, reads dev id

Files at this revision

API Documentation at this revision

Comitter:
phonemacro
Date:
Fri Aug 17 05:35:58 2018 +0000
Parent:
4:6ec3bc44f055
Child:
6:ec1c447e825c
Commit message:
Updated driver for MAX86140/MAX86141 driver functions

Changed in this revision

MAX8614X.cpp Show annotated file Show diff for this revision Revisions of this file
MAX8614X.h Show annotated file Show diff for this revision Revisions of this file
MAX8614X_agc.cpp Show annotated file Show diff for this revision Revisions of this file
MaximSensor/MaximSensor.cpp Show annotated file Show diff for this revision Revisions of this file
MaximSensor/MaximSensor.h Show annotated file Show diff for this revision Revisions of this file
MaximSensor/queue.cpp Show annotated file Show diff for this revision Revisions of this file
MaximSensor/queue.h Show annotated file Show diff for this revision Revisions of this file
--- a/MAX8614X.cpp	Thu Aug 16 19:53:01 2018 +0000
+++ b/MAX8614X.cpp	Fri Aug 17 05:35:58 2018 +0000
@@ -45,20 +45,13 @@
     m_cs = 1;
 }
 
-int MAX8614X::init()
-{
-    int ret = RTN_NO_ERROR;
-    m_ir.mode(PullUp);
-    m_ir.fall(Callback<void()>(this, &MAX8614X::irq_handler));
-
-    return ret;
-}
 int MAX8614X::readRegister(uint8_t reg, uint8_t *data, int len)
 {
     m_cs = 0;
 
     m_spiBus.write(reg);
     m_spiBus.write(0x80);
+
     int i = 0;
     for(; i < len; i++) { /*TODO: make len unsigned*/
         data[i] = m_spiBus.write(0x00);
@@ -97,6 +90,212 @@
 
     return ret;
 }
+
+int MAX8614X::get_part_info(uint8_t *part_id, uint8_t *rev_id)
+{
+    uint32_t i;
+    int ret;
+    uint8_t buf[2];
+    const uint8_t max8614x_part_ids[] = {
+        MAX86140_PART_ID_VAL,
+        MAX86141_PART_ID_VAL,
+        MAX86142_PART_ID_VAL,
+        MAX86143_PART_ID_VAL,
+    };
+
+    ret = readRegister(MAX8614X_REV_ID_REG, buf, 2);
+    if (ret < 0) {
+        pr_err("readRegister failed. ret: %d", ret);
+        return ret;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(max8614x_part_ids); i++) {
+        if (buf[1] == max8614x_part_ids[i]) {
+            *rev_id = buf[0];
+            *part_id = buf[1];
+            return 0;
+        }
+    }
+
+    // Unsupported part
+    return -1;
+}
+
+int MAX8614X::get_num_samples_in_fifo()
+{
+    int fifo_ovf_cnt;
+    uint8_t fifo_data[4];
+    uint32_t num_samples;
+    int ret;
+
+    ret = readRegister(MAX8614X_OVF_CNT_REG, fifo_data, 2);
+    if (ret < 0) {
+        pr_err("readRegister failed. ret: %d", ret);
+        return ret;
+    }
+
+    fifo_ovf_cnt = fifo_data[0] & MAX8614X_OVF_CNT_MASK;
+    num_samples = fifo_data[1];
+
+    if (num_samples >= MAX8614X_MAX_FIFO_DEPTH) {
+        pr_err("# FIFO is Full. OVF: %d num_samples: %lu",
+                fifo_ovf_cnt, num_samples);
+    }
+
+    return num_samples;
+}
+
+int MAX8614X::read_fifo_data(uint8_t *fifo_data, int num_samples)
+{
+    uint16_t num_bytes = num_samples * MAX8614X_DATA_WORD_SIZE;
+    int ret = 0;
+
+    struct RegisterMap test_clk_enable[] = {
+        {0xFF, 0x54},
+        {0xFF, 0x4D},
+        {0x81, 0x20},
+        {0xFF, 0x00}
+    };
+
+    struct RegisterMap test_clk_disable[] = {
+        {0xFF, 0x54},
+        {0xFF, 0x4D},
+        {0x81, 0x00},
+        {0xFF, 0x00}
+    };
+
+
+    ret = writeBlock(test_clk_enable, ARRAY_SIZE(test_clk_enable));
+    if (ret < 0) {
+        pr_err("writeBlock failed. ret: %d", ret);
+        return ret;
+    }
+
+    fifo_data[0] = MAX8614X_FIFO_DATA_REG;
+    ret = readRegister(MAX8614X_FIFO_DATA_REG, fifo_data, num_bytes);
+    if (ret < 0) {
+        pr_err("readRegister failed. ret: %d", ret);
+        return ret;
+    }
+
+    ret = writeBlock(test_clk_disable, ARRAY_SIZE(test_clk_disable));
+    if (ret < 0) {
+        pr_err("writeBlock failed. ret: %d", ret);
+        return ret;
+    }
+
+    return ret;
+}
+
+void MAX8614X::fifo_irq_handler()
+{
+    uint8_t fifo_buf[MAX8614X_MAX_FIFO_DEPTH * MAX8614X_DATA_WORD_SIZE] = {0};
+    int ret;
+    int num_samples = 0;
+    static int last_samples[DATA_TYPE_PPG2_LEDC4];
+    fifo_data_t fifo_data;
+    uint16_t idx;
+    int i;
+    static ppg_data_t ppg_data;
+    static uint32_t ppg_data_ack = 0;
+    const uint32_t ir_green_red_ppg_type = ((1 << DATA_TYPE_PPG1_LEDC1) |
+                                            (1 << DATA_TYPE_PPG1_LEDC2) |
+                                            (1 << DATA_TYPE_PPG1_LEDC3));
+
+    num_samples = get_num_samples_in_fifo();
+    if (num_samples <= 0) {
+        pr_debug("get_num_samples_in_fifo failed. err: %d", num_samples);
+        return;
+    }
+
+    ret = read_fifo_data(fifo_buf, num_samples);
+    if (ret < 0) {
+        pr_debug("read_fifo_data failed. ret: %d", ret);
+        return;
+    }
+
+    for (i = 0; i < num_samples; i++) {
+        idx = MAX8614X_DATA_WORD_SIZE * i;
+        fifo_data.raw = fifo_buf[idx + 0] << 16
+                | fifo_buf[idx + 1] << 8
+                | fifo_buf[idx + 2];
+        if (fifo_data.type == DATA_TYPE_INVALID_DATA || fifo_data.type == 0) {
+            pr_err("Received invalid data. data: %X, i: %d",
+                    (unsigned int)fifo_data.raw, i);
+
+            continue;
+        }
+        pr_debug("\ttype: %lu, val: %lu (%lX)",
+                fifo_data.type, fifo_data.val, fifo_data.val);
+
+        if (fifo_data.type > DATA_TYPE_PPG2_LEDC3) {
+            pr_err("Wrong Data Type: -> Type: %lu, val:%lu, Raw:%lu",
+                    fifo_data.type, fifo_data.val, fifo_data.raw);
+            continue;
+        }
+
+        if (fifo_data.type > 0 && fifo_data.type < DATA_TYPE_PPG2_LEDC3) {
+            last_samples[fifo_data.type] = fifo_data.val;
+        }
+
+        if (fifo_data.type == DATA_TYPE_PPG1_LEDC1) {
+            max8614x_agc_handler(&led_ctrl, last_samples);
+        }
+
+        if (fifo_data.type == DATA_TYPE_PPG1_LEDC1) {
+            ppg_data.ir = fifo_data.val;
+        } else if (fifo_data.type == DATA_TYPE_PPG1_LEDC2) {
+            ppg_data.red = fifo_data.val;
+        } else if (fifo_data.type == DATA_TYPE_PPG1_LEDC3) {
+            ppg_data.green = fifo_data.val;
+        }
+
+        ppg_data_ack |= 1 << fifo_data.type;
+
+        if ((ppg_data_ack & ir_green_red_ppg_type) != ir_green_red_ppg_type ){
+            continue;
+        }
+        ppg_data_ack = 0;
+
+        ret = enqueue(&queue, &ppg_data);
+        if (ret < 0) {
+            pr_err("Enqueue data is failed. ret: %d, thrown: %d",
+                    ret, num_samples - i);
+            return;
+        }
+    }
+}
+
+int MAX8614X::enable_die_temp()
+{
+    int ret = 0;
+
+    ret = writeRegister(MAX8614X_DIE_TEMP_CFG_REG, MAX8614X_DIE_TEMP_EN);
+    if (ret < 0) {
+        pr_err("SPI Communication error");
+    }
+
+    return ret;
+}
+
+int MAX8614X::read_die_temp()
+{
+    int ret = 0;
+    uint8_t buf[2];
+
+    ret = readRegister(MAX8614X_DIE_TEMP_INT_REG, buf, 2);
+    if (ret < 0) {
+        pr_err("Unable to read die_temp. ret: %d", ret);
+        return ret;
+    }
+
+    die_temp.frac = (uint8_t)buf[1] & MAX8614X_DIE_TEMP_FRAC_MASK;
+    die_temp.tint = (uint8_t)buf[0];
+
+    pr_debug("Die temp: %d - %d, %d", die_temp.val, buf[0], buf[1]);
+    return enable_die_temp();
+}
+
 void MAX8614X::irq_handler(void)
 {
     int ret;
@@ -104,10 +303,30 @@
 
     ret = readRegister(MAX8614X_INT_STATUS1_REG, status.val, 2);
     if (ret < 0) {
-        printf("readRegister failed. ret: %d", ret);
+        pr_err("readRegister failed. ret: %d", ret);
+    }
+    pr_debug("Status reg: %X %X", status.val[0], status.val[1]);
+
+    if (status.a_full || status.data_rdy) {
+        fifo_irq_handler();
+    }
+
+    if (status.die_temp_rdy) {
+        pr_debug("Pwr_rdy interrupt was triggered.");
     }
-    printf("Status reg: %X %X \n\r", status.val[0], status.val[1]);
+
+    if (status.pwr_rdy) {
+        pr_info("Pwr_rdy interrupt was triggered.");
+    }
 
+    if (status.die_temp_rdy) {
+        read_die_temp();
+    }
+
+    if (status.vdd_oor) {
+        vdd_oor_cnt++;
+        pr_info("VDD Out of range cnt: %d", vdd_oor_cnt);
+    }
     if (status.sha_done) {
         shaComplete = true;
         printf("sha interrupt\n\r");
@@ -121,7 +340,213 @@
 {
     shaComplete = false;
 }
-MAX8614X::~MAX8614X(void) 
+int MAX8614X::reset()
+{
+    int ret = 0;
+
+    ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG,
+            MAX8614X_SYSTEM_RESET_MASK);
+    if (ret < 0) {
+        pr_err("writeRegister failed. ret: %d", ret);
+        return ret;
+    }
+
+    ret = queue_reset(&queue);
+    if (ret < 0) {
+        pr_err("queue_reset failed. ret: %d", ret);
+        return ret;
+    }
+
+    led_control_reset(&led_ctrl);
+
+    return ret;
+}
+
+int MAX8614X::poweroff()
+{
+    int ret = 0;
+
+    ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG,
+            MAX8614X_SYSTEM_SHDN_MASK);
+    if (ret < 0) {
+        pr_err("writeRegister failed. ret: %d", ret);
+        return ret;
+    }
+
+    return ret;
+}
+
+int MAX8614X::init()
+{
+    int ret = RTN_NO_ERROR;
+    uint8_t part_id, rev_id;
+    void *queue_buf = NULL;
+
+    ret = get_part_info(&part_id, &rev_id);
+    if (ret < 0) {
+        pr_err("MAX8614X is not detected. Part_id: 0x%X, Rev_Id: 0x%X",
+                part_id, rev_id);
+        ret = RTN_ERR_NOT_8614x;
+        goto fail;
+    }
+    pr_info("MAX8614X detected. Part_id: 0x%X, Rev_Id: 0x%X", part_id, rev_id);
+
+    queue_buf = malloc(sizeof(ppg_data_t) * MAX8614X_DRIVER_FIFO_SZ);
+    if (queue_buf == NULL) {
+        pr_err("malloc failed. ret: %d", ret);
+        ret = RTN_ERR_MEM_ALLOC_FAIL;
+        goto fail;
+    }
+
+    ret = queue_init(&queue, queue_buf,
+            sizeof(ppg_data_t), sizeof(ppg_data_t) * MAX8614X_DRIVER_FIFO_SZ);
+    if (ret < 0) {
+        pr_err("queue_init failed");
+        ret = RTN_ERR_QUEUE_INIT;
+        free(queue_buf);
+        goto fail;
+    }
+
+    ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG,
+            MAX8614X_SYSTEM_RESET_MASK);
+    if (ret < 0) {
+        pr_err("writeRegister failed. ret: %d", ret);
+        goto fail;
+    }
+
+    die_temp.frac = 0;
+    die_temp.tint = 0;
+
+    led_control_init(&led_ctrl); /*TODO: after porting agc, test */
+
+    m_ir.fall(Callback<void()>(this, &MAX8614X::irq_handler));
+
+    return ret;
+fail:
+    pr_err("Init failed. ret: %d", ret);
+    return ret;
+}
+
+int MAX8614X::sensor_enable(int enable)
 {
-  //empty block
-}
\ No newline at end of file
+    int ret = RTN_NO_ERROR;
+    uint8_t led_seq[3];
+
+    RegisterMap_t ppg_init_cfg[] = {
+        { MAX8614X_SYSTEM_CTRL_REG, MAX8614X_SYSTEM_RESET_MASK},
+        { MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us)
+                               | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA)
+                               | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA)
+        { MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_100_SPS}, // PPG_SR: 3 (100Hz), SMP_AVE=0
+        { MAX8614X_LED_SEQ1_REG, 0x21},
+        { MAX8614X_LED_SEQ2_REG, 0x03},
+        { MAX8614X_LED1_PA_REG, 0x80},
+        { MAX8614X_LED2_PA_REG, 0x80},
+        { MAX8614X_LED3_PA_REG, 0x80},
+        { MAX8614X_LED_RANGE1_REG, MAX8614X_LED1_RGE_25mA_MASK
+                                 | MAX8614X_LED2_RGE_25mA_MASK
+                                 | MAX8614X_LED3_RGE_25mA_MASK},
+        { MAX8614X_FIFO_CFG1_REG, 0x0C},
+        { MAX8614X_FIFO_CFG2_REG, MAX8614X_FLUSH_FIFO_MASK
+                                | MAX8614X_FIFO_STAT_CLR_MASK
+                                | MAX8614X_A_FULL_TYPE_MASK // Try 0
+                                | MAX8614X_FIFO_RO_MASK
+                                | MAX8614X_FIFO_EN_MASK},
+        { MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_A_FULL_MASK
+                                  | MAX8614X_INT1_EN_DIE_TEMP_MASK
+                                  | MAX8614X_INT1_EN_VDD_OOR_MASK},
+    };
+
+    if (enable) {
+        /* Read current sequence settings, and check what modes are open */
+        led_seq[0] = MAX8614X_LED_SEQ1_REG;
+        ret |= readRegister(MAX8614X_LED_SEQ1_REG, led_seq, 3);
+        if (ret < 0) {
+            pr_err("readRegister failed. ret: %d", ret);
+            return ret;
+        }
+
+        pr_debug("0-Sequence registers: %X %X %X", led_seq[0], led_seq[1], led_seq[2]);
+        ret |= writeBlock(ppg_init_cfg, ARRAY_SIZE(ppg_init_cfg));
+        led_seq[0] = MAX8614X_INT_STATUS1_REG;
+        ret |= readRegister(MAX8614X_INT_STATUS1_REG, led_seq, 3); // Mert: the len was 3 ?!
+        pr_debug("1-Sequence registers: %X %X %X", led_seq[0], led_seq[1], led_seq[2]);
+        if (ret < 0) {
+            pr_err("readRegister failed. ret: %d", ret);
+            return ret;
+        }
+        agc_enable(1);
+        pr_debug("Wrote register settings. ret: %d", ret);
+    } else {
+        ret = reset();
+        if (ret < 0) {
+            pr_err("reset failed. ret: %d", ret);
+            return ret;
+        }
+
+        ret = poweroff();
+        if (ret < 0) {
+            pr_err("poweroff failed. ret: %d", ret);
+            return ret;
+        }
+    }
+
+    return RTN_NO_ERROR;
+}
+
+int MAX8614X::agc_enable(int agc_enable)
+{
+    int ret = RTN_NO_ERROR;
+    led_ctrl.agc_is_enabled = !!agc_enable;
+    led_ctrl.lpm_is_enabled = !!agc_enable;
+    ret = led_prox_init(&led_ctrl, led_ctrl.lpm_is_enabled);
+    return ret;
+}
+
+int MAX8614X::dequeue_from_fifo_queue(uint32_t *ir, uint32_t *red, uint32_t *green)
+{
+    int ret;
+    ppg_data_t ppg_data;
+
+    ret = dequeue(&queue, &ppg_data);
+    if (ret < 0) {
+        return RTN_ERR_QUEUE_EMPTY;
+    }
+
+    pr_debug("%lu  %lu  %lu", ppg_data.ir, ppg_data.red, ppg_data.green);
+
+    *ir = ppg_data.ir;
+    *red = ppg_data.red;
+    *green = ppg_data.green;
+
+    return RTN_NO_ERROR;
+}
+
+int MAX8614X::dump_registers()
+{
+    int ret = 0;
+    uint8_t reg_addr;
+    uint8_t val;
+
+    for (reg_addr = 0x00; reg_addr <= 0x42; reg_addr++) {
+        ret |= readRegister(reg_addr, &val, 1);
+        printf("{%02X,%02X},", reg_addr, val);
+    }
+
+    for (reg_addr = 0xF0; reg_addr != 0x00; reg_addr++) {
+        ret |= readRegister(reg_addr, &val, 1);
+        printf("{%02X,%02X},", reg_addr, val);
+    }
+
+    return ret;
+}
+
+const char * MAX8614X::get_sensor_part_name()
+{
+    return "max86141";
+}
+
+const char * MAX8614X::get_sensor_name()
+{
+    return "ppg";
+}
--- a/MAX8614X.h	Thu Aug 16 19:53:01 2018 +0000
+++ b/MAX8614X.h	Fri Aug 17 05:35:58 2018 +0000
@@ -36,8 +36,8 @@
 #define _MAX8614X_H_
 
 #include "mbed.h"
-//#include "queue.h"
-//#include "MaximSensor.h"
+#include "queue.h"
+#include "MaximSensor.h"
 
 /**
 @brief The MAX8614X
@@ -46,7 +46,7 @@
 /**
 @brief MAX8614X - supports MAX8614X object with SPI interface
  */
-class MAX8614X
+class MAX8614X: public MaximSensor
 {
 public:
     /* PUBLIC CONST VARIABLES */
@@ -194,13 +194,153 @@
     static const uint8_t MAX8614X_MEMCNTRL_WR_EN_MASK     = (0x01 << 1);
     static const uint8_t MAX8614X_SHACMD_MAC_ROM_ID       = (0x35);
     static const uint8_t MAX8614X_SHACMD_MAC_NO_ROM_ID    = (0x36);
+
     /* PUBLIC TYPE DEFINITIONS */
     typedef struct RegisterMap {
         uint8_t addr;
         uint8_t val;
     } RegisterMap_t;
-   
-        typedef union {
+
+    /* PUBLIC FUNCTION DECLARATIONS */
+
+    MAX8614X(SPI &spiBus, DigitalOut &cs, PinName intPin);
+
+    int readRegister(uint8_t reg, uint8_t *data, int len);
+
+    int writeRegister(uint8_t reg, const uint8_t data);
+
+    int writeBlock(const RegisterMap reg_block[], unsigned int size);
+
+    int dequeue_from_fifo_queue(uint32_t *ir, uint32_t *red, uint32_t *green);
+
+    int get_part_info(uint8_t *part_id, uint8_t *rev_id);
+
+    int init();
+
+    const char *get_sensor_part_name();
+
+    const char *get_sensor_name();
+
+    int sensor_enable(int enable);
+
+    int agc_enable(int agc_enable);
+
+    int dump_registers();
+    bool isShaComplete(void);
+    void clearShaComplete(void);
+
+    /* PUBLIC VARIABLES */
+    InterruptIn m_ir;
+
+private:
+    /* PRIVATE CONST VARIABLES */
+    static const uint32_t MAX8614X_DATA_WORD_SIZE = 3;
+    static const uint32_t MAX8614X_MAX_FIFO_DEPTH = 128;
+    static const uint32_t MAX8614X_DATA_TYPE_MASK = (0x1F << 19);
+    static const uint32_t MAX8614X_DRIVER_FIFO_SZ = (MAX8614X_MAX_FIFO_DEPTH * 4);
+
+    /* PRIVATE TYPE DEFINITIONS  */
+    enum LedSequence
+    {
+        DATA_SEQ_NONE,
+        DATA_SEQ_LED1,
+        DATA_SEQ_LED2,
+        DATA_SEQ_LED3,
+        DATA_SEQ_LED1_LED2,
+        DATA_SEQ_LED1_LED3,
+        DATA_SEQ_LED2_LED3,
+        DATA_SEQ_LED1_LED2_LED3,
+        DATA_SEQ_PILOT_LED1,
+        DATA_SEQ_AMBIENT,
+        DATA_SEQ_LED4_EXT_MUX,
+        DATA_SEQ_LED5_EXT_MUX,
+        DATA_SEQ_LED6_EXT_MUX,
+    };
+
+    enum DataTypes
+    {
+        DATA_TYPE_PPG1_LEDC1 = 0x01,
+        DATA_TYPE_PPG1_LEDC2,
+        DATA_TYPE_PPG1_LEDC3,
+        DATA_TYPE_PPG1_LEDC4,
+        DATA_TYPE_PPG1_LEDC5,
+        DATA_TYPE_PPG1_LEDC6,
+        DATA_TYPE_PPG2_LEDC1,
+        DATA_TYPE_PPG2_LEDC2,
+        DATA_TYPE_PPG2_LEDC3,
+        DATA_TYPE_PPG2_LEDC4,
+        DATA_TYPE_PPG2_LEDC5,
+        DATA_TYPE_PPG2_LEDC6,
+        DATA_TYPE_PPF1_LEDC1,
+        DATA_TYPE_PPF1_LEDC2,
+        DATA_TYPE_PPF1_LEDC3,
+        DATA_TYPE_PPF2_LEDC1 = 0x13,
+        DATA_TYPE_PPF3_LEDC2,
+        DATA_TYPE_PPF3_LEDC3,
+        DATA_TYPE_PROX1 = 0x19,
+        DATA_TYPE_PROX2,
+        DATA_TYPE_INVALID_DATA = 0x1E,
+        DATA_TYPE_TIME_STAMP,
+    };
+
+    enum PartIDs
+    {
+        MAX86140_PART_ID_VAL = 0x24,
+        MAX86141_PART_ID_VAL,
+        MAX86142_PART_ID_VAL,
+        MAX86143_PART_ID_VAL,
+    };
+
+    enum LedRanges
+    {
+        LED_RANGE_0_50,
+        LED_RANGE_50_100,
+        LED_RANGE_100_150,
+        LED_RANGE_150_200,
+    };
+
+    enum LedRangeSteps
+    {
+        LED_RANGE_STEP_25uA = 120,
+        LED_RANGE_STEP_50uA = 240,
+        LED_RANGE_STEP_75uA = 360,
+        LED_RANGE_STEP_100uA = 480,
+    };
+
+    typedef enum {
+        LED_1 = 0,
+        LED_2,
+        LED_3,
+        LED_4,
+        LED_5,
+        LED_6,
+        NUM_OF_LED,
+    } max8614x_led_t;
+
+    enum LED_CTRL_SM {
+        LED_PROX = 1,
+        LED_DATA_ACQ,
+    };
+
+    typedef union {
+        struct {
+            uint32_t val:19;
+            uint32_t type:5;
+            uint32_t:8;
+        };
+        uint32_t raw;
+    } fifo_data_t;
+
+    typedef union {
+        uint16_t val;
+        struct {
+            uint8_t tint;
+            uint8_t frac:4;
+            uint8_t:4;
+        };
+    } die_temp_t;
+
+    typedef union {
         struct {
             struct {
                 unsigned char pwr_rdy:1;
@@ -220,32 +360,96 @@
         uint8_t val[2];
     } int_status_t;
 
-
-    /* PUBLIC FUNCTION DECLARATIONS */
+    union led_range {
+        struct {
+            uint8_t led1:2;
+            uint8_t led2:2;
+            uint8_t led3:2;
+            uint8_t:2;
+            uint8_t led4:2;
+            uint8_t led5:2;
+            uint8_t led6:2;
+            uint8_t:2;
+        };
+        uint8_t val[2];
+    };
 
-    MAX8614X(SPI &spiBus, DigitalOut &cs, PinName intPin);
-    ~MAX8614X();
-    int init();
-
-    int readRegister(uint8_t reg, uint8_t *data, int len);
+    typedef struct {
+        uint32_t green;
+        uint32_t ir;
+        uint32_t red;
+    } ppg_data_t;
 
-    int writeRegister(uint8_t reg, const uint8_t data);
-
-    int writeBlock(const RegisterMap reg_block[], unsigned int size);
-    void irq_handler(void);
-    bool isShaComplete(void);
-    void clearShaComplete(void);
-        /* PUBLIC VARIABLES */
-    InterruptIn m_ir;
-        
-private:
+    struct led_control {
+        uint32_t diode_sum[NUM_OF_LED];
+        uint32_t state;
+        uint32_t prox_sum;
+        uint32_t prox_sample_cnt;
+        int32_t led_current[NUM_OF_LED];
+        uint32_t default_current[NUM_OF_LED];
+        int32_t agc_led_out_percent;
+        int32_t agc_corr_coeff;
+        int32_t agc_min_num_samples;
+        int32_t agc_sensitivity_percent;
+        int32_t change_by_percent_of_range[NUM_OF_LED];
+        int32_t change_by_percent_of_current_setting[NUM_OF_LED];
+        int32_t change_led_by_absolute_count[NUM_OF_LED];
+        uint32_t sample_cnt;
+        union led_range led_range_settings;
+        uint8_t led_ranges;
+        uint8_t agc_is_enabled;
+        uint8_t lpm_is_enabled;
+    };
 
     /* PRIVATE VARIABLES */
-    SPI &m_spiBus;
-    DigitalOut &m_cs;
+    SPI m_spiBus;
+    DigitalOut m_cs;
+    struct queue_t queue;
+    struct led_control led_ctrl;
+    int vdd_oor_cnt;
+    die_temp_t die_temp;
     bool shaComplete;
 
     /* PRIVATE FUNCTION DECLARATIONS */
+    int reset();
+
+    int poweroff();
+
+    void irq_handler();
+
+    int enable_die_temp();
+
+    int read_die_temp();
+
+    int get_num_samples_in_fifo();
+
+    void fifo_irq_handler();
+
+    int read_fifo_data(uint8_t *fifo_data, int num_samples);
+
+    /* AGC functions */
+    int max8614x_update_led_range(int new_range, uint8_t led_num,
+            union led_range *led_range_settings);
+
+    int max8614x_update_led_current(union led_range *led_range_settings,
+            int led_new_val, max8614x_led_t led_num);
+
+    void ppg_auto_gain_ctrl(struct led_control *led_ctrl,
+            uint32_t sample_cnt, int diode_data, max8614x_led_t led_num);
+
+    void max8614x_agc_handler(struct led_control *led_ctrl,
+            int *samples);
+
+    int led_control_sm(struct led_control *led_ctrl,
+            int diode_data, char lpm);
+
+    void led_control_reset(struct led_control *led_ctrl);
+
+    int led_prox_init(struct led_control *led_ctrl, char lpm);
+
+    int led_daq_init(struct led_control *led_ctrl, char lpm);
+
+    void led_control_init(struct led_control *led_ctrl);
 };
 
 #endif /* _MAX8614X_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX8614X_agc.cpp	Fri Aug 17 05:35:58 2018 +0000
@@ -0,0 +1,509 @@
+/*******************************************************************************
+* Author: Ismail Kose, Ismail.Kose@maximintegrated.com
+* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* 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 MAXIM INTEGRATED 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.
+*
+* Except as contained in this notice, the name of Maxim Integrated
+* Products, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+*******************************************************************************
+*/
+
+#include "MAX8614X.h"
+#include <errno.h>
+
+#define pr_err(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+#define pr_info(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+#define pr_debug(fmt, args...) if(0) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+
+#define ARRAY_SIZE(array)			(sizeof(array)/sizeof(array[0]))
+
+#define ILLEGAL_OUTPUT_POINTER				1
+#define ILLEGAL_DIODE_OUTPUT_MIN_MAX_PAIR	2
+#define ILLEGAL_LED_SETTING_MIN_MAX_PAIR	3
+#define CONSTRAINT_VIOLATION				4
+
+#define MAX8614X_LED_DRIVE_CURRENT_FULL_SCALE		\
+		(MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT)
+
+#define MAX8614X_AGC_DEFAULT_LED_OUT_RANGE			15
+#define MAX8614X_AGC_DEFAULT_CORRECTION_COEFF		50
+#define MAX8614X_AGC_DEFAULT_SENSITIVITY_PERCENT	10
+#define MAX8614X_AGC_DEFAULT_NUM_SAMPLES_TO_AVG		25
+
+#define MAX8614X_PROX_THRESHOLD_1			10000
+#define MAX8614X_PROX_THRESHOLD_2			40000
+#define MAX8614X_PROX_DEBOUNCE_SPS			2
+#define MAX8614X_DAQ_DEBOUNCE_SPS			20
+
+#define MAX8614X_DEFAULT_DAQ_LED_CURRENT_1	40000
+#define MAX8614X_DEFAULT_DAQ_LED_CURRENT_2	40000
+#define MAX8614X_DEFAULT_DAQ_LED_CURRENT_3	40000
+#define MAX8614X_DEFAULT_PROX_LED_CURRENT_1	10000
+#define MAX8614X_DEFAULT_PROX_LED_CURRENT_2	0
+#define MAX8614X_DEFAULT_PROX_LED_CURRENT_3	0
+
+
+#define MAX8614X_MIN_LED_DRIVE_CURRENT		0
+#define MAX8614X_MAX_LED_DRIVE_CURRENT		60000
+
+#define MAX8614X_MAX_PPG_DIODE_VAL			((1 << 19) - 1)
+#define MAX8614X_MIN_PPG_DIODE_VAL			0
+
+#define MAX8614X_DEFAULT_CURRENT1			0x30
+#define MAX8614X_DEFAULT_CURRENT2			0
+#define MAX8614X_DEFAULT_CURRENT3			0
+
+
+int MAX8614X::max8614x_update_led_range(
+		int new_range, uint8_t led_num,
+		union led_range *led_range_settings)
+{
+	int old_range;
+	Registers reg_addr;
+
+	switch (led_num) {
+	case LED_1:
+		old_range = led_range_settings->led1;
+		led_range_settings->led1 = new_range;
+		reg_addr = MAX8614X_LED_RANGE1_REG;
+		break;
+	case LED_2:
+		old_range = led_range_settings->led2;
+		led_range_settings->led2 = new_range;
+		reg_addr = MAX8614X_LED_RANGE1_REG;
+		break;
+	case LED_3:
+		old_range = led_range_settings->led3;
+		led_range_settings->led3 = new_range;
+		reg_addr = MAX8614X_LED_RANGE1_REG;
+		break;
+	case LED_4:
+		old_range = led_range_settings->led4;
+		led_range_settings->led4 = new_range;
+		reg_addr = MAX8614X_LED_RANGE2_REG;
+		break;
+	case LED_5:
+		old_range = led_range_settings->led5;
+		led_range_settings->led5 = new_range;
+		reg_addr = MAX8614X_LED_RANGE2_REG;
+		break;
+	case LED_6:
+		old_range = led_range_settings->led6;
+		led_range_settings->led6 = new_range;
+		reg_addr = MAX8614X_LED_RANGE2_REG;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (old_range == new_range)
+		return 0;
+
+	return writeRegister( reg_addr,
+			led_range_settings->val[led_num < LED_4 ? 0 : 1]);
+}
+
+int MAX8614X::max8614x_update_led_current(
+		union led_range *led_range_settings,
+		int led_new_val,
+		max8614x_led_t led_num)
+{
+	int ret = 0;
+	Registers led_current_reg_addr;
+	int led_range;
+	uint8_t led_current_reg_val;
+	int	led_range_index = led_new_val / 25000;
+	const int led_range_steps[] = {
+		LED_RANGE_STEP_25uA,
+		LED_RANGE_STEP_50uA,
+		LED_RANGE_STEP_75uA,
+		LED_RANGE_STEP_100uA,
+		LED_RANGE_STEP_100uA, /* For led current greater than 100uA */
+	};
+
+	switch(led_num) {
+	case LED_1:
+		led_current_reg_addr = MAX8614X_LED1_PA_REG;
+		break;
+	case LED_2:
+		led_current_reg_addr = MAX8614X_LED2_PA_REG;
+		break;
+	case LED_3:
+		led_current_reg_addr = MAX8614X_LED3_PA_REG;
+		break;
+	case LED_4:
+		led_current_reg_addr = MAX8614X_LED4_PA_REG;
+		break;
+	case LED_5:
+		led_current_reg_addr = MAX8614X_LED5_PA_REG;
+		break;
+	case LED_6:
+		led_current_reg_addr = MAX8614X_LED6_PA_REG;
+		break;
+	default:
+		pr_err("Invalid led number: %d\n", led_num);
+		return -EINVAL;
+	}
+
+	if (led_new_val < MAX8614X_MIN_LED_DRIVE_CURRENT
+				|| led_new_val > MAX8614X_MAX_LED_DRIVE_CURRENT) {
+		pr_err("Invalid led value: %d\n", led_new_val);
+		return -EINVAL;
+	}
+
+	led_current_reg_val = led_new_val / led_range_steps[led_range_index];
+
+	pr_debug("Updating LED%d current to %d. led_rge_idx: %d, reg_val: %.2X",
+			led_num, led_new_val, led_range_index, led_current_reg_val);
+
+	ret = writeRegister(led_current_reg_addr, led_current_reg_val);
+	if (ret < 0)
+		return ret;
+
+
+	led_range = led_range_index;
+	pr_debug("Updating LED%d range to %d.", led_num, led_range);
+	if (led_range > 3)
+		led_range = 3;
+	ret = max8614x_update_led_range( led_range, led_num, led_range_settings);
+	if (ret < 0)
+		return ret;
+	return ret;
+}
+
+int32_t agc_adj_calculator(
+		int32_t *change_by_percent_of_range,
+		int32_t *change_by_percent_of_current_setting,
+		int32_t *change_led_by_absolute_count,
+		int32_t *set_led_to_absolute_count,
+		int32_t target_percent_of_range,
+		int32_t correction_coefficient,
+		int32_t allowed_error_in_percentage,
+		int32_t current_average,
+		int32_t number_of_samples_averaged,
+		int32_t led_drive_current_value)
+{
+	int32_t current_percent_of_range = 0;
+	int32_t delta = 0;
+	int32_t desired_delta = 0;
+	int32_t current_power_percent = 0;
+
+	if (change_by_percent_of_range == 0
+			|| change_by_percent_of_current_setting == 0
+			|| change_led_by_absolute_count == 0
+			|| set_led_to_absolute_count == 0)
+		return ILLEGAL_OUTPUT_POINTER;
+
+	if (target_percent_of_range > 90 || target_percent_of_range < 10)
+		return CONSTRAINT_VIOLATION;
+
+	if (correction_coefficient > 100 || correction_coefficient < 0)
+		return CONSTRAINT_VIOLATION;
+
+	if (allowed_error_in_percentage > 100
+			|| allowed_error_in_percentage < 0)
+		return CONSTRAINT_VIOLATION;
+
+#if ((MAX8614X_MAX_PPG_DIODE_VAL - MAX8614X_MIN_PPG_DIODE_VAL) <= 0 \
+			 || (MAX8614X_MAX_PPG_DIODE_VAL < 0) || (MAX8614X_MIN_PPG_DIODE_VAL < 0))
+	#error "Illegal diode Min/Max Pair"
+#endif
+
+#if ((MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT) <= 0 \
+		|| (MAX8614X_MAX_LED_DRIVE_CURRENT < 0) || (MAX8614X_MIN_LED_DRIVE_CURRENT < 0))
+	#error "Illegal LED Min/Max current Pair"
+#endif
+
+	if (led_drive_current_value > MAX8614X_MAX_LED_DRIVE_CURRENT
+			|| led_drive_current_value < MAX8614X_MIN_LED_DRIVE_CURRENT)
+		return CONSTRAINT_VIOLATION;
+
+	if (current_average < MAX8614X_MIN_PPG_DIODE_VAL
+			|| current_average > MAX8614X_MAX_PPG_DIODE_VAL)
+		return CONSTRAINT_VIOLATION;
+
+	current_percent_of_range = 100 *
+		(current_average - MAX8614X_MIN_PPG_DIODE_VAL) /
+		(MAX8614X_MAX_PPG_DIODE_VAL - MAX8614X_MIN_PPG_DIODE_VAL) ;
+
+	delta = current_percent_of_range - target_percent_of_range;
+	delta = delta * correction_coefficient / 100;
+
+	if (delta > -allowed_error_in_percentage
+			&& delta < allowed_error_in_percentage) {
+		*change_by_percent_of_range = 0;
+		*change_by_percent_of_current_setting = 0;
+		*change_led_by_absolute_count = 0;
+		*set_led_to_absolute_count = led_drive_current_value;
+		return 0;
+	}
+
+	current_power_percent = 100 *
+			(led_drive_current_value - MAX8614X_MIN_LED_DRIVE_CURRENT) /
+			(MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT);
+	if (delta < 0)
+		desired_delta = -delta * (100 - current_power_percent) /
+				(100 - current_percent_of_range);
+
+	if (delta > 0)
+		desired_delta = -delta * (current_power_percent)
+				/ (current_percent_of_range);
+
+	*change_by_percent_of_range = desired_delta;
+
+	*change_led_by_absolute_count =	(desired_delta
+			* MAX8614X_LED_DRIVE_CURRENT_FULL_SCALE / 100);
+	*change_by_percent_of_current_setting =
+			(*change_led_by_absolute_count * 100)
+			/ (led_drive_current_value);
+	*set_led_to_absolute_count  = led_drive_current_value
+			+ *change_led_by_absolute_count;
+
+	//If we are saturated, cut power in half
+	if (current_percent_of_range >= 100)
+	{
+		*change_by_percent_of_range = -100; //Unknown, set fake value
+		*change_by_percent_of_current_setting = -50;
+		*change_led_by_absolute_count = 0 - (led_drive_current_value / 2);
+		*set_led_to_absolute_count  = led_drive_current_value / 2;
+	}
+
+	return 0;
+}
+
+void MAX8614X::ppg_auto_gain_ctrl(
+		struct led_control *led_ctrl,
+		uint32_t sample_cnt, int diode_data, max8614x_led_t led_num)
+{
+	int ret;
+	int diode_avg;
+
+	if (led_num > LED_3) /* TODO: why3? */
+		return;
+
+	led_ctrl->diode_sum[led_num] += diode_data;
+	if (sample_cnt % led_ctrl->agc_min_num_samples == 0) {
+		diode_avg = led_ctrl->diode_sum[led_num]
+				/ led_ctrl->agc_min_num_samples;
+		led_ctrl->diode_sum[led_num] = 0;
+	} else
+		return;
+
+	ret = agc_adj_calculator(
+		&led_ctrl->change_by_percent_of_range[led_num],
+		&led_ctrl->change_by_percent_of_current_setting[led_num],
+		&led_ctrl->change_led_by_absolute_count[led_num],
+		&led_ctrl->led_current[led_num],
+		led_ctrl->agc_led_out_percent,
+		led_ctrl->agc_corr_coeff,
+		led_ctrl->agc_sensitivity_percent,
+		diode_avg,
+		led_ctrl->agc_min_num_samples,
+		led_ctrl->led_current[led_num]);
+	if (ret)
+		return;
+
+	if (led_ctrl->change_led_by_absolute_count[led_num] == 0)
+		return;
+
+	ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
+			led_ctrl->led_current[led_num], led_num);
+	if (ret < 0)
+		pr_err("%s failed", __func__);
+	return;
+}
+
+void MAX8614X::max8614x_agc_handler(struct led_control *led_ctrl,
+		int *samples)
+{
+	static int ret = -1;
+
+	if (!led_ctrl->agc_is_enabled)
+		return;
+
+	led_ctrl->sample_cnt++;
+	ret = led_control_sm(led_ctrl,
+		samples[DATA_TYPE_PPG1_LEDC1],
+		led_ctrl->lpm_is_enabled);
+
+	if (ret == LED_DATA_ACQ) {
+		ppg_auto_gain_ctrl(led_ctrl,
+				led_ctrl->sample_cnt,
+				samples[DATA_TYPE_PPG1_LEDC1],
+				LED_1);
+		ppg_auto_gain_ctrl(led_ctrl,
+				led_ctrl->sample_cnt,
+				samples[DATA_TYPE_PPG1_LEDC2],
+				LED_2);
+		ppg_auto_gain_ctrl(led_ctrl,
+				led_ctrl->sample_cnt,
+				samples[DATA_TYPE_PPG1_LEDC3],
+				LED_3);
+	}
+
+	return;
+}
+
+int MAX8614X::led_prox_init(struct led_control *led_ctrl, char lpm)
+{
+	int ret;
+	const RegisterMap low_pm_settings[] = {
+		{ MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us)
+							   | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA)
+							   | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA)
+		{ MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_25_SPS},
+		{ MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_DATA_RDY_MASK },
+	};
+
+	led_ctrl->led_current[LED_1] = MAX8614X_DEFAULT_PROX_LED_CURRENT_1;
+	ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
+			led_ctrl->led_current[LED_1], LED_1);
+
+	led_ctrl->led_current[LED_2] = MAX8614X_DEFAULT_PROX_LED_CURRENT_2;
+	ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
+			led_ctrl->led_current[LED_2], LED_2);
+
+	led_ctrl->led_current[LED_3] = MAX8614X_DEFAULT_PROX_LED_CURRENT_3;
+	ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
+			led_ctrl->led_current[LED_3], LED_3);
+
+	if (lpm)
+		ret |= writeBlock(low_pm_settings,
+				ARRAY_SIZE(low_pm_settings));
+	return ret;
+}
+
+int MAX8614X::led_daq_init(struct led_control *led_ctrl, char lpm)
+{
+	int ret;
+	const RegisterMap non_lpm_settings[] = {
+		{ MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us)
+							   | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA)
+							   | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA)
+		{ MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_100_SPS},
+		{ MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_A_FULL_MASK },
+	};
+
+	led_ctrl->led_current[LED_1] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_1;
+	ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
+			led_ctrl->led_current[LED_1], LED_1);
+
+	led_ctrl->led_current[LED_2] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_2;
+	ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
+			led_ctrl->led_current[LED_2], LED_2);
+
+	led_ctrl->led_current[LED_3] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_3;
+	ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
+			led_ctrl->led_current[LED_3], LED_3);
+
+	if (lpm)
+		ret |= writeBlock(non_lpm_settings,
+				ARRAY_SIZE(non_lpm_settings));
+
+	return ret;
+}
+
+int MAX8614X::led_control_sm(struct led_control *led_ctrl, int diode_data, char lpm)
+{
+	int ret = led_ctrl->state;
+	int avg = 0;
+
+	led_ctrl->prox_sample_cnt++;
+	led_ctrl->prox_sum += diode_data;
+
+	switch (led_ctrl->state) {
+	case LED_PROX:
+		if (led_ctrl->prox_sample_cnt % MAX8614X_PROX_DEBOUNCE_SPS != 0)
+			break;
+
+		avg = led_ctrl->prox_sum / MAX8614X_PROX_DEBOUNCE_SPS;
+		if (avg >= MAX8614X_PROX_THRESHOLD_1) {
+			led_ctrl->state = LED_DATA_ACQ;
+			ret = led_daq_init(led_ctrl, lpm);
+			led_ctrl->prox_sample_cnt = 0;
+		}
+		led_ctrl->prox_sum = 0;
+		break;
+
+	case LED_DATA_ACQ:
+		if (led_ctrl->prox_sample_cnt % MAX8614X_DAQ_DEBOUNCE_SPS != 0)
+			break;
+
+		avg = led_ctrl->prox_sum / MAX8614X_DAQ_DEBOUNCE_SPS;
+		if (avg <= MAX8614X_PROX_THRESHOLD_2) {
+			led_ctrl->state = LED_PROX;
+			ret = led_prox_init(led_ctrl, lpm);
+			led_ctrl->prox_sample_cnt = 0;
+		}
+		led_ctrl->prox_sum = 0;
+		break;
+
+	default:
+		led_ctrl->state = LED_PROX;
+		led_ctrl->prox_sum = 0;
+		led_ctrl->prox_sample_cnt = 0;
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+void MAX8614X::led_control_reset(struct led_control *led_ctrl)
+{
+	led_ctrl->led_current[LED_1] = led_ctrl->default_current[LED_1];
+	led_ctrl->led_current[LED_2] = led_ctrl->default_current[LED_2];
+	led_ctrl->led_current[LED_3] = led_ctrl->default_current[LED_3];
+
+	memset(led_ctrl->change_by_percent_of_range, 0,
+			sizeof(led_ctrl->change_by_percent_of_range));
+	memset(led_ctrl->change_by_percent_of_current_setting, 0,
+			sizeof(led_ctrl->change_by_percent_of_range));
+	memset(led_ctrl->change_led_by_absolute_count, 0,
+			sizeof(led_ctrl->change_by_percent_of_range));
+	memset(led_ctrl->diode_sum, 0, sizeof(led_ctrl->diode_sum));
+
+	led_ctrl->agc_is_enabled = 1;
+	led_ctrl->prox_sum = 0;
+	led_ctrl->prox_sample_cnt = 0;
+	led_ctrl->sample_cnt = -1;
+	led_ctrl->state = LED_PROX;
+}
+
+void MAX8614X::led_control_init(struct led_control *led_ctrl)
+{
+	memset(led_ctrl, 0, sizeof(struct led_control));
+
+	led_ctrl->default_current[LED_1] = MAX8614X_DEFAULT_CURRENT1;
+	led_ctrl->default_current[LED_2] = MAX8614X_DEFAULT_CURRENT2;
+	led_ctrl->default_current[LED_3] = MAX8614X_DEFAULT_CURRENT3;
+	led_ctrl->agc_led_out_percent = MAX8614X_AGC_DEFAULT_LED_OUT_RANGE;
+	led_ctrl->agc_corr_coeff = MAX8614X_AGC_DEFAULT_CORRECTION_COEFF;
+	led_ctrl->agc_min_num_samples = MAX8614X_AGC_DEFAULT_NUM_SAMPLES_TO_AVG;
+	led_ctrl->agc_sensitivity_percent = MAX8614X_AGC_DEFAULT_SENSITIVITY_PERCENT;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MaximSensor/MaximSensor.cpp	Fri Aug 17 05:35:58 2018 +0000
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * 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 MAXIM INTEGRATED 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.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *******************************************************************************
+ */
+
+#include "mbed.h"
+#include "MaximSensor.h"
+#include <string.h>
+
+#define pr_err(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+#define pr_debug(fmt, args...) if(0) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+#define pr_info(fmt, args...) if(0) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
+
+int MaximSensor::agc_enable(int agc_enable)
+{
+	pr_err("function %s is not implemented", __func__);
+
+	return 0;
+}
+
+int MaximSensor::dump_registers()
+{
+	int ret = 0;
+	uint8_t reg_addr = 0;
+	uint8_t val;
+
+	do {
+		ret |= readRegister(reg_addr, &val, 1);
+		printf("{%02X,%02X},", reg_addr, val);
+		reg_addr++;
+	} while (reg_addr > 0x00);
+
+	return ret;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MaximSensor/MaximSensor.h	Fri Aug 17 05:35:58 2018 +0000
@@ -0,0 +1,56 @@
+/*******************************************************************************
+* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* 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 MAXIM INTEGRATED 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.
+*
+* Except as contained in this notice, the name of Maxim Integrated
+* Products, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+*******************************************************************************
+*/
+#ifndef _MAXIMSENSOR_H_
+#define _MAXIMSENSOR_H_
+
+class MaximSensor
+{
+public:
+	virtual int readRegister(uint8_t reg, uint8_t *data, int len) = 0;
+	virtual int writeRegister(uint8_t reg,	const uint8_t data) = 0;
+	virtual int get_part_info(uint8_t *part_id,	uint8_t *rev_id)= 0;
+
+	virtual int sensor_enable(int enable) = 0;
+	virtual int agc_enable(int agc_enable);
+
+	virtual const char *get_sensor_part_name() = 0;
+	virtual const char *get_sensor_name()= 0;
+
+	virtual int dump_registers();
+
+private:
+
+};
+
+#endif /* _MAXIMSENSOR_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MaximSensor/queue.cpp	Fri Aug 17 05:35:58 2018 +0000
@@ -0,0 +1,149 @@
+/*******************************************************************************
+* Author: Ismail Kose, Ismail.Kose@maximintegrated.com
+* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* 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 MAXIM INTEGRATED 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.
+*
+* Except as contained in this notice, the name of Maxim Integrated
+* Products, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+*******************************************************************************
+*/
+
+/*
+ * TODO:
+ * Add a function to enqueue data block instead of one by one.
+ * Write function definitions in the header file as doxygen format
+ * Init function will also allocate memory for queue buffer, providing the buffer will not necessary
+ *
+ * */
+
+#define enter_critical_section()
+#define exit_critical_section()
+
+#include "queue.h"
+int queue_reset(struct queue_t *q)
+{
+	if (!q)
+		return -1;
+
+	q->wr = q->base;
+	q->rd = q->base;
+	q->num_item = 0;
+	q->ovf_item = 0;
+
+	return 0;
+}
+
+int queue_init(struct queue_t *q, void *buf, int item_size, int buffer_size)
+{
+	if (!q || !buf)
+		return -1;
+
+	if (buffer_size % item_size != 0)
+		return -1; // Padding problem
+
+	q->num_item = 0;
+	q->base = buf;
+	q->wr = buf;
+	q->rd = buf;
+	q->item_size = item_size;
+	q->buffer_size = buffer_size;
+
+	return 0;
+}
+
+void queue_destroy(struct queue_t *q)
+{
+/* TODO: This is placeholder function, double check the implementation */
+	free((void *)q->base);
+	free((void *)q);
+}
+
+int enqueue(struct queue_t *q, void *data)
+{
+	int ret = 0;
+
+	if (!q || !data)
+		return -1; // Invalid pointer
+
+	enter_critical_section();
+	if (q->wr == q->rd)
+		ret = (q->num_item != 0) ? -2 : 0; // Is FIFO Full or Empty?
+
+	if (((uint32_t)q->wr) >= ((uint32_t)q->base + q->buffer_size))
+		q->wr = q->base;
+
+	memcpy((void *)q->wr, data, q->item_size);
+	q->wr = (void *)((uint32_t)q->wr + q->item_size);
+	q->num_item++;
+	exit_critical_section();
+	return ret;
+}
+
+int dequeue(struct queue_t *q, void *data)
+{
+	int fifo_size;
+
+	if (!q || !data)
+		return -1;
+
+	fifo_size = q->buffer_size / q->item_size;
+
+	enter_critical_section();
+	if (q->num_item <= 0) {
+		exit_critical_section();
+		return -2;
+	}
+
+	if (q->num_item > fifo_size) {
+		uint32_t curr_rd_off = (((uint32_t)q->rd - (uint32_t)q->base) + q->num_item * q->item_size);
+		q->ovf_item = q->num_item - fifo_size;
+		q->rd = (void *)((uint32_t)q->base + (curr_rd_off % q->buffer_size));
+		q->num_item = fifo_size; // OVF number samples are already gone.
+		printf("%s:%d - %d samples lost\n", __func__, __LINE__, q->ovf_item);
+	} else
+		q->ovf_item = 0;
+
+	if (((uint32_t)q->rd) >= ((uint32_t)q->base + q->buffer_size))
+		q->rd = q->base;
+
+	memcpy(data, (void *)q->rd, q->item_size);
+	q->rd = (void *)((uint32_t)q->rd + q->item_size);
+	q->num_item--;
+	exit_critical_section();
+
+#if defined(QUEUE_DEBUG)
+	do {
+		static int cnt;
+
+		if (cnt++ % 100 == 0)
+			printf("$ Fifo size: %d, usage: %d\n", fifo_size, q->num_item);
+	} while(0);
+#endif
+
+	return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MaximSensor/queue.h	Fri Aug 17 05:35:58 2018 +0000
@@ -0,0 +1,110 @@
+/*******************************************************************************
+* Author: Ismail Kose, Ismail.Kose@maximintegrated.com
+* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* 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 MAXIM INTEGRATED 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.
+*
+* Except as contained in this notice, the name of Maxim Integrated
+* Products, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+*******************************************************************************
+*/
+
+#ifndef _QUEUE_H_
+#define _QUEUE_H_
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct queue_t {
+	void *wr; // write pointer
+	void *rd; // read pointer
+	void *base; // buffer base pointer
+	int num_item; // number of data item
+	int ovf_item; // Number of overflowed data
+	int buffer_size; // buffer size in bytes
+	int item_size; // data size
+};
+
+/**
+ * @brief Queue initialization.
+ * @param[in]       *q Points to the queue handle
+ * @param[in]       *buf Points to external queue buffer
+ * @param[in]       item_size Data size
+ * @param[in]       buffer_size Total buffer size in bytes
+ * @param[out]      *pDst points to output matrix structure
+ * @return     The function returns 0: success
+ *								-1: Invalid Pointer
+ *								-2: Queue buffer is full, no more space
+ **/
+int queue_init(struct queue_t *q, void *buf, int item_size, int buffer_size);
+
+
+
+
+/**
+ * @brief Data reset.
+ * @param[in]       *q Points to the queue handle
+ * @param[in]       *data Points to any type of data to put FIFO
+ * @param[out]      *pDst Points to output matrix structure
+ * @return     The function returns 0: success
+ *								-1: Invalid Pointer
+ *								-2: Queue buffer is full, no more space
+ **/
+int queue_reset(struct queue_t *q);
+
+
+/**
+ * @brief Data enqueue.
+ * @param[in]       *q points to the queue handle
+ * @param[in]       *data points to any type of data to put FIFO
+ * @return     The function returns 0: success
+ *								-1: Invalid Pointer
+ *								-2: Queue buffer is full, no more space
+ **/
+int enqueue(struct queue_t *q, void *data);
+
+
+/**
+ * @brief Data dequeue.
+ * @param[in]       *q points to the queue handle
+ * @param[in]       *data points to any type of data to put FIFO
+ * @param[out]      *data pop data from Queue
+ * @return     The function returns 0: success
+ *								-1: Invalid Pointer
+ *								-2: Queue buffer is empty
+ **/
+int dequeue(struct queue_t *q, void *data);
+
+
+
+/**
+ * @brief Queue Destroy
+ * @param[in]       *q points to the queue handle
+ **/
+void queue_destroy(struct queue_t *q);
+#endif //_QUEUE_H_
+