2023-06-13 14:12:17

by Astrid Rost

[permalink] [raw]
Subject: [PATCH v6 0/8] iio: light: vcnl4000: Add features for vncl4040/4200

Add a more complete support for vncl4040 and vcnl4200, which allows to
change the distance of proximity detection and interrupt support for the
illuminance sensor.

Proximity functionality:
- Interrupt support (new on vcnl4200).

Proximity reduce the amount of interrupts:
- Adaptable integration time (new on vcnl4200) - the sampling rate
changes according to this value.
- Period - interrupt is asserted if the value is above or
below a certain threshold.

Proximity change the activity distance:
- Oversampling ratio - Amount of LED pulses per measured raw value.
- Calibration bias - LED current calibration of the sensor.

Illuminance functionality:
- Interrupt support.

Illuminance reduce the amount of interrupts:
- Adaptable integration time - the sampling rate and scale changes
according to this value.
- Period – interrupt is asserted if the value is above or
below a certain threshold.

changes v2:
- [PATCH v2 3/7] Fixed calculation of al_scale.
Fix the value of vcnl4040 according to the data-sheet.
Use div_u64 for the division.
scription for the branch

changes v3:
- [PATCH v3 1-3/7] Add differences between the chips as variables in
chip-spec.
- [PATCH v3 4/7] Changed commit message.
- [PATCH v3 5/7] Use period instead of debounce time. This causes some
calculations as the period is a time and the chip allows to set a certain
amount of measurements above/below the threshold, before throwing an
interrupt.
- [PATCH v3 6/7] Changed commit message.

changes v4:
- [PATCH v3 1-3/7] Fix setting correct als_it for vcnl4040.
- [PATCH v3 5/7] Use MICRO macro.
Fix values greater than 1 s for the proximity period.

changes v5:
[PATCH v5 2/7]:
- Calculate ps_it from ps_it_times by usinh NSEC_PER_USEC.
[PATCH v5 3/7]:
- Calculate als_it from ps_it_times by using NSEC_PER_USEC.
- Store scale step factor in chip_spec.
- Fixes sampling_rate to ns + 20 %.
[PATCH v5 3/7 - 7/7]
- Changed formatting.
- Changed some variable names.

- [PATCH v3 4/7] Changed commit message.
- [PATCH v3 5/7] Use period instead of debounce time. This causes some
calculations as the period is a time and the chip allows to set a certain
amount of measurements above/below the threshold, before throwing an
interrupt.
- [PATCH v3 6/7] Changed commit message.

changes v4:
- [PATCH v3 1-3/7] Fix setting correct als_it for vcnl4040.
- [PATCH v3 5/7] Use MICRO macro.
Fix values greater than 1 s for the proximity period.

changes v5:
[PATCH v5 2/7]:
- Calculate ps_it from ps_it_times by usinh NSEC_PER_USEC.
[PATCH v5 3/7]:
- Calculate als_it from ps_it_times by using NSEC_PER_USEC.
- Store scale step factor in chip_spec.
- Fixes sampling_rate to ns + 20 %.
[PATCH v5 3/7 - 7/7]
- Changed formatting.
- Changed some variable names.

changes v6:
Added [PATCH v6 3/8]:
- Add switch case for IIO_PROXIMITY check.
[PATCH v5 1/7 - 7/7]
- Changed formatting.
[PATCH v5 3/7, 5/7, 6/7, 7/7]
- Changed loop.
- Changed some variable names.

Astrid Rost (8):
[PATCH v6 1/8] iio: light: vcnl4000: Add proximity irq for vcnl4200
[PATCH v6 2/8] iio: light: vcnl4000: Add proximity ps_it for vcnl4200
[PATCH v6 3/8] iio: light: vcnl4000: Check type with switch case
[PATCH v6 4/8] iio: light: vcnl4000: Add als_it for vcnl4040/4200
[PATCH v6 5/8] iio: light: vcnl4000: add illuminance irq vcnl4040/4200
[PATCH v6 6/8] iio: light: vcnl4000: Add period for vcnl4040/4200
[PATCH v6 7/8] iio: light: vcnl4000: Add oversampling_ratio for 4040/4200
[PATCH v6 8/8] iio: light: vcnl4000: Add calibration bias for 4040/4200

drivers/iio/light/vcnl4000.c | 710 +++++++++++++++++++++++++++++++----
1 file changed, 643 insertions(+), 67 deletions(-)

