1 // SPDX-License-Identifier: GPL-2.0-only
3 * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4040/4200 combined ambient
4 * light and proximity sensor
6 * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
7 * Copyright 2019 Pursim SPC
10 * VCNL4000/10/20 (7-bit I2C slave address 0x13)
11 * VCNL4040 (7-bit I2C slave address 0x60)
12 * VCNL4200 (7-bit I2C slave address 0x51)
15 * allow to adjust IR current
16 * proximity threshold and event handling
17 * periodic ALS/proximity measurement (VCNL4010/20)
18 * interrupts (VCNL4010/20/40, VCNL4200)
21 #include <linux/module.h>
22 #include <linux/i2c.h>
23 #include <linux/err.h>
24 #include <linux/delay.h>
25 #include <linux/pm_runtime.h>
27 #include <linux/iio/iio.h>
28 #include <linux/iio/sysfs.h>
30 #define VCNL4000_DRV_NAME "vcnl4000"
31 #define VCNL4000_PROD_ID 0x01
32 #define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */
33 #define VCNL4040_PROD_ID 0x86
34 #define VCNL4200_PROD_ID 0x58
36 #define VCNL4000_COMMAND 0x80 /* Command register */
37 #define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */
38 #define VCNL4000_LED_CURRENT 0x83 /* IR LED current for proximity mode */
39 #define VCNL4000_AL_PARAM 0x84 /* Ambient light parameter register */
40 #define VCNL4000_AL_RESULT_HI 0x85 /* Ambient light result register, MSB */
41 #define VCNL4000_AL_RESULT_LO 0x86 /* Ambient light result register, LSB */
42 #define VCNL4000_PS_RESULT_HI 0x87 /* Proximity result register, MSB */
43 #define VCNL4000_PS_RESULT_LO 0x88 /* Proximity result register, LSB */
44 #define VCNL4000_PS_MEAS_FREQ 0x89 /* Proximity test signal frequency */
45 #define VCNL4000_PS_MOD_ADJ 0x8a /* Proximity modulator timing adjustment */
47 #define VCNL4200_AL_CONF 0x00 /* Ambient light configuration */
48 #define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */
49 #define VCNL4200_PS_DATA 0x08 /* Proximity data */
50 #define VCNL4200_AL_DATA 0x09 /* Ambient light data */
51 #define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */
53 #define VCNL4040_DEV_ID 0x0c /* Device ID and version */
55 /* Bit masks for COMMAND register */
56 #define VCNL4000_AL_RDY BIT(6) /* ALS data ready? */
57 #define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */
58 #define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */
59 #define VCNL4000_PS_OD BIT(3) /* start on-demand proximity measurement */
61 #define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */
63 enum vcnl4000_device_ids
{
70 struct vcnl4200_channel
{
72 ktime_t last_measurement
;
73 ktime_t sampling_rate
;
77 struct vcnl4000_data
{
78 struct i2c_client
*client
;
79 enum vcnl4000_device_ids id
;
82 const struct vcnl4000_chip_spec
*chip_spec
;
83 struct mutex vcnl4000_lock
;
84 struct vcnl4200_channel vcnl4200_al
;
85 struct vcnl4200_channel vcnl4200_ps
;
88 struct vcnl4000_chip_spec
{
90 int (*init
)(struct vcnl4000_data
*data
);
91 int (*measure_light
)(struct vcnl4000_data
*data
, int *val
);
92 int (*measure_proximity
)(struct vcnl4000_data
*data
, int *val
);
93 int (*set_power_state
)(struct vcnl4000_data
*data
, bool on
);
96 static const struct i2c_device_id vcnl4000_id
[] = {
97 { "vcnl4000", VCNL4000
},
98 { "vcnl4010", VCNL4010
},
99 { "vcnl4020", VCNL4010
},
100 { "vcnl4040", VCNL4040
},
101 { "vcnl4200", VCNL4200
},
104 MODULE_DEVICE_TABLE(i2c
, vcnl4000_id
);
106 static int vcnl4000_set_power_state(struct vcnl4000_data
*data
, bool on
)
112 static int vcnl4000_init(struct vcnl4000_data
*data
)
116 ret
= i2c_smbus_read_byte_data(data
->client
, VCNL4000_PROD_REV
);
122 case VCNL4000_PROD_ID
:
123 if (data
->id
!= VCNL4000
)
124 dev_warn(&data
->client
->dev
,
125 "wrong device id, use vcnl4000");
127 case VCNL4010_PROD_ID
:
128 if (data
->id
!= VCNL4010
)
129 dev_warn(&data
->client
->dev
,
130 "wrong device id, use vcnl4010/4020");
136 data
->rev
= ret
& 0xf;
137 data
->al_scale
= 250000;
138 mutex_init(&data
->vcnl4000_lock
);
140 return data
->chip_spec
->set_power_state(data
, true);
143 static int vcnl4200_set_power_state(struct vcnl4000_data
*data
, bool on
)
145 u16 val
= on
? 0 /* power on */ : 1 /* shut down */;
148 ret
= i2c_smbus_write_word_data(data
->client
, VCNL4200_AL_CONF
, val
);
152 ret
= i2c_smbus_write_word_data(data
->client
, VCNL4200_PS_CONF1
, val
);
157 /* Wait at least one integration cycle before fetching data */
158 data
->vcnl4200_al
.last_measurement
= ktime_get();
159 data
->vcnl4200_ps
.last_measurement
= ktime_get();
165 static int vcnl4200_init(struct vcnl4000_data
*data
)
169 ret
= i2c_smbus_read_word_data(data
->client
, VCNL4200_DEV_ID
);
175 if (id
!= VCNL4200_PROD_ID
) {
176 ret
= i2c_smbus_read_word_data(data
->client
, VCNL4040_DEV_ID
);
182 if (id
!= VCNL4040_PROD_ID
)
186 dev_dbg(&data
->client
->dev
, "device id 0x%x", id
);
188 data
->rev
= (ret
>> 8) & 0xf;
190 data
->vcnl4200_al
.reg
= VCNL4200_AL_DATA
;
191 data
->vcnl4200_ps
.reg
= VCNL4200_PS_DATA
;
193 case VCNL4200_PROD_ID
:
194 /* Default wait time is 50ms, add 20% tolerance. */
195 data
->vcnl4200_al
.sampling_rate
= ktime_set(0, 60000 * 1000);
196 /* Default wait time is 4.8ms, add 20% tolerance. */
197 data
->vcnl4200_ps
.sampling_rate
= ktime_set(0, 5760 * 1000);
198 data
->al_scale
= 24000;
200 case VCNL4040_PROD_ID
:
201 /* Default wait time is 80ms, add 20% tolerance. */
202 data
->vcnl4200_al
.sampling_rate
= ktime_set(0, 96000 * 1000);
203 /* Default wait time is 5ms, add 20% tolerance. */
204 data
->vcnl4200_ps
.sampling_rate
= ktime_set(0, 6000 * 1000);
205 data
->al_scale
= 120000;
208 mutex_init(&data
->vcnl4200_al
.lock
);
209 mutex_init(&data
->vcnl4200_ps
.lock
);
211 ret
= data
->chip_spec
->set_power_state(data
, true);
218 static int vcnl4000_measure(struct vcnl4000_data
*data
, u8 req_mask
,
219 u8 rdy_mask
, u8 data_reg
, int *val
)
224 mutex_lock(&data
->vcnl4000_lock
);
226 ret
= i2c_smbus_write_byte_data(data
->client
, VCNL4000_COMMAND
,
231 /* wait for data to become ready */
233 ret
= i2c_smbus_read_byte_data(data
->client
, VCNL4000_COMMAND
);
238 msleep(20); /* measurement takes up to 100 ms */
242 dev_err(&data
->client
->dev
,
243 "vcnl4000_measure() failed, data not ready\n");
248 ret
= i2c_smbus_read_word_swapped(data
->client
, data_reg
);
252 mutex_unlock(&data
->vcnl4000_lock
);
258 mutex_unlock(&data
->vcnl4000_lock
);
262 static int vcnl4200_measure(struct vcnl4000_data
*data
,
263 struct vcnl4200_channel
*chan
, int *val
)
267 ktime_t next_measurement
;
269 mutex_lock(&chan
->lock
);
271 next_measurement
= ktime_add(chan
->last_measurement
,
272 chan
->sampling_rate
);
273 delta
= ktime_us_delta(next_measurement
, ktime_get());
275 usleep_range(delta
, delta
+ 500);
276 chan
->last_measurement
= ktime_get();
278 mutex_unlock(&chan
->lock
);
280 ret
= i2c_smbus_read_word_data(data
->client
, chan
->reg
);
289 static int vcnl4000_measure_light(struct vcnl4000_data
*data
, int *val
)
291 return vcnl4000_measure(data
,
292 VCNL4000_AL_OD
, VCNL4000_AL_RDY
,
293 VCNL4000_AL_RESULT_HI
, val
);
296 static int vcnl4200_measure_light(struct vcnl4000_data
*data
, int *val
)
298 return vcnl4200_measure(data
, &data
->vcnl4200_al
, val
);
301 static int vcnl4000_measure_proximity(struct vcnl4000_data
*data
, int *val
)
303 return vcnl4000_measure(data
,
304 VCNL4000_PS_OD
, VCNL4000_PS_RDY
,
305 VCNL4000_PS_RESULT_HI
, val
);
308 static int vcnl4200_measure_proximity(struct vcnl4000_data
*data
, int *val
)
310 return vcnl4200_measure(data
, &data
->vcnl4200_ps
, val
);
313 static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg
[] = {
316 .init
= vcnl4000_init
,
317 .measure_light
= vcnl4000_measure_light
,
318 .measure_proximity
= vcnl4000_measure_proximity
,
319 .set_power_state
= vcnl4000_set_power_state
,
322 .prod
= "VCNL4010/4020",
323 .init
= vcnl4000_init
,
324 .measure_light
= vcnl4000_measure_light
,
325 .measure_proximity
= vcnl4000_measure_proximity
,
326 .set_power_state
= vcnl4000_set_power_state
,
330 .init
= vcnl4200_init
,
331 .measure_light
= vcnl4200_measure_light
,
332 .measure_proximity
= vcnl4200_measure_proximity
,
333 .set_power_state
= vcnl4200_set_power_state
,
337 .init
= vcnl4200_init
,
338 .measure_light
= vcnl4200_measure_light
,
339 .measure_proximity
= vcnl4200_measure_proximity
,
340 .set_power_state
= vcnl4200_set_power_state
,
344 static const struct iio_chan_spec vcnl4000_channels
[] = {
347 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
) |
348 BIT(IIO_CHAN_INFO_SCALE
),
350 .type
= IIO_PROXIMITY
,
351 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
),
355 static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data
*data
, bool on
)
357 struct device
*dev
= &data
->client
->dev
;
361 ret
= pm_runtime_get_sync(dev
);
363 pm_runtime_put_noidle(dev
);
365 pm_runtime_mark_last_busy(dev
);
366 ret
= pm_runtime_put_autosuspend(dev
);
372 static int vcnl4000_read_raw(struct iio_dev
*indio_dev
,
373 struct iio_chan_spec
const *chan
,
374 int *val
, int *val2
, long mask
)
377 struct vcnl4000_data
*data
= iio_priv(indio_dev
);
380 case IIO_CHAN_INFO_RAW
:
381 ret
= vcnl4000_set_pm_runtime_state(data
, true);
385 switch (chan
->type
) {
387 ret
= data
->chip_spec
->measure_light(data
, val
);
392 ret
= data
->chip_spec
->measure_proximity(data
, val
);
399 vcnl4000_set_pm_runtime_state(data
, false);
401 case IIO_CHAN_INFO_SCALE
:
402 if (chan
->type
!= IIO_LIGHT
)
406 *val2
= data
->al_scale
;
407 return IIO_VAL_INT_PLUS_MICRO
;
413 static const struct iio_info vcnl4000_info
= {
414 .read_raw
= vcnl4000_read_raw
,
417 static int vcnl4000_probe(struct i2c_client
*client
,
418 const struct i2c_device_id
*id
)
420 struct vcnl4000_data
*data
;
421 struct iio_dev
*indio_dev
;
424 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*data
));
428 data
= iio_priv(indio_dev
);
429 i2c_set_clientdata(client
, indio_dev
);
430 data
->client
= client
;
431 data
->id
= id
->driver_data
;
432 data
->chip_spec
= &vcnl4000_chip_spec_cfg
[data
->id
];
434 ret
= data
->chip_spec
->init(data
);
438 dev_dbg(&client
->dev
, "%s Ambient light/proximity sensor, Rev: %02x\n",
439 data
->chip_spec
->prod
, data
->rev
);
441 indio_dev
->dev
.parent
= &client
->dev
;
442 indio_dev
->info
= &vcnl4000_info
;
443 indio_dev
->channels
= vcnl4000_channels
;
444 indio_dev
->num_channels
= ARRAY_SIZE(vcnl4000_channels
);
445 indio_dev
->name
= VCNL4000_DRV_NAME
;
446 indio_dev
->modes
= INDIO_DIRECT_MODE
;
448 ret
= pm_runtime_set_active(&client
->dev
);
452 ret
= iio_device_register(indio_dev
);
456 pm_runtime_enable(&client
->dev
);
457 pm_runtime_set_autosuspend_delay(&client
->dev
, VCNL4000_SLEEP_DELAY_MS
);
458 pm_runtime_use_autosuspend(&client
->dev
);
462 data
->chip_spec
->set_power_state(data
, false);
466 static const struct of_device_id vcnl_4000_of_match
[] = {
468 .compatible
= "vishay,vcnl4000",
469 .data
= (void *)VCNL4000
,
472 .compatible
= "vishay,vcnl4010",
473 .data
= (void *)VCNL4010
,
476 .compatible
= "vishay,vcnl4020",
477 .data
= (void *)VCNL4010
,
480 .compatible
= "vishay,vcnl4040",
481 .data
= (void *)VCNL4040
,
484 .compatible
= "vishay,vcnl4200",
485 .data
= (void *)VCNL4200
,
489 MODULE_DEVICE_TABLE(of
, vcnl_4000_of_match
);
491 static int vcnl4000_remove(struct i2c_client
*client
)
493 struct iio_dev
*indio_dev
= i2c_get_clientdata(client
);
494 struct vcnl4000_data
*data
= iio_priv(indio_dev
);
496 pm_runtime_dont_use_autosuspend(&client
->dev
);
497 pm_runtime_disable(&client
->dev
);
498 iio_device_unregister(indio_dev
);
499 pm_runtime_set_suspended(&client
->dev
);
501 return data
->chip_spec
->set_power_state(data
, false);
504 static int __maybe_unused
vcnl4000_runtime_suspend(struct device
*dev
)
506 struct iio_dev
*indio_dev
= i2c_get_clientdata(to_i2c_client(dev
));
507 struct vcnl4000_data
*data
= iio_priv(indio_dev
);
509 return data
->chip_spec
->set_power_state(data
, false);
512 static int __maybe_unused
vcnl4000_runtime_resume(struct device
*dev
)
514 struct iio_dev
*indio_dev
= i2c_get_clientdata(to_i2c_client(dev
));
515 struct vcnl4000_data
*data
= iio_priv(indio_dev
);
517 return data
->chip_spec
->set_power_state(data
, true);
520 static const struct dev_pm_ops vcnl4000_pm_ops
= {
521 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend
,
522 pm_runtime_force_resume
)
523 SET_RUNTIME_PM_OPS(vcnl4000_runtime_suspend
,
524 vcnl4000_runtime_resume
, NULL
)
527 static struct i2c_driver vcnl4000_driver
= {
529 .name
= VCNL4000_DRV_NAME
,
530 .pm
= &vcnl4000_pm_ops
,
531 .of_match_table
= vcnl_4000_of_match
,
533 .probe
= vcnl4000_probe
,
534 .id_table
= vcnl4000_id
,
535 .remove
= vcnl4000_remove
,
538 module_i2c_driver(vcnl4000_driver
);
540 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
541 MODULE_DESCRIPTION("Vishay VCNL4000 proximity/ambient light sensor driver");
542 MODULE_LICENSE("GPL");