Skip to content

Commit

Permalink
iio: light: vcnl4000: add illuminance irq vcnl4040/4200
Browse files Browse the repository at this point in the history
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 <astrid.rost@axis.com>
Link: https://lore.kernel.org/r/20230613135025.2596641-6-astrid.rost@axis.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
  • Loading branch information
Astrid Rost authored and jic23 committed Jul 20, 2023
1 parent fea2c97 commit bc292aa
Showing 1 changed file with 92 additions and 2 deletions.
94 changes: 92 additions & 2 deletions drivers/iio/light/vcnl4000.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) |
Expand Down

0 comments on commit bc292aa

Please sign in to comment.