--
2.30.2



2023-06-13 14:12:48

by Astrid Rost

[permalink] [raw]
Subject: [PATCH v6 4/8] iio: light: vcnl4000: Add als_it for vcnl4040/4200

Add illuminance integration time for vcnl4040 and vcnl4200.
Add read/write attribute for illuminance integration time and read
attribute for available integration times.
Set scale and sampling rate according to the integration time.

Signed-off-by: Astrid Rost <[email protected]>
---
drivers/iio/light/vcnl4000.c | 94 ++++++++++++++++++++++++++++++++++--
1 file changed, 91 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index b2dc9ca7325f..0a96e9451ec7 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -80,6 +80,7 @@
#define VCNL4000_SELF_TIMED_EN BIT(0) /* start self-timed measurement */

#define VCNL4040_ALS_CONF_ALS_SHUTDOWN BIT(0)
+#define VCNL4040_ALS_CONF_IT GENMASK(7, 6) /* Ambient integration time */
#define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0)
#define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */
#define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */
@@ -133,6 +134,20 @@ static const int vcnl4200_ps_it_times[][2] = {
{0, 864},
};

+static const int vcnl4040_als_it_times[][2] = {
+ {0, 80000},
+ {0, 160000},
+ {0, 320000},
+ {0, 640000},
+};
+
+static const int vcnl4200_als_it_times[][2] = {
+ {0, 50000},
+ {0, 100000},
+ {0, 200000},
+ {0, 400000},
+};
+
#define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */

enum vcnl4000_device_ids {
@@ -178,6 +193,9 @@ struct vcnl4000_chip_spec {
u8 int_reg;
const int(*ps_it_times)[][2];
const int num_ps_it_times;
+ const int(*als_it_times)[][2];
+ const int num_als_it_times;
+ const unsigned int ulux_step;
};

static const struct i2c_device_id vcnl4000_id[] = {
@@ -331,16 +349,15 @@ static int vcnl4200_init(struct vcnl4000_data *data)
data->vcnl4200_al.sampling_rate = ktime_set(0, 60000 * 1000);
/* Default wait time is 4.8ms, add 20% tolerance. */
data->vcnl4200_ps.sampling_rate = ktime_set(0, 5760 * 1000);
- data->al_scale = 24000;
break;
case VCNL4040_PROD_ID:
/* Default wait time is 80ms, add 20% tolerance. */
data->vcnl4200_al.sampling_rate = ktime_set(0, 96000 * 1000);
/* Default wait time is 5ms, add 20% tolerance. */
data->vcnl4200_ps.sampling_rate = ktime_set(0, 6000 * 1000);
- data->al_scale = 120000;
break;
}
+ data->al_scale = data->chip_spec->ulux_step;
mutex_init(&data->vcnl4200_al.lock);
mutex_init(&data->vcnl4200_ps.lock);

@@ -510,6 +527,60 @@ static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
return ret;
}

