/*
|
* Copyright (c) 2015-2016 Infineon Technologies AG
|
*
|
* Driver for Infineon DPS310 Digital Barometric Pressure Sensor
|
*
|
*
|
*/
|
|
#include "dps310.h"
|
|
/* Meaningful Default Configuration */
|
#define IFX_DPS310_TEMPERATURE_OSR OSR_2
|
#define IFX_DPS310_PRESSURE_OSR OSR_64
|
#define IFX_DPS310_TEMPERATURE_MR TMP_MR_4
|
#define IFX_DPS310_PRESSURE_MR PM_MR_8
|
|
/**/
|
|
static dps310_scaling_coeffs_e
|
dps310_get_scaling_coef (dps310_osr_e osr)
|
{
|
dps310_scaling_coeffs_e scaling_coeff;
|
|
switch (osr){
|
|
case OSR_1:
|
scaling_coeff = OSR_SF_1;
|
break;
|
case OSR_2:
|
scaling_coeff = OSR_SF_2;
|
break;
|
case OSR_4:
|
scaling_coeff = OSR_SF_4;
|
break;
|
case OSR_8:
|
scaling_coeff = OSR_SF_8;
|
break;
|
case OSR_16:
|
scaling_coeff = OSR_SF_16;
|
break;
|
case OSR_32:
|
scaling_coeff = OSR_SF_32;
|
break;
|
case OSR_64:
|
scaling_coeff = OSR_SF_64;
|
break;
|
case OSR_128:
|
scaling_coeff = OSR_SF_128;
|
break;
|
default:
|
scaling_coeff = OSR_SF_1;
|
break;
|
}
|
return scaling_coeff;
|
}
|
|
static int dps310_read_calib_coeffs(struct dps310_state *drv_state)
|
|
{
|
s32 ret;
|
u8 read_buffer[IFX_DPS310_COEF_LEN] = {0};
|
|
if (drv_state == NULL)
|
return -EINVAL;
|
|
ret = drv_state->io->read_block((u8)IFX_DPS310_COEF_REG_ADDR,
|
(u8)IFX_DPS310_COEF_LEN, read_buffer);
|
|
if ( ret != IFX_DPS310_COEF_LEN )
|
return ret;
|
|
drv_state->calib_coeffs.C0 = (read_buffer[0] << 4) + ((read_buffer[1] >>4) & 0x0F);
|
|
if(drv_state->calib_coeffs.C0 > POW_2_11_MINUS_1)
|
drv_state->calib_coeffs.C0 = drv_state->calib_coeffs.C0 - POW_2_12;
|
|
drv_state->calib_coeffs.C1 = (read_buffer[2] + ((read_buffer[1] & 0x0F)<<8));
|
|
if(drv_state->calib_coeffs.C1 > POW_2_11_MINUS_1)
|
drv_state->calib_coeffs.C1 = drv_state->calib_coeffs.C1 - POW_2_12;
|
|
drv_state->calib_coeffs.C00 = ((read_buffer[4]<<4) + (read_buffer[3]<<12)) + ((read_buffer[5]>>4) & 0x0F);
|
|
if(drv_state->calib_coeffs.C00 > POW_2_19_MINUS_1)
|
drv_state->calib_coeffs.C00 = drv_state->calib_coeffs.C00 -POW_2_20;
|
|
drv_state->calib_coeffs.C10 = ((read_buffer[5] & 0x0F)<<16) + read_buffer[7] + (read_buffer[6]<<8);
|
|
if(drv_state->calib_coeffs.C10 > POW_2_19_MINUS_1)
|
drv_state->calib_coeffs.C10 = drv_state->calib_coeffs.C10 - POW_2_20;
|
|
drv_state->calib_coeffs.C01 = (read_buffer[9] + (read_buffer[8]<<8));
|
|
if(drv_state->calib_coeffs.C01 > POW_2_15_MINUS_1)
|
drv_state->calib_coeffs.C01 = drv_state->calib_coeffs.C01 - POW_2_16;
|
|
drv_state->calib_coeffs.C11 = (read_buffer[11] + (read_buffer[10]<<8));
|
|
if(drv_state->calib_coeffs.C11 > POW_2_15_MINUS_1)
|
drv_state->calib_coeffs.C11 = drv_state->calib_coeffs.C11 - POW_2_16;
|
|
drv_state->calib_coeffs.C20 = (read_buffer[13] + (read_buffer[12]<<8));
|
|
if(drv_state->calib_coeffs.C20 > POW_2_15_MINUS_1)
|
drv_state->calib_coeffs.C20 = drv_state->calib_coeffs.C20 - POW_2_16;
|
|
drv_state->calib_coeffs.C21 = (read_buffer[15] + (read_buffer[14]<<8));
|
|
if(drv_state->calib_coeffs.C21 > POW_2_15_MINUS_1)
|
drv_state->calib_coeffs.C21 = drv_state->calib_coeffs.C21 - POW_2_16;
|
|
drv_state->calib_coeffs.C30 = (read_buffer[17] + (read_buffer[16]<<8));
|
|
if(drv_state->calib_coeffs.C30 > POW_2_15_MINUS_1)
|
drv_state->calib_coeffs.C30 = drv_state->calib_coeffs.C30 - POW_2_16;
|
|
/* lets see which temperature diode is used for calibration and update state accordingly*/
|
ret = drv_state->io->read_byte(IFX_DPS310_TMP_COEF_SRCE_REG_ADDR);
|
|
if (ret < 0){
|
return -EIO;
|
}
|
if ((ret >> IFX_DPS310_TMP_COEF_SRCE_REG_POS_MASK) & 1 ){
|
drv_state->tmp_ext = TMP_EXT_MEMS;
|
}
|
else{
|
drv_state->tmp_ext = TMP_EXT_ASIC;
|
}
|
return 0;
|
}
|
|
|
int dps310_resume(struct dps310_state *drv_state)
|
{
|
s32 ret;
|
if (drv_state == NULL)
|
return -EINVAL;
|
|
ret = drv_state->io->write_byte(IFX_DPS310_MEAS_CFG_REG_ADDR,
|
(u8)DPS310_MODE_BACKGROUND_ALL);
|
if (ret < 0)
|
return -EIO;
|
|
drv_state->dev_mode = DPS310_MODE_BACKGROUND_ALL;
|
|
return 0;
|
|
}
|
|
|
int dps310_standby(struct dps310_state *drv_state)
|
{
|
s32 ret;
|
if (drv_state == NULL)
|
return -EINVAL;
|
|
ret = drv_state->io->write_byte(IFX_DPS310_MEAS_CFG_REG_ADDR,
|
(u8)DPS310_MODE_IDLE);
|
if (ret < 0)
|
return -EIO;
|
|
drv_state->dev_mode = DPS310_MODE_IDLE;
|
|
return 0;
|
}
|
|
int dps310_config(struct dps310_state *drv_state,
|
dps310_osr_e osr_temp,
|
dps310_tmp_rate_e mr_temp,
|
dps310_osr_e osr_press,
|
dps310_pm_rate_e mr_press,
|
dps310_temperature_src_e temp_src)
|
{
|
|
s32 ret;
|
u8 config;
|
|
if (drv_state == NULL)
|
return -EINVAL;
|
|
/* configure temperature measurements first*/
|
/*Prepare a configuration word for TMP_CFG register*/
|
config = (u8) temp_src;
|
|
/*First Set the TMP_RATE[2:0] -> 6:4 */
|
config |= ((u8)mr_temp);
|
|
/*Set the TMP_PRC[3:0] -> 2:0 */
|
config |= ((u8)osr_temp);
|
|
ret = drv_state->io->write_byte(IFX_DPS310_TMP_CFG_REG_ADDR,
|
config);
|
if (ret < 0)
|
return -EIO;
|
|
/*Prepare a configuration word for PRS_CFG register*/
|
/*First Set the PM_RATE[2:0] -> 6:4 */
|
config = (u8) ( 0x00 ) | ((u8)mr_press);
|
|
/*Set the PM_PRC[3:0] -> 3:0 */
|
config |= ((u8)osr_press);
|
|
ret = drv_state->io->write_byte(IFX_DPS310_PRS_CFG_REG_ADDR,
|
config);
|
if (ret < 0)
|
return -EIO;
|
|
/* always take configuration word from state*/
|
config = drv_state->cfg_word;
|
|
/*If oversampling rate for temperature is greater than 8 times, then set TMP_SHIFT bit in CFG_REG */
|
if ((u8)osr_temp > (u8) OSR_8){
|
config |= (u8) IFX_DPS310_CFG_TMP_SHIFT_EN_SET_VAL;
|
}
|
|
/*If oversampling rate for pressure is greater than 8 times, then set P_SHIFT bit in CFG_REG */
|
if ((u8)osr_press > (u8) OSR_8){
|
config |= (u8) IFX_DPS310_CFG_PRS_SHIFT_EN_SET_VAL;
|
}
|
|
/* write CFG_REG */
|
ret = drv_state->io->write_byte(IFX_DPS310_CFG_REG_ADDR,
|
config);
|
if (ret < 0)
|
return -EIO;
|
|
/*Update state accordingly with proper scaling factors based on oversampling rates*/
|
drv_state->tmp_osr_scale_coeff = dps310_get_scaling_coef(osr_temp);
|
|
drv_state->prs_osr_scale_coeff = dps310_get_scaling_coef(osr_press);
|
|
drv_state->press_mr = mr_press;
|
|
drv_state->temp_mr = mr_temp;
|
|
drv_state->temp_osr = osr_temp;
|
|
drv_state->press_osr = osr_press;
|
|
drv_state->tmp_ext = temp_src;
|
|
return 0;
|
|
}
|
|
|
int dps310_get_processed_data (struct dps310_state *drv_state,
|
f64 *pressure,
|
f64 *temperature)
|
{
|
s32 ret;
|
u8 read_buffer[IFX_DPS310_PSR_TMP_READ_LEN] = {0};
|
f64 press_raw;
|
f64 temp_raw;
|
|
f64 temp_scaled;
|
f64 temp_final;
|
f64 press_scaled;
|
f64 press_final;
|
|
if (drv_state == NULL)
|
return -EINVAL;
|
|
ret = test_read_block(IFX_DPS310_PSR_TMP_READ_REG_ADDR,
|
IFX_DPS310_PSR_TMP_READ_LEN,
|
read_buffer);
|
|
if (ret < IFX_DPS310_PSR_TMP_READ_LEN)
|
return -EINVAL;
|
|
press_raw = (read_buffer[2]) + (read_buffer[1]<<8) + (read_buffer[0] <<16);
|
temp_raw = (read_buffer[5]) + (read_buffer[4]<<8) + (read_buffer[3] <<16);
|
|
if(temp_raw > POW_2_23_MINUS_1){
|
temp_raw = temp_raw - POW_2_24;
|
}
|
|
if(press_raw > POW_2_23_MINUS_1){
|
press_raw = press_raw - POW_2_24;
|
}
|
|
temp_scaled = (double)temp_raw / (double) (drv_state->tmp_osr_scale_coeff);
|
|
temp_final = (drv_state->calib_coeffs.C0 /2.0f) + drv_state->calib_coeffs.C1 * temp_scaled ;
|
|
press_scaled = (double) press_raw / drv_state->prs_osr_scale_coeff;
|
|
press_final = drv_state->calib_coeffs.C00 +
|
press_scaled * ( drv_state->calib_coeffs.C10 + press_scaled *
|
( drv_state->calib_coeffs.C20 + press_scaled * drv_state->calib_coeffs.C30 ) ) +
|
temp_scaled * drv_state->calib_coeffs.C01 +
|
temp_scaled * press_scaled * ( drv_state->calib_coeffs.C11 +
|
press_scaled * drv_state->calib_coeffs.C21 );
|
|
press_final = press_final * 0.01f; //to convert it into mBar
|
|
*temperature = temp_final;
|
*pressure = press_final; //press_final;
|
|
return 0;
|
}
|
|
int dps310_init(struct dps310_state *drv_state, dps310_bus_connection *io)
|
{
|
s32 ret;
|
|
if (!drv_state){
|
return -EINVAL;
|
}
|
|
if (!io){
|
return -EINVAL;
|
}
|
|
drv_state->cfg_word = 0;
|
drv_state->enable = 0;
|
|
/*first verify chip by reading product and rev id*/
|
ret = io->read_byte(IFX_DPS310_PROD_REV_ID_REG_ADDR);
|
|
if (ret < 0){
|
ret = -EIO;
|
goto err_handler_iio;
|
}
|
|
if (ret != IFX_DSPS310_PROD_REV_ID_VAL){
|
ret = -EINVAL;
|
goto err_handler_iio;
|
}
|
|
/* attach bus connection instance to state*/
|
drv_state->io = io;
|
|
/* from here wait for about 40ms till calibration coefficients become available*/
|
if (drv_state->io->delayms != NULL)
|
drv_state->io->delayms(40);
|
|
/* read now the calibration coeffs, temperature coef source and store in driver state*/
|
ret = dps310_read_calib_coeffs(drv_state);
|
|
if (ret < 0){
|
goto err_handler_iio;
|
}
|
|
/* Now apply ADC Temperature gain settings*/
|
/* First write valid signature on 0x0e and 0x0f
|
* to unlock address 0x62 */
|
drv_state->io->write_byte((u8)0x0e,(u8)0xa5);
|
drv_state->io->write_byte((u8)0x0f,(u8)0x96);
|
/*Then update high gain value for Temperature*/
|
drv_state->io->write_byte((u8)0x62,(u8)0x02);
|
|
/*Finally lock back the location 0x62*/
|
drv_state->io->write_byte((u8)0x0e,(u8)0x00);
|
drv_state->io->write_byte((u8)0x0f,(u8)0x00);
|
|
|
/* configure sensor for default ODR settings*/
|
ret = dps310_config(drv_state,
|
IFX_DPS310_TEMPERATURE_OSR,
|
IFX_DPS310_TEMPERATURE_MR,
|
IFX_DPS310_PRESSURE_OSR,
|
IFX_DPS310_PRESSURE_MR,
|
drv_state->tmp_ext);
|
if (ret < 0){
|
goto err_handler_iio;
|
}
|
|
/* activate sensor*/
|
ret = dps310_resume(drv_state);
|
if (ret < 0){
|
goto err_handler_iio;
|
}
|
|
return 0;
|
|
err_handler_iio:
|
return ret;
|
|
}
|