Revision:
5:1f7b8cb07e26
Parent:
4:6ec3bc44f055
Child:
6:ec1c447e825c
--- 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";
+}