+static int vcnl4040_read_als_it(struct vcnl4000_data *data, int *val, int *val2)
+{
+ int ret;
+
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
+ if (ret < 0)
+ return ret;
+
+ ret = FIELD_GET(VCNL4040_ALS_CONF_IT, ret);
+ if (ret >= data->chip_spec->num_als_it_times)
+ return -EINVAL;
+
+ *val = (*data->chip_spec->als_it_times)[ret][0];
+ *val2 = (*data->chip_spec->als_it_times)[ret][1];
+
+ return 0;
+}
+
+static ssize_t vcnl4040_write_als_it(struct vcnl4000_data *data, int val)
+{
+ unsigned int i;
+ int ret;
+ u16 regval;
+
+ for (i = 0; i < data->chip_spec->num_als_it_times; i++) {
+ if (val == (*data->chip_spec->als_it_times)[i][1])
+ break;
+ }
+
+ if (i == data->chip_spec->num_als_it_times)
+ return -EINVAL;
+
+ data->vcnl4200_al.sampling_rate = ktime_set(0, val * 1200);
+ data->al_scale = div_u64(mul_u32_u32(data->chip_spec->ulux_step,
+ (*data->chip_spec->als_it_times)[0][1]),
+ val);
+
+ mutex_lock(&data->vcnl4000_lock);
+
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
+ if (ret < 0)
+ goto out_unlock;
+
+ regval = FIELD_PREP(VCNL4040_ALS_CONF_IT, i);
+ regval |= (ret & ~VCNL4040_ALS_CONF_IT);
+ ret = i2c_smbus_write_word_data(data->client,
+ VCNL4200_AL_CONF,
+ regval);
+
+out_unlock:
+ mutex_unlock(&data->vcnl4000_lock);
+ return ret;
+}
+
static int vcnl4040_read_ps_it(struct vcnl4000_data *data, int *val, int *val2)
{
int ret;
@@ -601,6 +672,9 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_INT_TIME:
switch (chan->type) {
+ case IIO_LIGHT:
+ ret = vcnl4040_read_als_it(data, val, val2);
+ break;
case IIO_PROXIMITY:
ret = vcnl4040_read_ps_it(data, val, val2);
break;
@@ -626,6 +700,8 @@ static int vcnl4040_write_raw(struct iio_dev *indio_dev,
if (val != 0)
return -EINVAL;
switch (chan->type) {
+ case IIO_LIGHT:
+ return vcnl4040_write_als_it(data, val2);
case IIO_PROXIMITY:
return vcnl4040_write_ps_it(data, val2);
default:
@@ -646,6 +722,10 @@ static int vcnl4040_read_avail(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
switch (chan->type) {
+ case IIO_LIGHT:
+ *vals = (int *)(*data->chip_spec->als_it_times);
+ *length = 2 * data->chip_spec->num_als_it_times;
+ break;
case IIO_PROXIMITY:
*vals = (int *)(*data->chip_spec->ps_it_times);
*length = 2 * data->chip_spec->num_ps_it_times;
@@ -1310,7 +1390,9 @@ static const struct iio_chan_spec vcnl4040_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_SCALE),
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME),
}, {
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
@@ -1383,6 +1465,9 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.int_reg = VCNL4040_INT_FLAGS,
.ps_it_times = &vcnl4040_ps_it_times,
.num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times),
+ .als_it_times = &vcnl4040_als_it_times,
+ .num_als_it_times = ARRAY_SIZE(vcnl4040_als_it_times),
+ .ulux_step = 100000,
},
[VCNL4200] = {
.prod = "VCNL4200",
@@ -1397,6 +1482,9 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.int_reg = VCNL4200_INT_FLAGS,
.ps_it_times = &vcnl4200_ps_it_times,
.num_ps_it_times = ARRAY_SIZE(vcnl4200_ps_it_times),
+ .als_it_times = &vcnl4200_als_it_times,
+ .num_als_it_times = ARRAY_SIZE(vcnl4200_als_it_times),
+ .ulux_step = 24000,
},
};

--
2.30.2


2023-06-13 14:13:42

by Astrid Rost

[permalink] [raw]
Subject: [PATCH v6 1/8] iio: light: vcnl4000: Add proximity irq for vcnl4200

Add proximity interrupt support for vcnl4200 (similar to vcnl4040).
Add support to configure proximity sensor interrupts and threshold
limits. If an interrupt is detected an event will be pushed to the
event interface.

Signed-off-by: Astrid Rost <[email protected]>
---
drivers/iio/light/vcnl4000.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index 56d3963d3d66..55a1952672a4 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -65,6 +65,7 @@
#define VCNL4200_PS_DATA 0x08 /* Proximity data */
#define VCNL4200_AL_DATA 0x09 /* Ambient light data */
#define VCNL4040_INT_FLAGS 0x0b /* Interrupt register */
+#define VCNL4200_INT_FLAGS 0x0d /* Interrupt register */
#define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */

#define VCNL4040_DEV_ID 0x0c /* Device ID and version */
@@ -164,6 +165,8 @@ struct vcnl4000_chip_spec {
int (*set_power_state)(struct vcnl4000_data *data, bool on);
irqreturn_t (*irq_thread)(int irq, void *priv);
irqreturn_t (*trig_buffer_func)(int irq, void *priv);
+
+ u8 int_reg;
};

static const struct i2c_device_id vcnl4000_id[] = {
@@ -1005,7 +1008,7 @@ static irqreturn_t vcnl4040_irq_thread(int irq, void *p)
struct vcnl4000_data *data = iio_priv(indio_dev);
int ret;

- ret = i2c_smbus_read_word_data(data->client, VCNL4040_INT_FLAGS);
+ ret = i2c_smbus_read_word_data(data->client, data->chip_spec->int_reg);
if (ret < 0)
return IRQ_HANDLED;

@@ -1314,6 +1317,7 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.num_channels = ARRAY_SIZE(vcnl4040_channels),
.info = &vcnl4040_info,
.irq_thread = vcnl4040_irq_thread,
+ .int_reg = VCNL4040_INT_FLAGS,
},
[VCNL4200] = {
.prod = "VCNL4200",
@@ -1321,9 +1325,11 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.measure_light = vcnl4200_measure_light,
.measure_proximity = vcnl4200_measure_proximity,
.set_power_state = vcnl4200_set_power_state,
- .channels = vcnl4000_channels,
+ .channels = vcnl4040_channels,
.num_channels = ARRAY_SIZE(vcnl4000_channels),
- .info = &vcnl4000_info,
+ .info = &vcnl4040_info,
+ .irq_thread = vcnl4040_irq_thread,
+ .int_reg = VCNL4200_INT_FLAGS,
},
};

