Skip to content

Commit bc292aa

Browse files
Astrid Rostjic23
Astrid Rost
authored andcommitted
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]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jonathan Cameron <[email protected]>
1 parent fea2c97 commit bc292aa

File tree

1 file changed

+92
-2
lines changed

1 file changed

+92
-2
lines changed

drivers/iio/light/vcnl4000.c

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@
6262
#define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */
6363
#define VCNL4040_PS_THDL_LM 0x06 /* Proximity threshold low */
6464
#define VCNL4040_PS_THDH_LM 0x07 /* Proximity threshold high */
65+
#define VCNL4040_ALS_THDL_LM 0x02 /* Ambient light threshold low */
66+
#define VCNL4040_ALS_THDH_LM 0x01 /* Ambient light threshold high */
6567
#define VCNL4200_PS_DATA 0x08 /* Proximity data */
6668
#define VCNL4200_AL_DATA 0x09 /* Ambient light data */
6769
#define VCNL4040_INT_FLAGS 0x0b /* Interrupt register */
@@ -81,11 +83,14 @@
8183

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

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

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

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

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

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

932939
switch (chan->type) {
940+
case IIO_LIGHT:
941+
switch (info) {
942+
case IIO_EV_INFO_VALUE:
943+
switch (dir) {
944+
case IIO_EV_DIR_RISING:
945+
ret = i2c_smbus_read_word_data(data->client,
946+
VCNL4040_ALS_THDH_LM);
947+
break;
948+
case IIO_EV_DIR_FALLING:
949+
ret = i2c_smbus_read_word_data(data->client,
950+
VCNL4040_ALS_THDL_LM);
951+
break;
952+
default:
953+
return -EINVAL;
954+
}
955+
break;
956+
default:
957+
return -EINVAL;
958+
}
959+
break;
933960
case IIO_PROXIMITY:
934961
switch (info) {
935962
case IIO_EV_INFO_VALUE:
@@ -970,6 +997,28 @@ static int vcnl4040_write_event(struct iio_dev *indio_dev,
970997
struct vcnl4000_data *data = iio_priv(indio_dev);
971998

972999
switch (chan->type) {
1000+
case IIO_LIGHT:
1001+
switch (info) {
1002+
case IIO_EV_INFO_VALUE:
1003+
switch (dir) {
1004+
case IIO_EV_DIR_RISING:
1005+
ret = i2c_smbus_write_word_data(data->client,
1006+
VCNL4040_ALS_THDH_LM,
1007+
val);
1008+
break;
1009+
case IIO_EV_DIR_FALLING:
1010+
ret = i2c_smbus_write_word_data(data->client,
1011+
VCNL4040_ALS_THDL_LM,
1012+
val);
1013+
break;
1014+
default:
1015+
return -EINVAL;
1016+
}
1017+
break;
1018+
default:
1019+
return -EINVAL;
1020+
}
1021+
break;
9731022
case IIO_PROXIMITY:
9741023
switch (info) {
9751024
case IIO_EV_INFO_VALUE:
@@ -1091,6 +1140,14 @@ static int vcnl4040_read_event_config(struct iio_dev *indio_dev,
10911140
struct vcnl4000_data *data = iio_priv(indio_dev);
10921141

10931142
switch (chan->type) {
1143+
case IIO_LIGHT:
1144+
ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
1145+
if (ret < 0)
1146+
return ret;
1147+
1148+
data->als_int = FIELD_GET(VCNL4040_ALS_CONF_INT_EN, ret);
1149+
1150+
return data->als_int;
10941151
case IIO_PROXIMITY:
10951152
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
10961153
if (ret < 0)
@@ -1118,6 +1175,21 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev,
11181175
mutex_lock(&data->vcnl4000_lock);
11191176

11201177
switch (chan->type) {
1178+
case IIO_LIGHT:
1179+
ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
1180+
if (ret < 0)
1181+
goto out;
1182+
1183+
mask = VCNL4040_ALS_CONF_INT_EN;
1184+
if (state)
1185+
val = (ret | mask);
1186+
else
1187+
val = (ret & ~mask);
1188+
1189+
data->als_int = FIELD_GET(VCNL4040_ALS_CONF_INT_EN, val);
1190+
ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF,
1191+
val);
1192+
break;
11211193
case IIO_PROXIMITY:
11221194
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
11231195
if (ret < 0)
@@ -1140,7 +1212,7 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev,
11401212

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

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

1246+
if (ret & VCNL4040_ALS_FALLING) {
1247+
iio_push_event(indio_dev,
1248+
IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
1249+
IIO_EV_TYPE_THRESH,
1250+
IIO_EV_DIR_FALLING),
1251+
iio_get_time_ns(indio_dev));
1252+
}
1253+
1254+
if (ret & VCNL4040_ALS_RISING) {
1255+
iio_push_event(indio_dev,
1256+
IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
1257+
IIO_EV_TYPE_THRESH,
1258+
IIO_EV_DIR_RISING),
1259+
iio_get_time_ns(indio_dev));
1260+
}
1261+
11741262
return IRQ_HANDLED;
11751263
}
11761264

@@ -1393,6 +1481,8 @@ static const struct iio_chan_spec vcnl4040_channels[] = {
13931481
BIT(IIO_CHAN_INFO_SCALE) |
13941482
BIT(IIO_CHAN_INFO_INT_TIME),
13951483
.info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME),
1484+
.event_spec = vcnl4000_event_spec,
1485+
.num_event_specs = ARRAY_SIZE(vcnl4000_event_spec),
13961486
}, {
13971487
.type = IIO_PROXIMITY,
13981488
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |

0 commit comments

Comments
 (0)