Hi Mårten,
Le mar., sept. 20 2022 at 20:09:56 +0200, Mårten Lindahl
<marten.lindahl@xxxxxxxx> a écrit :
As the vcnl4040 and vcnl4200 chip uses runtime power management for
turning the ambient light and proximity sensors on/off, it overwrites
the entire register each time. In ALS_CONF register bit fields ALS_IT,
ALS_PERS, ALS_INT_EN are overwritten. In PS_CONF1 register bit fields
PS_DUTY, PS_PERS, PS_IT, PS_HD, and PS_INT are overwritten.
Add functions for preserving the affected bit fields when changing
power
state.
Signed-off-by: Mårten Lindahl <marten.lindahl@xxxxxxxx>
---
drivers/iio/light/vcnl4000.c | 53
++++++++++++++++++++++++++++++++++--
1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/drivers/iio/light/vcnl4000.c
b/drivers/iio/light/vcnl4000.c
index 3db4e26731bb..0b226c684957 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -74,6 +74,9 @@
#define VCNL4000_PROX_EN BIT(1) /* start proximity measurement */
#define VCNL4000_SELF_TIMED_EN BIT(0) /* start self-timed
measurement */
+#define VCNL4040_ALS_CONF_ALS_SD BIT(0) /* Enable ambient light
sensor */
+#define VCNL4040_PS_CONF1_PS_SD BIT(0) /* Enable proximity sensor */
+
/* Bit masks for interrupt registers. */
#define VCNL4010_INT_THR_SEL BIT(0) /* Select threshold interrupt
source */
#define VCNL4010_INT_THR_EN BIT(1) /* Threshold interrupt type */
@@ -188,16 +191,62 @@ static int vcnl4000_init(struct vcnl4000_data
*data)
return data->chip_spec->set_power_state(data, true);
};
+static ssize_t vcnl4000_write_als_enable(struct vcnl4000_data *data,
int val)
+{
+ int ret;
+
+ switch (data->id) {
+ case VCNL4040:
+ case VCNL4200:
The switch isn't needed, since vcnl4200_set_power_state() is only
called for compatible chips.
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
+ if (ret < 0)
+ return ret;
+
+ if (val)
+ ret &= ~VCNL4040_ALS_CONF_ALS_SD;
+ else
+ ret |= VCNL4040_ALS_CONF_ALS_SD;
+
+ return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF,
+ ret);
Are you sure a race cannot happen here?
I would assume it cannot, but that's still a bit fishy.
This driver would benefit from a regmap conversion, but it's probably a
bit too much to ask...
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t vcnl4000_write_ps_enable(struct vcnl4000_data *data,
int val)
+{
+ int ret;
+
+ switch (data->id) {
+ case VCNL4040:
+ case VCNL4200:
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+ if (ret < 0)
+ return ret;
+
+ if (val)
+ ret &= ~VCNL4040_PS_CONF1_PS_SD;
+ else
+ ret |= VCNL4040_PS_CONF1_PS_SD;
+
+ return i2c_smbus_write_word_data(data->client,
+ VCNL4200_PS_CONF1, ret);
+ default:
+ return -EINVAL;
+ }
+}
+
static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool
on)
{
u16 val = on ? 0 /* power on */ : 1 /* shut down */;
int ret;
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF,
val);
+ ret = vcnl4000_write_als_enable(data, !val);
You set "val" to 0 if "on", and to 1 if "!on", then pass "!val", this
is very confusing. You could just pass "on" here and below.
Cheers,
-Paul
if (ret < 0)
return ret;
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
val);
+ ret = vcnl4000_write_ps_enable(data, !val);
if (ret < 0)
return ret;
--
2.30.2