--
2.30.2


2023-06-13 14:13:57

by Astrid Rost

[permalink] [raw]
Subject: [PATCH v6 8/8] iio: light: vcnl4000: Add calibration bias for 4040/4200

The calibration bias is setting the LED current to change the detection
distance. Add read/write attribute for proximity calibration bias and
read attribute for available values. This is supported for vcnl4040 and
vcnl4200.

Signed-off-by: Astrid Rost <[email protected]>
---
drivers/iio/light/vcnl4000.c | 93 +++++++++++++++++++++++++++++++++++-
1 file changed, 91 insertions(+), 2 deletions(-)

diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index ebe9b5343bb3..d0246bcca2df 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -92,6 +92,7 @@
#define VCNL4040_CONF1_PS_PERS GENMASK(5, 4) /* Proximity interrupt persistence setting */
#define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */
#define VCNL4040_PS_CONF3_MPS GENMASK(6, 5) /* Proximity multi pulse number */
+#define VCNL4040_PS_MS_LED_I GENMASK(10, 8) /* Proximity current */
#define VCNL4040_PS_IF_AWAY BIT(8) /* Proximity event cross low threshold */
#define VCNL4040_PS_IF_CLOSE BIT(9) /* Proximity event cross high threshold */
#define VCNL4040_ALS_RISING BIT(12) /* Ambient Light cross high threshold */
@@ -158,6 +159,17 @@ static const int vcnl4200_als_it_times[][2] = {
{0, 400000},
};

+static const int vcnl4040_ps_calibbias_ua[][2] = {
+ {0, 50000},
+ {0, 75000},
+ {0, 100000},
+ {0, 120000},
+ {0, 140000},
+ {0, 160000},
+ {0, 180000},
+ {0, 200000},
+};
+
static const int vcnl4040_als_persistence[] = {1, 2, 4, 8};
static const int vcnl4040_ps_persistence[] = {1, 2, 3, 4};
static const int vcnl4040_ps_oversampling_ratio[] = {1, 2, 4, 8};
@@ -820,6 +832,54 @@ static ssize_t vcnl4040_write_ps_oversampling_ratio(struct vcnl4000_data *data,
return ret;
}

