initial commit, reads dev id
Embed:
(wiki syntax)
Show/hide line numbers
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 }
Generated on Fri Sep 2 2022 22:34:53 by
1.7.2