initial commit, reads dev id

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MAX8614X.cpp Source File

MAX8614X.cpp

00001 /*******************************************************************************
00002 * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
00003 *
00004 * Permission is hereby granted, free of charge, to any person obtaining a
00005 * copy of this software and associated documentation files (the "Software"),
00006 * to deal in the Software without restriction, including without limitation
00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008 * and/or sell copies of the Software, and to permit persons to whom the
00009 * Software is furnished to do so, subject to the following conditions:
00010 *
00011 * The above copyright notice and this permission notice shall be included
00012 * in all copies or substantial portions of the Software.
00013 *
00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020 * OTHER DEALINGS IN THE SOFTWARE.
00021 *
00022 * Except as contained in this notice, the name of Maxim Integrated
00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated
00024 * Products, Inc. Branding Policy.
00025 *
00026 * The mere transfer of this software does not imply any licenses
00027 * of trade secrets, proprietary technology, copyrights, patents,
00028 * trademarks, maskwork rights, or any other form of intellectual
00029 * property whatsoever. Maxim Integrated Products, Inc. retains all
00030 * ownership rights.
00031 *******************************************************************************
00032 */
00033 #include "MAX8614X.h"
00034 
00035 #define pr_err(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
00036 #define pr_info(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
00037 #define pr_debug(fmt, args...) if(0) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
00038 
00039 #define ARRAY_SIZE(array)           (sizeof(array)/sizeof(array[0]))
00040 
00041 MAX8614X::MAX8614X(SPI &spiBus, DigitalOut &cs, PinName pin)
00042 :m_ir(pin), m_spiBus(spiBus), m_cs(cs)
00043 {
00044     m_cs = 1;
00045 }
00046 
00047 int MAX8614X::readRegister(uint8_t reg, uint8_t *data, int len)
00048 {
00049     m_cs = 0;
00050 
00051     m_spiBus.write(reg);
00052     m_spiBus.write(0x80);
00053 
00054     int i = 0;
00055     for(; i < len; i++) { /*TODO: make len unsigned*/
00056         data[i] = m_spiBus.write(0x00);
00057     }
00058 
00059     m_cs = 1;
00060     return 0; /*TODO: handle error cases*/
00061 }
00062 
00063 int MAX8614X::writeRegister(uint8_t reg, const uint8_t data)
00064 {
00065     m_cs = 0;
00066 
00067     m_spiBus.write(reg);
00068     m_spiBus.write(0x00);
00069     m_spiBus.write(data);
00070 
00071     m_cs = 1;
00072 
00073     return 0; /*TODO: handle error cases*/
00074 }
00075 
00076 int MAX8614X::writeBlock(const RegisterMap reg_block[], unsigned int size)
00077 {
00078     unsigned int i;
00079     int ret = 0;
00080 
00081     for (i = 0; i < size; i++) {
00082         ret = writeRegister((Registers) reg_block[i].addr,
00083                 reg_block[i].val);
00084         if (ret < 0) {
00085             pr_err("writeRegister failed. ret: %d", ret);
00086             return ret;
00087         }
00088     }
00089 
00090     return ret;
00091 }
00092 
00093 int MAX8614X::get_part_info(uint8_t *part_id, uint8_t *rev_id)
00094 {
00095     uint32_t i;
00096     int ret;
00097     uint8_t buf[2];
00098     const uint8_t max8614x_part_ids[] = {
00099         MAX86140_PART_ID_VAL,
00100         MAX86141_PART_ID_VAL,
00101         MAX86142_PART_ID_VAL,
00102         MAX86143_PART_ID_VAL,
00103     };
00104 
00105     ret = readRegister(MAX8614X_REV_ID_REG, buf, 2);
00106     if (ret < 0) {
00107         pr_err("readRegister failed. ret: %d", ret);
00108         return ret;
00109     }
00110 
00111     for (i = 0; i < ARRAY_SIZE(max8614x_part_ids); i++) {
00112         if (buf[1] == max8614x_part_ids[i]) {
00113             *rev_id = buf[0];
00114             *part_id = buf[1];
00115             return 0;
00116         }
00117     }
00118 
00119     // Unsupported part
00120     return -1;
00121 }
00122 
00123 int MAX8614X::get_num_samples_in_fifo()
00124 {
00125     int fifo_ovf_cnt;
00126     uint8_t fifo_data[4];
00127     uint32_t num_samples;
00128     int ret;
00129 
00130     ret = readRegister(MAX8614X_OVF_CNT_REG, fifo_data, 2);
00131     if (ret < 0) {
00132         pr_err("readRegister failed. ret: %d", ret);
00133         return ret;
00134     }
00135 
00136     fifo_ovf_cnt = fifo_data[0] & MAX8614X_OVF_CNT_MASK;
00137     num_samples = fifo_data[1];
00138 
00139     if (num_samples >= MAX8614X_MAX_FIFO_DEPTH) {
00140         pr_err("# FIFO is Full. OVF: %d num_samples: %lu",
00141                 fifo_ovf_cnt, num_samples);
00142     }
00143 
00144     return num_samples;
00145 }
00146 
00147 int MAX8614X::read_fifo_data(uint8_t *fifo_data, int num_samples)
00148 {
00149     uint16_t num_bytes = num_samples * MAX8614X_DATA_WORD_SIZE;
00150     int ret = 0;
00151 
00152     fifo_data[0] = MAX8614X_FIFO_DATA_REG;
00153     ret = readRegister(MAX8614X_FIFO_DATA_REG, fifo_data, num_bytes);
00154     if (ret < 0) {
00155         pr_err("readRegister failed. ret: %d", ret);
00156         return ret;
00157     }
00158 
00159     return ret;
00160 }
00161 
00162 void MAX8614X::fifo_irq_handler()
00163 {
00164     uint8_t fifo_buf[MAX8614X_MAX_FIFO_DEPTH * MAX8614X_DATA_WORD_SIZE] = {0};
00165     int ret;
00166     int num_samples = 0;
00167     static int last_samples[DATA_TYPE_PPG2_LEDC4];
00168     fifo_data_t fifo_data;
00169     uint16_t idx;
00170     int i;
00171     static ppg_data_t ppg_data;
00172     static uint32_t ppg_data_ack = 0;
00173     const uint32_t ir_green_red_ppg_type = ((1 << DATA_TYPE_PPG1_LEDC1) |
00174                                             (1 << DATA_TYPE_PPG1_LEDC2) |
00175                                             (1 << DATA_TYPE_PPG1_LEDC3));
00176 
00177     num_samples = get_num_samples_in_fifo();
00178     if (num_samples <= 0) {
00179         pr_debug("get_num_samples_in_fifo failed. err: %d", num_samples);
00180         return;
00181     }
00182 
00183     ret = read_fifo_data(fifo_buf, num_samples);
00184     if (ret < 0) {
00185         pr_debug("read_fifo_data failed. ret: %d", ret);
00186         return;
00187     }
00188 
00189     for (i = 0; i < num_samples; i++) {
00190         idx = MAX8614X_DATA_WORD_SIZE * i;
00191         fifo_data.raw = fifo_buf[idx + 0] << 16
00192                 | fifo_buf[idx + 1] << 8
00193                 | fifo_buf[idx + 2];
00194         if (fifo_data.type == DATA_TYPE_INVALID_DATA || fifo_data.type == 0) {
00195             pr_err("Received invalid data. data: %X, i: %d",
00196                     (unsigned int)fifo_data.raw, i);
00197 
00198             continue;
00199         }
00200         pr_debug("\ttype: %lu, val: %lu (%lX)",
00201                 fifo_data.type, fifo_data.val, fifo_data.val);
00202 
00203         if (fifo_data.type > DATA_TYPE_PPG2_LEDC3) {
00204             pr_err("Wrong Data Type: -> Type: %lu, val:%lu, Raw:%lu",
00205                     fifo_data.type, fifo_data.val, fifo_data.raw);
00206             continue;
00207         }
00208 
00209         if (fifo_data.type > 0 && fifo_data.type < DATA_TYPE_PPG2_LEDC3) {
00210             last_samples[fifo_data.type] = fifo_data.val;
00211         }
00212 
00213         if (fifo_data.type == DATA_TYPE_PPG1_LEDC1) {
00214             max8614x_agc_handler(&led_ctrl, last_samples);
00215         }
00216 
00217         if (fifo_data.type == DATA_TYPE_PPG1_LEDC1) {
00218             ppg_data.ir = fifo_data.val;
00219         } else if (fifo_data.type == DATA_TYPE_PPG1_LEDC2) {
00220             ppg_data.red = fifo_data.val;
00221         } else if (fifo_data.type == DATA_TYPE_PPG1_LEDC3) {
00222             ppg_data.green = fifo_data.val;
00223         }
00224 
00225         ppg_data_ack |= 1 << fifo_data.type;
00226 
00227         if ((ppg_data_ack & ir_green_red_ppg_type) != ir_green_red_ppg_type ){
00228             continue;
00229         }
00230         ppg_data_ack = 0;
00231 
00232         ret = enqueue(&queue, &ppg_data);
00233         if (ret < 0) {
00234             pr_err("Enqueue data is failed. ret: %d, thrown: %d",
00235                     ret, num_samples - i);
00236             return;
00237         }
00238     }
00239 }
00240 
00241 int MAX8614X::enable_die_temp()
00242 {
00243     int ret = 0;
00244 
00245     ret = writeRegister(MAX8614X_DIE_TEMP_CFG_REG, MAX8614X_DIE_TEMP_EN);
00246     if (ret < 0) {
00247         pr_err("SPI Communication error");
00248     }
00249 
00250     return ret;
00251 }
00252 
00253 int MAX8614X::read_die_temp()
00254 {
00255     int ret = 0;
00256     uint8_t buf[2];
00257 
00258     ret = readRegister(MAX8614X_DIE_TEMP_INT_REG, buf, 2);
00259     if (ret < 0) {
00260         pr_err("Unable to read die_temp. ret: %d", ret);
00261         return ret;
00262     }
00263 
00264     die_temp.frac = (uint8_t)buf[1] & MAX8614X_DIE_TEMP_FRAC_MASK;
00265     die_temp.tint = (uint8_t)buf[0];
00266 
00267     pr_debug("Die temp: %d - %d, %d", die_temp.val, buf[0], buf[1]);
00268     return enable_die_temp();
00269 }
00270 
00271 void MAX8614X::irq_handler(void)
00272 {
00273     int ret;
00274     int_status_t status;
00275 
00276     ret = readRegister(MAX8614X_INT_STATUS1_REG, status.val, 2);
00277     if (ret < 0) {
00278         pr_err("readRegister failed. ret: %d", ret);
00279     }
00280     pr_debug("Status reg: %X %X", status.val[0], status.val[1]);
00281 
00282     if (status.a_full || status.data_rdy) {
00283         fifo_irq_handler();
00284     }
00285 
00286     if (status.die_temp_rdy) {
00287         pr_debug("Pwr_rdy interrupt was triggered.");
00288     }
00289 
00290     if (status.pwr_rdy) {
00291         pr_info("Pwr_rdy interrupt was triggered.");
00292     }
00293 
00294     if (status.die_temp_rdy) {
00295         read_die_temp();
00296     }
00297 
00298     if (status.vdd_oor) {
00299         vdd_oor_cnt++;
00300         pr_info("VDD Out of range cnt: %d", vdd_oor_cnt);
00301     }
00302     if (status.sha_done) {
00303         shaComplete = true;
00304         printf("sha interrupt\n\r");
00305     }
00306 }
00307 bool MAX8614X::isShaComplete(void)
00308 {
00309     return shaComplete;
00310 }
00311 void MAX8614X::clearShaComplete(void)
00312 {
00313     shaComplete = false;
00314 }
00315 int MAX8614X::reset()
00316 {
00317     int ret = 0;
00318 
00319     ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG,
00320             MAX8614X_SYSTEM_RESET_MASK);
00321     if (ret < 0) {
00322         pr_err("writeRegister failed. ret: %d", ret);
00323         return ret;
00324     }
00325 
00326     ret = queue_reset(&queue);
00327     if (ret < 0) {
00328         pr_err("queue_reset failed. ret: %d", ret);
00329         return ret;
00330     }
00331 
00332     led_control_reset(&led_ctrl);
00333 
00334     return ret;
00335 }
00336 
00337 int MAX8614X::poweroff()
00338 {
00339     int ret = 0;
00340 
00341     ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG,
00342             MAX8614X_SYSTEM_SHDN_MASK);
00343     if (ret < 0) {
00344         pr_err("writeRegister failed. ret: %d", ret);
00345         return ret;
00346     }
00347 
00348     return ret;
00349 }
00350 
00351 int MAX8614X::init()
00352 {
00353     int ret = RTN_NO_ERROR;
00354     uint8_t part_id, rev_id;
00355     void *queue_buf = NULL;
00356 
00357     ret = get_part_info(&part_id, &rev_id);
00358     if (ret < 0) {
00359         pr_err("MAX8614X is not detected. Part_id: 0x%X, Rev_Id: 0x%X",
00360                 part_id, rev_id);
00361         ret = RTN_ERR_NOT_8614x;
00362         goto fail;
00363     }
00364     pr_info("MAX8614X detected. Part_id: 0x%X, Rev_Id: 0x%X", part_id, rev_id);
00365 
00366     queue_buf = malloc(sizeof(ppg_data_t) * MAX8614X_DRIVER_FIFO_SZ);
00367     if (queue_buf == NULL) {
00368         pr_err("malloc failed. ret: %d", ret);
00369         ret = RTN_ERR_MEM_ALLOC_FAIL;
00370         goto fail;
00371     }
00372 
00373     ret = queue_init(&queue, queue_buf,
00374             sizeof(ppg_data_t), sizeof(ppg_data_t) * MAX8614X_DRIVER_FIFO_SZ);
00375     if (ret < 0) {
00376         pr_err("queue_init failed");
00377         ret = RTN_ERR_QUEUE_INIT;
00378         free(queue_buf);
00379         goto fail;
00380     }
00381 
00382     ret = writeRegister(MAX8614X_SYSTEM_CTRL_REG,
00383             MAX8614X_SYSTEM_RESET_MASK);
00384     if (ret < 0) {
00385         pr_err("writeRegister failed. ret: %d", ret);
00386         goto fail;
00387     }
00388 
00389     die_temp.frac = 0;
00390     die_temp.tint = 0;
00391 
00392     led_control_init(&led_ctrl); /*TODO: after porting agc, test */
00393 
00394     m_ir.fall(Callback<void()>(this, &MAX8614X::irq_handler));
00395 
00396     return ret;
00397 fail:
00398     pr_err("Init failed. ret: %d", ret);
00399     return ret;
00400 }
00401 
00402 int MAX8614X::sensor_enable(int enable)
00403 {
00404     int ret = RTN_NO_ERROR;
00405     uint8_t led_seq[3];
00406 
00407     RegisterMap_t ppg_init_cfg[] = {
00408         { MAX8614X_SYSTEM_CTRL_REG, MAX8614X_SYSTEM_RESET_MASK},
00409         { MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us)
00410                                | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA)
00411                                | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA)
00412         { MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_100_SPS}, // PPG_SR: 3 (100Hz), SMP_AVE=0
00413         { MAX8614X_LED_SEQ1_REG, 0x21},
00414         { MAX8614X_LED_SEQ2_REG, 0x03},
00415         { MAX8614X_LED1_PA_REG, 0x80},
00416         { MAX8614X_LED2_PA_REG, 0x80},
00417         { MAX8614X_LED3_PA_REG, 0x80},
00418         { MAX8614X_LED_RANGE1_REG, MAX8614X_LED1_RGE_25mA_MASK
00419                                  | MAX8614X_LED2_RGE_25mA_MASK
00420                                  | MAX8614X_LED3_RGE_25mA_MASK},
00421         { MAX8614X_FIFO_CFG1_REG, 0x0C},
00422         { MAX8614X_FIFO_CFG2_REG, MAX8614X_FLUSH_FIFO_MASK
00423                                 | MAX8614X_FIFO_STAT_CLR_MASK
00424                                 | MAX8614X_A_FULL_TYPE_MASK // Try 0
00425                                 | MAX8614X_FIFO_RO_MASK
00426                                 | MAX8614X_FIFO_EN_MASK},
00427         { MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_A_FULL_MASK
00428                                   | MAX8614X_INT1_EN_DIE_TEMP_MASK
00429                                   | MAX8614X_INT1_EN_VDD_OOR_MASK},
00430     };
00431 
00432     if (enable) {
00433         /* Read current sequence settings, and check what modes are open */
00434         led_seq[0] = MAX8614X_LED_SEQ1_REG;
00435         ret |= readRegister(MAX8614X_LED_SEQ1_REG, led_seq, 3);
00436         if (ret < 0) {
00437             pr_err("readRegister failed. ret: %d", ret);
00438             return ret;
00439         }
00440 
00441         pr_debug("0-Sequence registers: %X %X %X", led_seq[0], led_seq[1], led_seq[2]);
00442         ret |= writeBlock(ppg_init_cfg, ARRAY_SIZE(ppg_init_cfg));
00443         led_seq[0] = MAX8614X_INT_STATUS1_REG;
00444         ret |= readRegister(MAX8614X_INT_STATUS1_REG, led_seq, 3); // Mert: the len was 3 ?!
00445         pr_debug("1-Sequence registers: %X %X %X", led_seq[0], led_seq[1], led_seq[2]);
00446         if (ret < 0) {
00447             pr_err("readRegister failed. ret: %d", ret);
00448             return ret;
00449         }
00450         agc_enable(1);
00451         pr_debug("Wrote register settings. ret: %d", ret);
00452     } else {
00453         ret = reset();
00454         if (ret < 0) {
00455             pr_err("reset failed. ret: %d", ret);
00456             return ret;
00457         }
00458 
00459         ret = poweroff();
00460         if (ret < 0) {
00461             pr_err("poweroff failed. ret: %d", ret);
00462             return ret;
00463         }
00464     }
00465 
00466     return RTN_NO_ERROR;
00467 }
00468 
00469 int MAX8614X::agc_enable(int agc_enable)
00470 {
00471     int ret = RTN_NO_ERROR;
00472     led_ctrl.agc_is_enabled = !!agc_enable;
00473     led_ctrl.lpm_is_enabled = !!agc_enable;
00474     ret = led_prox_init(&led_ctrl, led_ctrl.lpm_is_enabled);
00475     return ret;
00476 }
00477 
00478 int MAX8614X::dequeue_from_fifo_queue(uint32_t *ir, uint32_t *red, uint32_t *green)
00479 {
00480     int ret;
00481     ppg_data_t ppg_data;
00482 
00483     ret = dequeue(&queue, &ppg_data);
00484     if (ret < 0) {
00485         return RTN_ERR_QUEUE_EMPTY;
00486     }
00487 
00488     pr_debug("%lu  %lu  %lu", ppg_data.ir, ppg_data.red, ppg_data.green);
00489 
00490     *ir = ppg_data.ir;
00491     *red = ppg_data.red;
00492     *green = ppg_data.green;
00493 
00494     return RTN_NO_ERROR;
00495 }
00496 
00497 int MAX8614X::dump_registers()
00498 {
00499     int ret = 0;
00500     uint8_t reg_addr;
00501     uint8_t val;
00502 
00503     for (reg_addr = 0x00; reg_addr <= 0x42; reg_addr++) {
00504         ret |= readRegister(reg_addr, &val, 1);
00505         printf("{%02X,%02X},", reg_addr, val);
00506     }
00507 
00508     for (reg_addr = 0xF0; reg_addr != 0x00; reg_addr++) {
00509         ret |= readRegister(reg_addr, &val, 1);
00510         printf("{%02X,%02X},", reg_addr, val);
00511     }
00512 
00513     return ret;
00514 }
00515 
00516 const char * MAX8614X::get_sensor_part_name()
00517 {
00518     return "max86141";
00519 }
00520 
00521 const char * MAX8614X::get_sensor_name()
00522 {
00523     return "ppg";
00524 }