+static ssize_t vcnl4040_read_ps_calibbias(struct vcnl4000_data *data, int *val, int *val2)
+{
+ int ret;
+
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
+ if (ret < 0)
+ return ret;
+
+ ret = FIELD_GET(VCNL4040_PS_MS_LED_I, ret);
+ if (ret >= ARRAY_SIZE(vcnl4040_ps_calibbias_ua))
+ return -EINVAL;
+
+ *val = vcnl4040_ps_calibbias_ua[ret][0];
+ *val2 = vcnl4040_ps_calibbias_ua[ret][1];
+
+ return ret;
+}
+
+static ssize_t vcnl4040_write_ps_calibbias(struct vcnl4000_data *data, int val)
+{
+ unsigned int i;
+ int ret;
+ u16 regval;
+
+ for (i = 0; i < ARRAY_SIZE(vcnl4040_ps_calibbias_ua); i++) {
+ if (val == vcnl4040_ps_calibbias_ua[i][1])
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(vcnl4040_ps_calibbias_ua))
+ return -EINVAL;
+
+ mutex_lock(&data->vcnl4000_lock);
+
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
+ if (ret < 0)
+ goto out_unlock;
+
+ regval = (ret & ~VCNL4040_PS_MS_LED_I);
+ regval |= FIELD_PREP(VCNL4040_PS_MS_LED_I, i);
+ ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,
+ regval);
+
+out_unlock:
+ mutex_unlock(&data->vcnl4000_lock);
+ return ret;
+}
+
static int vcnl4000_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -880,6 +940,16 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
+ case IIO_CHAN_INFO_CALIBBIAS:
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ ret = vcnl4040_read_ps_calibbias(data, val, val2);
+ if (ret < 0)
+ return ret;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
default:
return -EINVAL;
}
@@ -910,6 +980,13 @@ static int vcnl4040_write_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
+ case IIO_CHAN_INFO_CALIBBIAS:
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ return vcnl4040_write_ps_calibbias(data, val2);
+ default:
+ return -EINVAL;
+ }
default:
return -EINVAL;
}
@@ -948,6 +1025,16 @@ static int vcnl4040_read_avail(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
+ case IIO_CHAN_INFO_CALIBBIAS:
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ *vals = (int *)vcnl4040_ps_calibbias_ua;
+ *length = 2 * ARRAY_SIZE(vcnl4040_ps_calibbias_ua);
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
default:
return -EINVAL;
}
@@ -1721,9 +1808,11 @@ static const struct iio_chan_spec vcnl4040_channels[] = {
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_INT_TIME) |
- BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) |
- BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
.ext_info = vcnl4000_ext_info,
.event_spec = vcnl4040_event_spec,
.num_event_specs = ARRAY_SIZE(vcnl4040_event_spec),
--
2.30.2


2023-06-13 14:16:38

by Astrid Rost

[permalink] [raw]
Subject: [PATCH v6 5/8] iio: light: vcnl4000: add illuminance irq vcnl4040/4200

Add support to configure ambient light sensor interrupts and threshold
limits for vcnl4040 and vcnl4200. If an interrupt is detected an event
will be pushed to the event interface.

Signed-off-by: Astrid Rost <[email protected]>
---
drivers/iio/light/vcnl4000.c | 94 +++++++++++++++++++++++++++++++++++-
1 file changed, 92 insertions(+), 2 deletions(-)

diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index 0a96e9451ec7..0f4c39adc68a 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -62,6 +62,8 @@
#define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */
#define VCNL4040_PS_THDL_LM 0x06 /* Proximity threshold low */
#define VCNL4040_PS_THDH_LM 0x07 /* Proximity threshold high */
+#define VCNL4040_ALS_THDL_LM 0x02 /* Ambient light threshold low */
+#define VCNL4040_ALS_THDH_LM 0x01 /* Ambient light threshold high */
#define VCNL4200_PS_DATA 0x08 /* Proximity data */
#define VCNL4200_AL_DATA 0x09 /* Ambient light data */
#define VCNL4040_INT_FLAGS 0x0b /* Interrupt register */
@@ -81,11 +83,14 @@

#define VCNL4040_ALS_CONF_ALS_SHUTDOWN BIT(0)
#define VCNL4040_ALS_CONF_IT GENMASK(7, 6) /* Ambient integration time */
+#define VCNL4040_ALS_CONF_INT_EN BIT(1) /* Ambient light Interrupt enable */
#define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0)
#define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */
#define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */
#define VCNL4040_PS_IF_AWAY BIT(8) /* Proximity event cross low threshold */
#define VCNL4040_PS_IF_CLOSE BIT(9) /* Proximity event cross high threshold */
+#define VCNL4040_ALS_RISING BIT(12) /* Ambient Light cross high threshold */
+#define VCNL4040_ALS_FALLING BIT(13) /* Ambient Light cross low threshold */

