drivers: sensor: vcnl4040: fix sensor register init

The driver has a read register, modify value, write value flow due to
needing to modify nibbles of registers at different times.  The issue
this driver previously had was new incoming configurations from the
driver would be corrupted by previous configurations written into the
vcnl4040 (when there's been no power off). This would be in the case
when a device continuously power on and a developer is tweaking the
vcnl4040's configuration or when deploying firmware updates with
a new vcnl4040 configuration.

Signed-off-by: Nick Ward <nick.ward@ftpsolutions.com.au>
This commit is contained in:
Nick Ward 2022-11-18 11:34:47 +11:00 committed by Carles Cufí
parent d8c107e166
commit db8ecd5ec8
2 changed files with 32 additions and 66 deletions

View File

@ -43,7 +43,7 @@ int vcnl4040_write(const struct device *dev, uint8_t reg, uint16_t value)
ret = i2c_write_dt(&config->i2c, buf, sizeof(buf));
if (ret < 0) {
LOG_ERR("write: %u", ret);
LOG_ERR("write[%02X]: %u", reg, ret);
return ret;
}
@ -119,67 +119,20 @@ static int vcnl4040_channel_get(const struct device *dev,
return ret;
}
static int vcnl4040_proxy_setup(const struct device *dev)
static int vcnl4040_reg_setup(const struct device *dev)
{
const struct vcnl4040_config *config = dev->config;
uint16_t conf = 0;
if (vcnl4040_read(dev, VCNL4040_REG_PS_MS, &conf)) {
LOG_ERR("Could not read proximity config");
return -EIO;
}
/* Set LED current */
conf |= config->led_i << VCNL4040_LED_I_POS;
if (vcnl4040_write(dev, VCNL4040_REG_PS_MS, conf)) {
LOG_ERR("Could not write proximity config");
return -EIO;
}
if (vcnl4040_read(dev, VCNL4040_REG_PS_CONF, &conf)) {
LOG_ERR("Could not read proximity config");
return -EIO;
}
/* Set PS_HD */
conf |= VCNL4040_PS_HD_MASK;
/* Set duty cycle */
conf |= config->led_dc << VCNL4040_PS_DUTY_POS;
/* Set integration time */
conf |= config->proxy_it << VCNL4040_PS_IT_POS;
/* Clear proximity shutdown */
conf &= ~VCNL4040_PS_SD_MASK;
if (vcnl4040_write(dev, VCNL4040_REG_PS_CONF, conf)) {
LOG_ERR("Could not write proximity config");
return -EIO;
}
return 0;
}
uint16_t value[VCNL4040_RW_REG_COUNT] = { 0 };
uint8_t reg;
int ret = 0;
#ifdef CONFIG_VCNL4040_ENABLE_ALS
static int vcnl4040_ambient_setup(const struct device *dev)
{
const struct vcnl4040_config *config = dev->config;
struct vcnl4040_data *data = dev->data;
uint16_t conf = 0;
if (vcnl4040_read(dev, VCNL4040_REG_ALS_CONF, &conf)) {
LOG_ERR("Could not read proximity config");
return -EIO;
}
/* Set ALS integration time */
conf |= config->als_it << VCNL4040_ALS_IT_POS;
value[VCNL4040_REG_ALS_CONF] = config->als_it << VCNL4040_ALS_IT_POS;
/* Clear ALS shutdown */
conf &= ~VCNL4040_ALS_SD_MASK;
if (vcnl4040_write(dev, VCNL4040_REG_ALS_CONF, conf)) {
LOG_ERR("Could not write proximity config");
return -EIO;
}
value[VCNL4040_REG_ALS_CONF] &= ~VCNL4040_ALS_SD_MASK;
/*
* scale the lux depending on the value of the integration time
@ -205,11 +158,29 @@ static int vcnl4040_ambient_setup(const struct device *dev)
config->als_it);
break;
}
return 0;
}
#else
value[VCNL4040_REG_ALS_CONF] = VCNL4040_ALS_SD_MASK; /* default */
#endif
/* Set PS_HD */
value[VCNL4040_REG_PS_CONF] = VCNL4040_PS_HD_MASK;
/* Set duty cycle */
value[VCNL4040_REG_PS_CONF] |= config->led_dc << VCNL4040_PS_DUTY_POS;
/* Set integration time */
value[VCNL4040_REG_PS_CONF] |= config->proxy_it << VCNL4040_PS_IT_POS;
/* Clear proximity shutdown */
value[VCNL4040_REG_PS_CONF] &= ~VCNL4040_PS_SD_MASK;
/* Set LED current */
value[VCNL4040_REG_PS_MS] = config->led_i << VCNL4040_LED_I_POS;
for (reg = 0; reg < ARRAY_SIZE(value); reg++) {
ret |= vcnl4040_write(dev, reg, value[reg]);
}
return ret;
}
#ifdef CONFIG_PM_DEVICE
static int vcnl4040_pm_action(const struct device *dev,
enum pm_device_action action)
@ -295,18 +266,11 @@ static int vcnl4040_init(const struct device *dev)
return -EIO;
}
if (vcnl4040_proxy_setup(dev)) {
LOG_ERR("Failed to setup proximity functionality");
if (vcnl4040_reg_setup(dev)) {
LOG_ERR("register setup");
return -EIO;
}
#ifdef CONFIG_VCNL4040_ENABLE_ALS
if (vcnl4040_ambient_setup(dev)) {
LOG_ERR("Failed to setup ambient light functionality");
return -EIO;
}
#endif
k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT);
#if CONFIG_VCNL4040_TRIGGER

View File

@ -27,6 +27,8 @@
#define VCNL4040_REG_INT_FLAG 0x0B
#define VCNL4040_REG_DEVICE_ID 0x0C
#define VCNL4040_RW_REG_COUNT 0x08 /* [0x00, 0x07] */
#define VCNL4040_DEFAULT_ID 0x0186
#define VCNL4040_LED_I_POS 8