/* Bit masks for interrupt registers. */
#define VCNL4010_INT_THR_SEL BIT(0) /* Select threshold interrupt source */
@@ -170,6 +175,7 @@ struct vcnl4000_data {
int rev;
int al_scale;
u8 ps_int; /* proximity interrupt mode */
+ u8 als_int; /* ambient light interrupt mode*/
const struct vcnl4000_chip_spec *chip_spec;
struct mutex vcnl4000_lock;
struct vcnl4200_channel vcnl4200_al;
@@ -295,7 +301,7 @@ static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
int ret;

/* Do not power down if interrupts are enabled */
- if (!on && data->ps_int)
+ if (!on && (data->ps_int || data->als_int))
return 0;

ret = vcnl4000_write_als_enable(data, on);
@@ -340,6 +346,7 @@ static int vcnl4200_init(struct vcnl4000_data *data)

data->rev = (ret >> 8) & 0xf;
data->ps_int = 0;
+ data->als_int = 0;

data->vcnl4200_al.reg = VCNL4200_AL_DATA;
data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
@@ -930,6 +937,26 @@ static int vcnl4040_read_event(struct iio_dev *indio_dev,
struct vcnl4000_data *data = iio_priv(indio_dev);

switch (chan->type) {
+ case IIO_LIGHT:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ ret = i2c_smbus_read_word_data(data->client,
+ VCNL4040_ALS_THDH_LM);
+ break;
+ case IIO_EV_DIR_FALLING:
+ ret = i2c_smbus_read_word_data(data->client,
+ VCNL4040_ALS_THDL_LM);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
case IIO_PROXIMITY:
switch (info) {
case IIO_EV_INFO_VALUE:
@@ -970,6 +997,28 @@ static int vcnl4040_write_event(struct iio_dev *indio_dev,
struct vcnl4000_data *data = iio_priv(indio_dev);

switch (chan->type) {
+ case IIO_LIGHT:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ ret = i2c_smbus_write_word_data(data->client,
+ VCNL4040_ALS_THDH_LM,
+ val);
+ break;
+ case IIO_EV_DIR_FALLING:
+ ret = i2c_smbus_write_word_data(data->client,
+ VCNL4040_ALS_THDL_LM,
+ val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
case IIO_PROXIMITY:
switch (info) {
case IIO_EV_INFO_VALUE:
@@ -1091,6 +1140,14 @@ static int vcnl4040_read_event_config(struct iio_dev *indio_dev,
struct vcnl4000_data *data = iio_priv(indio_dev);

switch (chan->type) {
+ case IIO_LIGHT:
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
+ if (ret < 0)
+ return ret;
+
+ data->als_int = FIELD_GET(VCNL4040_ALS_CONF_INT_EN, ret);
+
+ return data->als_int;
case IIO_PROXIMITY:
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
if (ret < 0)
@@ -1118,6 +1175,21 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev,
mutex_lock(&data->vcnl4000_lock);

switch (chan->type) {
+ case IIO_LIGHT:
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
+ if (ret < 0)
+ goto out;
+
+ mask = VCNL4040_ALS_CONF_INT_EN;
+ if (state)
+ val = (ret | mask);
+ else
+ val = (ret & ~mask);
+
+ data->als_int = FIELD_GET(VCNL4040_ALS_CONF_INT_EN, val);
+ ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF,
+ val);
+ break;
case IIO_PROXIMITY:
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
if (ret < 0)
@@ -1140,7 +1212,7 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev,

out:
mutex_unlock(&data->vcnl4000_lock);
- data->chip_spec->set_power_state(data, data->ps_int != 0);
+ data->chip_spec->set_power_state(data, data->ps_int || data->als_int);

return ret;
}
@@ -1171,6 +1243,22 @@ static irqreturn_t vcnl4040_irq_thread(int irq, void *p)
iio_get_time_ns(indio_dev));
}

+ if (ret & VCNL4040_ALS_FALLING) {
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ iio_get_time_ns(indio_dev));
+ }
+
+ if (ret & VCNL4040_ALS_RISING) {
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ iio_get_time_ns(indio_dev));
+ }
+
return IRQ_HANDLED;
}

@@ -1393,6 +1481,8 @@ static const struct iio_chan_spec vcnl4040_channels[] = {
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_INT_TIME),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME),
+ .event_spec = vcnl4000_event_spec,
+ .num_event_specs = ARRAY_SIZE(vcnl4000_event_spec),
}, {
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
--
2.30.2


2023-06-17 20:36:59

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH v6 0/8] iio: light: vcnl4000: Add features for vncl4040/4200

On Tue, 13 Jun 2023 15:50:16 +0200
Astrid Rost <[email protected]> wrote:

> Add a more complete support for vncl4040 and vcnl4200, which allows to
> change the distance of proximity detection and interrupt support for the
> illuminance sensor.
Series applied to the togreg branch of iio.git and pushed out as testing
for 0-day to see if it can find anything we missed.

Note that I don't plan another pull request this cycle, so this is now
material for 6.6 and I'll be rebasing the tree after 6.5-rc1 is out.

Thanks,

Jonathan

>
> Proximity functionality:
> - Interrupt support (new on vcnl4200).
>
> Proximity reduce the amount of interrupts:
> - Adaptable integration time (new on vcnl4200) - the sampling rate
> changes according to this value.
> - Period - interrupt is asserted if the value is above or
> below a certain threshold.
>
> Proximity change the activity distance:
> - Oversampling ratio - Amount of LED pulses per measured raw value.
> - Calibration bias - LED current calibration of the sensor.
>
> Illuminance functionality:
> - Interrupt support.
>
> Illuminance reduce the amount of interrupts:
> - Adaptable integration time - the sampling rate and scale changes
> according to this value.
> - Period – interrupt is asserted if the value is above or
> below a certain threshold.
>
> changes v2:
> - [PATCH v2 3/7] Fixed calculation of al_scale.
> Fix the value of vcnl4040 according to the data-sheet.
> Use div_u64 for the division.
> scription for the branch
>
> changes v3:
> - [PATCH v3 1-3/7] Add differences between the chips as variables in
> chip-spec.
> - [PATCH v3 4/7] Changed commit message.
> - [PATCH v3 5/7] Use period instead of debounce time. This causes some
> calculations as the period is a time and the chip allows to set a certain
> amount of measurements above/below the threshold, before throwing an
> interrupt.
> - [PATCH v3 6/7] Changed commit message.
>
> changes v4:
> - [PATCH v3 1-3/7] Fix setting correct als_it for vcnl4040.
> - [PATCH v3 5/7] Use MICRO macro.
> Fix values greater than 1 s for the proximity period.
>
> changes v5:
> [PATCH v5 2/7]:
> - Calculate ps_it from ps_it_times by usinh NSEC_PER_USEC.
> [PATCH v5 3/7]:
> - Calculate als_it from ps_it_times by using NSEC_PER_USEC.
> - Store scale step factor in chip_spec.
> - Fixes sampling_rate to ns + 20 %.
> [PATCH v5 3/7 - 7/7]
> - Changed formatting.
> - Changed some variable names.
>
> - [PATCH v3 4/7] Changed commit message.
> - [PATCH v3 5/7] Use period instead of debounce time. This causes some
> calculations as the period is a time and the chip allows to set a certain
> amount of measurements above/below the threshold, before throwing an
> interrupt.
> - [PATCH v3 6/7] Changed commit message.
>
> changes v4:
> - [PATCH v3 1-3/7] Fix setting correct als_it for vcnl4040.
> - [PATCH v3 5/7] Use MICRO macro.
> Fix values greater than 1 s for the proximity period.
>
> changes v5:
> [PATCH v5 2/7]:
> - Calculate ps_it from ps_it_times by usinh NSEC_PER_USEC.
> [PATCH v5 3/7]:
> - Calculate als_it from ps_it_times by using NSEC_PER_USEC.
> - Store scale step factor in chip_spec.
> - Fixes sampling_rate to ns + 20 %.
> [PATCH v5 3/7 - 7/7]
> - Changed formatting.
> - Changed some variable names.
>
> changes v6:
> Added [PATCH v6 3/8]:
> - Add switch case for IIO_PROXIMITY check.
> [PATCH v5 1/7 - 7/7]
> - Changed formatting.
> [PATCH v5 3/7, 5/7, 6/7, 7/7]
> - Changed loop.
> - Changed some variable names.
>
> Astrid Rost (8):
> [PATCH v6 1/8] iio: light: vcnl4000: Add proximity irq for vcnl4200
> [PATCH v6 2/8] iio: light: vcnl4000: Add proximity ps_it for vcnl4200
> [PATCH v6 3/8] iio: light: vcnl4000: Check type with switch case
> [PATCH v6 4/8] iio: light: vcnl4000: Add als_it for vcnl4040/4200
> [PATCH v6 5/8] iio: light: vcnl4000: add illuminance irq vcnl4040/4200
> [PATCH v6 6/8] iio: light: vcnl4000: Add period for vcnl4040/4200
> [PATCH v6 7/8] iio: light: vcnl4000: Add oversampling_ratio for 4040/4200
> [PATCH v6 8/8] iio: light: vcnl4000: Add calibration bias for 4040/4200
>
> drivers/iio/light/vcnl4000.c | 710 +++++++++++++++++++++++++++++++----
> 1 file changed, 643 insertions(+), 67 deletions(-)
>