forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f70575805708cabdedea7498aaa3f710fde4d920
kernel/drivers/iio/light/vcnl4000.c
....@@ -1,47 +1,61 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
2
- * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4200 combined ambient
3
+ * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4040/4200 combined ambient
34 * light and proximity sensor
45 *
56 * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
6
- *
7
- * This file is subject to the terms and conditions of version 2 of
8
- * the GNU General Public License. See the file COPYING in the main
9
- * directory of this archive for more details.
7
+ * Copyright 2019 Pursim SPC
8
+ * Copyright 2020 Mathieu Othacehe <m.othacehe@gmail.com>
109 *
1110 * IIO driver for:
1211 * VCNL4000/10/20 (7-bit I2C slave address 0x13)
12
+ * VCNL4040 (7-bit I2C slave address 0x60)
1313 * VCNL4200 (7-bit I2C slave address 0x51)
1414 *
1515 * TODO:
1616 * allow to adjust IR current
17
- * proximity threshold and event handling
18
- * periodic ALS/proximity measurement (VCNL4010/20)
19
- * interrupts (VCNL4010/20, VCNL4200)
17
+ * interrupts (VCNL4040, VCNL4200)
2018 */
2119
2220 #include <linux/module.h>
2321 #include <linux/i2c.h>
2422 #include <linux/err.h>
2523 #include <linux/delay.h>
24
+#include <linux/pm_runtime.h>
25
+#include <linux/interrupt.h>
2626
27
+#include <linux/iio/buffer.h>
28
+#include <linux/iio/events.h>
2729 #include <linux/iio/iio.h>
2830 #include <linux/iio/sysfs.h>
31
+#include <linux/iio/trigger.h>
32
+#include <linux/iio/trigger_consumer.h>
33
+#include <linux/iio/triggered_buffer.h>
2934
3035 #define VCNL4000_DRV_NAME "vcnl4000"
3136 #define VCNL4000_PROD_ID 0x01
3237 #define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */
38
+#define VCNL4040_PROD_ID 0x86
3339 #define VCNL4200_PROD_ID 0x58
3440
3541 #define VCNL4000_COMMAND 0x80 /* Command register */
3642 #define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */
43
+#define VCNL4010_PROX_RATE 0x82 /* Proximity rate */
3744 #define VCNL4000_LED_CURRENT 0x83 /* IR LED current for proximity mode */
3845 #define VCNL4000_AL_PARAM 0x84 /* Ambient light parameter register */
46
+#define VCNL4010_ALS_PARAM 0x84 /* ALS rate */
3947 #define VCNL4000_AL_RESULT_HI 0x85 /* Ambient light result register, MSB */
4048 #define VCNL4000_AL_RESULT_LO 0x86 /* Ambient light result register, LSB */
4149 #define VCNL4000_PS_RESULT_HI 0x87 /* Proximity result register, MSB */
4250 #define VCNL4000_PS_RESULT_LO 0x88 /* Proximity result register, LSB */
4351 #define VCNL4000_PS_MEAS_FREQ 0x89 /* Proximity test signal frequency */
52
+#define VCNL4010_INT_CTRL 0x89 /* Interrupt control */
4453 #define VCNL4000_PS_MOD_ADJ 0x8a /* Proximity modulator timing adjustment */
54
+#define VCNL4010_LOW_THR_HI 0x8a /* Low threshold, MSB */
55
+#define VCNL4010_LOW_THR_LO 0x8b /* Low threshold, LSB */
56
+#define VCNL4010_HIGH_THR_HI 0x8c /* High threshold, MSB */
57
+#define VCNL4010_HIGH_THR_LO 0x8d /* High threshold, LSB */
58
+#define VCNL4010_ISR 0x8e /* Interrupt status */
4559
4660 #define VCNL4200_AL_CONF 0x00 /* Ambient light configuration */
4761 #define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */
....@@ -49,15 +63,50 @@
4963 #define VCNL4200_AL_DATA 0x09 /* Ambient light data */
5064 #define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */
5165
66
+#define VCNL4040_DEV_ID 0x0c /* Device ID and version */
67
+
5268 /* Bit masks for COMMAND register */
5369 #define VCNL4000_AL_RDY BIT(6) /* ALS data ready? */
5470 #define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */
5571 #define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */
5672 #define VCNL4000_PS_OD BIT(3) /* start on-demand proximity measurement */
73
+#define VCNL4000_ALS_EN BIT(2) /* start ALS measurement */
74
+#define VCNL4000_PROX_EN BIT(1) /* start proximity measurement */
75
+#define VCNL4000_SELF_TIMED_EN BIT(0) /* start self-timed measurement */
76
+
77
+/* Bit masks for interrupt registers. */
78
+#define VCNL4010_INT_THR_SEL BIT(0) /* Select threshold interrupt source */
79
+#define VCNL4010_INT_THR_EN BIT(1) /* Threshold interrupt type */
80
+#define VCNL4010_INT_ALS_EN BIT(2) /* Enable on ALS data ready */
81
+#define VCNL4010_INT_PROX_EN BIT(3) /* Enable on proximity data ready */
82
+
83
+#define VCNL4010_INT_THR_HIGH 0 /* High threshold exceeded */
84
+#define VCNL4010_INT_THR_LOW 1 /* Low threshold exceeded */
85
+#define VCNL4010_INT_ALS 2 /* ALS data ready */
86
+#define VCNL4010_INT_PROXIMITY 3 /* Proximity data ready */
87
+
88
+#define VCNL4010_INT_THR \
89
+ (BIT(VCNL4010_INT_THR_LOW) | BIT(VCNL4010_INT_THR_HIGH))
90
+#define VCNL4010_INT_DRDY \
91
+ (BIT(VCNL4010_INT_PROXIMITY) | BIT(VCNL4010_INT_ALS))
92
+
93
+static const int vcnl4010_prox_sampling_frequency[][2] = {
94
+ {1, 950000},
95
+ {3, 906250},
96
+ {7, 812500},
97
+ {16, 625000},
98
+ {31, 250000},
99
+ {62, 500000},
100
+ {125, 0},
101
+ {250, 0},
102
+};
103
+
104
+#define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */
57105
58106 enum vcnl4000_device_ids {
59107 VCNL4000,
60108 VCNL4010,
109
+ VCNL4040,
61110 VCNL4200,
62111 };
63112
....@@ -77,23 +126,36 @@
77126 struct mutex vcnl4000_lock;
78127 struct vcnl4200_channel vcnl4200_al;
79128 struct vcnl4200_channel vcnl4200_ps;
129
+ uint32_t near_level;
80130 };
81131
82132 struct vcnl4000_chip_spec {
83133 const char *prod;
134
+ struct iio_chan_spec const *channels;
135
+ const int num_channels;
136
+ const struct iio_info *info;
137
+ bool irq_support;
84138 int (*init)(struct vcnl4000_data *data);
85139 int (*measure_light)(struct vcnl4000_data *data, int *val);
86140 int (*measure_proximity)(struct vcnl4000_data *data, int *val);
141
+ int (*set_power_state)(struct vcnl4000_data *data, bool on);
87142 };
88143
89144 static const struct i2c_device_id vcnl4000_id[] = {
90145 { "vcnl4000", VCNL4000 },
91146 { "vcnl4010", VCNL4010 },
92147 { "vcnl4020", VCNL4010 },
148
+ { "vcnl4040", VCNL4040 },
93149 { "vcnl4200", VCNL4200 },
94150 { }
95151 };
96152 MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
153
+
154
+static int vcnl4000_set_power_state(struct vcnl4000_data *data, bool on)
155
+{
156
+ /* no suspend op */
157
+ return 0;
158
+}
97159
98160 static int vcnl4000_init(struct vcnl4000_data *data)
99161 {
....@@ -123,44 +185,104 @@
123185 data->al_scale = 250000;
124186 mutex_init(&data->vcnl4000_lock);
125187
126
- return 0;
188
+ return data->chip_spec->set_power_state(data, true);
127189 };
190
+
191
+static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
192
+{
193
+ u16 val = on ? 0 /* power on */ : 1 /* shut down */;
194
+ int ret;
195
+
196
+ ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, val);
197
+ if (ret < 0)
198
+ return ret;
199
+
200
+ ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val);
201
+ if (ret < 0)
202
+ return ret;
203
+
204
+ if (on) {
205
+ /* Wait at least one integration cycle before fetching data */
206
+ data->vcnl4200_al.last_measurement = ktime_get();
207
+ data->vcnl4200_ps.last_measurement = ktime_get();
208
+ }
209
+
210
+ return 0;
211
+}
128212
129213 static int vcnl4200_init(struct vcnl4000_data *data)
130214 {
131
- int ret;
215
+ int ret, id;
132216
133217 ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
134218 if (ret < 0)
135219 return ret;
136220
137
- if ((ret & 0xff) != VCNL4200_PROD_ID)
138
- return -ENODEV;
221
+ id = ret & 0xff;
222
+
223
+ if (id != VCNL4200_PROD_ID) {
224
+ ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID);
225
+ if (ret < 0)
226
+ return ret;
227
+
228
+ id = ret & 0xff;
229
+
230
+ if (id != VCNL4040_PROD_ID)
231
+ return -ENODEV;
232
+ }
233
+
234
+ dev_dbg(&data->client->dev, "device id 0x%x", id);
139235
140236 data->rev = (ret >> 8) & 0xf;
141237
142
- /* Set defaults and enable both channels */
143
- ret = i2c_smbus_write_byte_data(data->client, VCNL4200_AL_CONF, 0x00);
144
- if (ret < 0)
145
- return ret;
146
- ret = i2c_smbus_write_byte_data(data->client, VCNL4200_PS_CONF1, 0x00);
147
- if (ret < 0)
148
- return ret;
149
-
150
- data->al_scale = 24000;
151238 data->vcnl4200_al.reg = VCNL4200_AL_DATA;
152239 data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
153
- /* Default wait time is 50ms, add 20% tolerance. */
154
- data->vcnl4200_al.sampling_rate = ktime_set(0, 60000 * 1000);
155
- /* Default wait time is 4.8ms, add 20% tolerance. */
156
- data->vcnl4200_ps.sampling_rate = ktime_set(0, 5760 * 1000);
157
- data->vcnl4200_al.last_measurement = ktime_set(0, 0);
158
- data->vcnl4200_ps.last_measurement = ktime_set(0, 0);
240
+ switch (id) {
241
+ case VCNL4200_PROD_ID:
242
+ /* Default wait time is 50ms, add 20% tolerance. */
243
+ data->vcnl4200_al.sampling_rate = ktime_set(0, 60000 * 1000);
244
+ /* Default wait time is 4.8ms, add 20% tolerance. */
245
+ data->vcnl4200_ps.sampling_rate = ktime_set(0, 5760 * 1000);
246
+ data->al_scale = 24000;
247
+ break;
248
+ case VCNL4040_PROD_ID:
249
+ /* Default wait time is 80ms, add 20% tolerance. */
250
+ data->vcnl4200_al.sampling_rate = ktime_set(0, 96000 * 1000);
251
+ /* Default wait time is 5ms, add 20% tolerance. */
252
+ data->vcnl4200_ps.sampling_rate = ktime_set(0, 6000 * 1000);
253
+ data->al_scale = 120000;
254
+ break;
255
+ }
159256 mutex_init(&data->vcnl4200_al.lock);
160257 mutex_init(&data->vcnl4200_ps.lock);
161258
259
+ ret = data->chip_spec->set_power_state(data, true);
260
+ if (ret < 0)
261
+ return ret;
262
+
162263 return 0;
163264 };
265
+
266
+static int vcnl4000_read_data(struct vcnl4000_data *data, u8 data_reg, int *val)
267
+{
268
+ s32 ret;
269
+
270
+ ret = i2c_smbus_read_word_swapped(data->client, data_reg);
271
+ if (ret < 0)
272
+ return ret;
273
+
274
+ *val = ret;
275
+ return 0;
276
+}
277
+
278
+static int vcnl4000_write_data(struct vcnl4000_data *data, u8 data_reg, int val)
279
+{
280
+ if (val > U16_MAX)
281
+ return -ERANGE;
282
+
283
+ return i2c_smbus_write_word_swapped(data->client, data_reg, val);
284
+}
285
+
164286
165287 static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
166288 u8 rdy_mask, u8 data_reg, int *val)
....@@ -192,12 +314,11 @@
192314 goto fail;
193315 }
194316
195
- ret = i2c_smbus_read_word_swapped(data->client, data_reg);
317
+ ret = vcnl4000_read_data(data, data_reg, val);
196318 if (ret < 0)
197319 goto fail;
198320
199321 mutex_unlock(&data->vcnl4000_lock);
200
- *val = ret;
201322
202323 return 0;
203324
....@@ -257,37 +378,51 @@
257378 return vcnl4200_measure(data, &data->vcnl4200_ps, val);
258379 }
259380
260
-static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
261
- [VCNL4000] = {
262
- .prod = "VCNL4000",
263
- .init = vcnl4000_init,
264
- .measure_light = vcnl4000_measure_light,
265
- .measure_proximity = vcnl4000_measure_proximity,
266
- },
267
- [VCNL4010] = {
268
- .prod = "VCNL4010/4020",
269
- .init = vcnl4000_init,
270
- .measure_light = vcnl4000_measure_light,
271
- .measure_proximity = vcnl4000_measure_proximity,
272
- },
273
- [VCNL4200] = {
274
- .prod = "VCNL4200",
275
- .init = vcnl4200_init,
276
- .measure_light = vcnl4200_measure_light,
277
- .measure_proximity = vcnl4200_measure_proximity,
278
- },
279
-};
381
+static int vcnl4010_read_proxy_samp_freq(struct vcnl4000_data *data, int *val,
382
+ int *val2)
383
+{
384
+ int ret;
280385
281
-static const struct iio_chan_spec vcnl4000_channels[] = {
282
- {
283
- .type = IIO_LIGHT,
284
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
285
- BIT(IIO_CHAN_INFO_SCALE),
286
- }, {
287
- .type = IIO_PROXIMITY,
288
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
386
+ ret = i2c_smbus_read_byte_data(data->client, VCNL4010_PROX_RATE);
387
+ if (ret < 0)
388
+ return ret;
389
+
390
+ if (ret >= ARRAY_SIZE(vcnl4010_prox_sampling_frequency))
391
+ return -EINVAL;
392
+
393
+ *val = vcnl4010_prox_sampling_frequency[ret][0];
394
+ *val2 = vcnl4010_prox_sampling_frequency[ret][1];
395
+
396
+ return 0;
397
+}
398
+
399
+static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data)
400
+{
401
+ int ret;
402
+
403
+ ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
404
+ if (ret < 0)
405
+ return false;
406
+
407
+ return !!(ret & VCNL4000_SELF_TIMED_EN);
408
+}
409
+
410
+static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
411
+{
412
+ struct device *dev = &data->client->dev;
413
+ int ret;
414
+
415
+ if (on) {
416
+ ret = pm_runtime_get_sync(dev);
417
+ if (ret < 0)
418
+ pm_runtime_put_noidle(dev);
419
+ } else {
420
+ pm_runtime_mark_last_busy(dev);
421
+ ret = pm_runtime_put_autosuspend(dev);
289422 }
290
-};
423
+
424
+ return ret;
425
+}
291426
292427 static int vcnl4000_read_raw(struct iio_dev *indio_dev,
293428 struct iio_chan_spec const *chan,
....@@ -298,20 +433,26 @@
298433
299434 switch (mask) {
300435 case IIO_CHAN_INFO_RAW:
436
+ ret = vcnl4000_set_pm_runtime_state(data, true);
437
+ if (ret < 0)
438
+ return ret;
439
+
301440 switch (chan->type) {
302441 case IIO_LIGHT:
303442 ret = data->chip_spec->measure_light(data, val);
304
- if (ret < 0)
305
- return ret;
306
- return IIO_VAL_INT;
443
+ if (!ret)
444
+ ret = IIO_VAL_INT;
445
+ break;
307446 case IIO_PROXIMITY:
308447 ret = data->chip_spec->measure_proximity(data, val);
309
- if (ret < 0)
310
- return ret;
311
- return IIO_VAL_INT;
448
+ if (!ret)
449
+ ret = IIO_VAL_INT;
450
+ break;
312451 default:
313
- return -EINVAL;
452
+ ret = -EINVAL;
314453 }
454
+ vcnl4000_set_pm_runtime_state(data, false);
455
+ return ret;
315456 case IIO_CHAN_INFO_SCALE:
316457 if (chan->type != IIO_LIGHT)
317458 return -EINVAL;
....@@ -324,9 +465,549 @@
324465 }
325466 }
326467
468
+static int vcnl4010_read_raw(struct iio_dev *indio_dev,
469
+ struct iio_chan_spec const *chan,
470
+ int *val, int *val2, long mask)
471
+{
472
+ int ret;
473
+ struct vcnl4000_data *data = iio_priv(indio_dev);
474
+
475
+ switch (mask) {
476
+ case IIO_CHAN_INFO_RAW:
477
+ case IIO_CHAN_INFO_SCALE:
478
+ ret = iio_device_claim_direct_mode(indio_dev);
479
+ if (ret)
480
+ return ret;
481
+
482
+ /* Protect against event capture. */
483
+ if (vcnl4010_is_in_periodic_mode(data)) {
484
+ ret = -EBUSY;
485
+ } else {
486
+ ret = vcnl4000_read_raw(indio_dev, chan, val, val2,
487
+ mask);
488
+ }
489
+
490
+ iio_device_release_direct_mode(indio_dev);
491
+ return ret;
492
+ case IIO_CHAN_INFO_SAMP_FREQ:
493
+ switch (chan->type) {
494
+ case IIO_PROXIMITY:
495
+ ret = vcnl4010_read_proxy_samp_freq(data, val, val2);
496
+ if (ret < 0)
497
+ return ret;
498
+ return IIO_VAL_INT_PLUS_MICRO;
499
+ default:
500
+ return -EINVAL;
501
+ }
502
+ default:
503
+ return -EINVAL;
504
+ }
505
+}
506
+
507
+static int vcnl4010_read_avail(struct iio_dev *indio_dev,
508
+ struct iio_chan_spec const *chan,
509
+ const int **vals, int *type, int *length,
510
+ long mask)
511
+{
512
+ switch (mask) {
513
+ case IIO_CHAN_INFO_SAMP_FREQ:
514
+ *vals = (int *)vcnl4010_prox_sampling_frequency;
515
+ *type = IIO_VAL_INT_PLUS_MICRO;
516
+ *length = 2 * ARRAY_SIZE(vcnl4010_prox_sampling_frequency);
517
+ return IIO_AVAIL_LIST;
518
+ default:
519
+ return -EINVAL;
520
+ }
521
+}
522
+
523
+static int vcnl4010_write_proxy_samp_freq(struct vcnl4000_data *data, int val,
524
+ int val2)
525
+{
526
+ unsigned int i;
527
+ int index = -1;
528
+
529
+ for (i = 0; i < ARRAY_SIZE(vcnl4010_prox_sampling_frequency); i++) {
530
+ if (val == vcnl4010_prox_sampling_frequency[i][0] &&
531
+ val2 == vcnl4010_prox_sampling_frequency[i][1]) {
532
+ index = i;
533
+ break;
534
+ }
535
+ }
536
+
537
+ if (index < 0)
538
+ return -EINVAL;
539
+
540
+ return i2c_smbus_write_byte_data(data->client, VCNL4010_PROX_RATE,
541
+ index);
542
+}
543
+
544
+static int vcnl4010_write_raw(struct iio_dev *indio_dev,
545
+ struct iio_chan_spec const *chan,
546
+ int val, int val2, long mask)
547
+{
548
+ int ret;
549
+ struct vcnl4000_data *data = iio_priv(indio_dev);
550
+
551
+ ret = iio_device_claim_direct_mode(indio_dev);
552
+ if (ret)
553
+ return ret;
554
+
555
+ /* Protect against event capture. */
556
+ if (vcnl4010_is_in_periodic_mode(data)) {
557
+ ret = -EBUSY;
558
+ goto end;
559
+ }
560
+
561
+ switch (mask) {
562
+ case IIO_CHAN_INFO_SAMP_FREQ:
563
+ switch (chan->type) {
564
+ case IIO_PROXIMITY:
565
+ ret = vcnl4010_write_proxy_samp_freq(data, val, val2);
566
+ goto end;
567
+ default:
568
+ ret = -EINVAL;
569
+ goto end;
570
+ }
571
+ default:
572
+ ret = -EINVAL;
573
+ goto end;
574
+ }
575
+
576
+end:
577
+ iio_device_release_direct_mode(indio_dev);
578
+ return ret;
579
+}
580
+
581
+static int vcnl4010_read_event(struct iio_dev *indio_dev,
582
+ const struct iio_chan_spec *chan,
583
+ enum iio_event_type type,
584
+ enum iio_event_direction dir,
585
+ enum iio_event_info info,
586
+ int *val, int *val2)
587
+{
588
+ int ret;
589
+ struct vcnl4000_data *data = iio_priv(indio_dev);
590
+
591
+ switch (info) {
592
+ case IIO_EV_INFO_VALUE:
593
+ switch (dir) {
594
+ case IIO_EV_DIR_RISING:
595
+ ret = vcnl4000_read_data(data, VCNL4010_HIGH_THR_HI,
596
+ val);
597
+ if (ret < 0)
598
+ return ret;
599
+ return IIO_VAL_INT;
600
+ case IIO_EV_DIR_FALLING:
601
+ ret = vcnl4000_read_data(data, VCNL4010_LOW_THR_HI,
602
+ val);
603
+ if (ret < 0)
604
+ return ret;
605
+ return IIO_VAL_INT;
606
+ default:
607
+ return -EINVAL;
608
+ }
609
+ default:
610
+ return -EINVAL;
611
+ }
612
+}
613
+
614
+static int vcnl4010_write_event(struct iio_dev *indio_dev,
615
+ const struct iio_chan_spec *chan,
616
+ enum iio_event_type type,
617
+ enum iio_event_direction dir,
618
+ enum iio_event_info info,
619
+ int val, int val2)
620
+{
621
+ int ret;
622
+ struct vcnl4000_data *data = iio_priv(indio_dev);
623
+
624
+ switch (info) {
625
+ case IIO_EV_INFO_VALUE:
626
+ switch (dir) {
627
+ case IIO_EV_DIR_RISING:
628
+ ret = vcnl4000_write_data(data, VCNL4010_HIGH_THR_HI,
629
+ val);
630
+ if (ret < 0)
631
+ return ret;
632
+ return IIO_VAL_INT;
633
+ case IIO_EV_DIR_FALLING:
634
+ ret = vcnl4000_write_data(data, VCNL4010_LOW_THR_HI,
635
+ val);
636
+ if (ret < 0)
637
+ return ret;
638
+ return IIO_VAL_INT;
639
+ default:
640
+ return -EINVAL;
641
+ }
642
+ default:
643
+ return -EINVAL;
644
+ }
645
+}
646
+
647
+static bool vcnl4010_is_thr_enabled(struct vcnl4000_data *data)
648
+{
649
+ int ret;
650
+
651
+ ret = i2c_smbus_read_byte_data(data->client, VCNL4010_INT_CTRL);
652
+ if (ret < 0)
653
+ return false;
654
+
655
+ return !!(ret & VCNL4010_INT_THR_EN);
656
+}
657
+
658
+static int vcnl4010_read_event_config(struct iio_dev *indio_dev,
659
+ const struct iio_chan_spec *chan,
660
+ enum iio_event_type type,
661
+ enum iio_event_direction dir)
662
+{
663
+ struct vcnl4000_data *data = iio_priv(indio_dev);
664
+
665
+ switch (chan->type) {
666
+ case IIO_PROXIMITY:
667
+ return vcnl4010_is_thr_enabled(data);
668
+ default:
669
+ return -EINVAL;
670
+ }
671
+}
672
+
673
+static int vcnl4010_config_threshold(struct iio_dev *indio_dev, bool state)
674
+{
675
+ struct vcnl4000_data *data = iio_priv(indio_dev);
676
+ int ret;
677
+ int icr;
678
+ int command;
679
+
680
+ if (state) {
681
+ ret = iio_device_claim_direct_mode(indio_dev);
682
+ if (ret)
683
+ return ret;
684
+
685
+ /* Enable periodic measurement of proximity data. */
686
+ command = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
687
+
688
+ /*
689
+ * Enable interrupts on threshold, for proximity data by
690
+ * default.
691
+ */
692
+ icr = VCNL4010_INT_THR_EN;
693
+ } else {
694
+ if (!vcnl4010_is_thr_enabled(data))
695
+ return 0;
696
+
697
+ command = 0;
698
+ icr = 0;
699
+ }
700
+
701
+ ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
702
+ command);
703
+ if (ret < 0)
704
+ goto end;
705
+
706
+ ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, icr);
707
+
708
+end:
709
+ if (state)
710
+ iio_device_release_direct_mode(indio_dev);
711
+
712
+ return ret;
713
+}
714
+
715
+static int vcnl4010_write_event_config(struct iio_dev *indio_dev,
716
+ const struct iio_chan_spec *chan,
717
+ enum iio_event_type type,
718
+ enum iio_event_direction dir,
719
+ int state)
720
+{
721
+ switch (chan->type) {
722
+ case IIO_PROXIMITY:
723
+ return vcnl4010_config_threshold(indio_dev, state);
724
+ default:
725
+ return -EINVAL;
726
+ }
727
+}
728
+
729
+static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,
730
+ uintptr_t priv,
731
+ const struct iio_chan_spec *chan,
732
+ char *buf)
733
+{
734
+ struct vcnl4000_data *data = iio_priv(indio_dev);
735
+
736
+ return sprintf(buf, "%u\n", data->near_level);
737
+}
738
+
739
+static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = {
740
+ {
741
+ .name = "nearlevel",
742
+ .shared = IIO_SEPARATE,
743
+ .read = vcnl4000_read_near_level,
744
+ },
745
+ { /* sentinel */ }
746
+};
747
+
748
+static const struct iio_event_spec vcnl4000_event_spec[] = {
749
+ {
750
+ .type = IIO_EV_TYPE_THRESH,
751
+ .dir = IIO_EV_DIR_RISING,
752
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
753
+ }, {
754
+ .type = IIO_EV_TYPE_THRESH,
755
+ .dir = IIO_EV_DIR_FALLING,
756
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
757
+ }, {
758
+ .type = IIO_EV_TYPE_THRESH,
759
+ .dir = IIO_EV_DIR_EITHER,
760
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
761
+ }
762
+};
763
+
764
+static const struct iio_chan_spec vcnl4000_channels[] = {
765
+ {
766
+ .type = IIO_LIGHT,
767
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
768
+ BIT(IIO_CHAN_INFO_SCALE),
769
+ }, {
770
+ .type = IIO_PROXIMITY,
771
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
772
+ .ext_info = vcnl4000_ext_info,
773
+ }
774
+};
775
+
776
+static const struct iio_chan_spec vcnl4010_channels[] = {
777
+ {
778
+ .type = IIO_LIGHT,
779
+ .scan_index = -1,
780
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
781
+ BIT(IIO_CHAN_INFO_SCALE),
782
+ }, {
783
+ .type = IIO_PROXIMITY,
784
+ .scan_index = 0,
785
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
786
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
787
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
788
+ .event_spec = vcnl4000_event_spec,
789
+ .num_event_specs = ARRAY_SIZE(vcnl4000_event_spec),
790
+ .ext_info = vcnl4000_ext_info,
791
+ .scan_type = {
792
+ .sign = 'u',
793
+ .realbits = 16,
794
+ .storagebits = 16,
795
+ .endianness = IIO_CPU,
796
+ },
797
+ },
798
+ IIO_CHAN_SOFT_TIMESTAMP(1),
799
+};
800
+
327801 static const struct iio_info vcnl4000_info = {
328802 .read_raw = vcnl4000_read_raw,
329803 };
804
+
805
+static const struct iio_info vcnl4010_info = {
806
+ .read_raw = vcnl4010_read_raw,
807
+ .read_avail = vcnl4010_read_avail,
808
+ .write_raw = vcnl4010_write_raw,
809
+ .read_event_value = vcnl4010_read_event,
810
+ .write_event_value = vcnl4010_write_event,
811
+ .read_event_config = vcnl4010_read_event_config,
812
+ .write_event_config = vcnl4010_write_event_config,
813
+};
814
+
815
+static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
816
+ [VCNL4000] = {
817
+ .prod = "VCNL4000",
818
+ .init = vcnl4000_init,
819
+ .measure_light = vcnl4000_measure_light,
820
+ .measure_proximity = vcnl4000_measure_proximity,
821
+ .set_power_state = vcnl4000_set_power_state,
822
+ .channels = vcnl4000_channels,
823
+ .num_channels = ARRAY_SIZE(vcnl4000_channels),
824
+ .info = &vcnl4000_info,
825
+ .irq_support = false,
826
+ },
827
+ [VCNL4010] = {
828
+ .prod = "VCNL4010/4020",
829
+ .init = vcnl4000_init,
830
+ .measure_light = vcnl4000_measure_light,
831
+ .measure_proximity = vcnl4000_measure_proximity,
832
+ .set_power_state = vcnl4000_set_power_state,
833
+ .channels = vcnl4010_channels,
834
+ .num_channels = ARRAY_SIZE(vcnl4010_channels),
835
+ .info = &vcnl4010_info,
836
+ .irq_support = true,
837
+ },
838
+ [VCNL4040] = {
839
+ .prod = "VCNL4040",
840
+ .init = vcnl4200_init,
841
+ .measure_light = vcnl4200_measure_light,
842
+ .measure_proximity = vcnl4200_measure_proximity,
843
+ .set_power_state = vcnl4200_set_power_state,
844
+ .channels = vcnl4000_channels,
845
+ .num_channels = ARRAY_SIZE(vcnl4000_channels),
846
+ .info = &vcnl4000_info,
847
+ .irq_support = false,
848
+ },
849
+ [VCNL4200] = {
850
+ .prod = "VCNL4200",
851
+ .init = vcnl4200_init,
852
+ .measure_light = vcnl4200_measure_light,
853
+ .measure_proximity = vcnl4200_measure_proximity,
854
+ .set_power_state = vcnl4200_set_power_state,
855
+ .channels = vcnl4000_channels,
856
+ .num_channels = ARRAY_SIZE(vcnl4000_channels),
857
+ .info = &vcnl4000_info,
858
+ .irq_support = false,
859
+ },
860
+};
861
+
862
+static irqreturn_t vcnl4010_irq_thread(int irq, void *p)
863
+{
864
+ struct iio_dev *indio_dev = p;
865
+ struct vcnl4000_data *data = iio_priv(indio_dev);
866
+ unsigned long isr;
867
+ int ret;
868
+
869
+ ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
870
+ if (ret < 0)
871
+ goto end;
872
+
873
+ isr = ret;
874
+
875
+ if (isr & VCNL4010_INT_THR) {
876
+ if (test_bit(VCNL4010_INT_THR_LOW, &isr)) {
877
+ iio_push_event(indio_dev,
878
+ IIO_UNMOD_EVENT_CODE(
879
+ IIO_PROXIMITY,
880
+ 1,
881
+ IIO_EV_TYPE_THRESH,
882
+ IIO_EV_DIR_FALLING),
883
+ iio_get_time_ns(indio_dev));
884
+ }
885
+
886
+ if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) {
887
+ iio_push_event(indio_dev,
888
+ IIO_UNMOD_EVENT_CODE(
889
+ IIO_PROXIMITY,
890
+ 1,
891
+ IIO_EV_TYPE_THRESH,
892
+ IIO_EV_DIR_RISING),
893
+ iio_get_time_ns(indio_dev));
894
+ }
895
+
896
+ i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
897
+ isr & VCNL4010_INT_THR);
898
+ }
899
+
900
+ if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev))
901
+ iio_trigger_poll_chained(indio_dev->trig);
902
+
903
+end:
904
+ return IRQ_HANDLED;
905
+}
906
+
907
+static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)
908
+{
909
+ struct iio_poll_func *pf = p;
910
+ struct iio_dev *indio_dev = pf->indio_dev;
911
+ struct vcnl4000_data *data = iio_priv(indio_dev);
912
+ const unsigned long *active_scan_mask = indio_dev->active_scan_mask;
913
+ u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */
914
+ bool data_read = false;
915
+ unsigned long isr;
916
+ int val = 0;
917
+ int ret;
918
+
919
+ ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
920
+ if (ret < 0)
921
+ goto end;
922
+
923
+ isr = ret;
924
+
925
+ if (test_bit(0, active_scan_mask)) {
926
+ if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) {
927
+ ret = vcnl4000_read_data(data,
928
+ VCNL4000_PS_RESULT_HI,
929
+ &val);
930
+ if (ret < 0)
931
+ goto end;
932
+
933
+ buffer[0] = val;
934
+ data_read = true;
935
+ }
936
+ }
937
+
938
+ ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
939
+ isr & VCNL4010_INT_DRDY);
940
+ if (ret < 0)
941
+ goto end;
942
+
943
+ if (!data_read)
944
+ goto end;
945
+
946
+ iio_push_to_buffers_with_timestamp(indio_dev, buffer,
947
+ iio_get_time_ns(indio_dev));
948
+
949
+end:
950
+ iio_trigger_notify_done(indio_dev->trig);
951
+ return IRQ_HANDLED;
952
+}
953
+
954
+static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev)
955
+{
956
+ struct vcnl4000_data *data = iio_priv(indio_dev);
957
+ int ret;
958
+ int cmd;
959
+
960
+ /* Do not enable the buffer if we are already capturing events. */
961
+ if (vcnl4010_is_in_periodic_mode(data))
962
+ return -EBUSY;
963
+
964
+ ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL,
965
+ VCNL4010_INT_PROX_EN);
966
+ if (ret < 0)
967
+ return ret;
968
+
969
+ cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
970
+ return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd);
971
+}
972
+
973
+static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev)
974
+{
975
+ struct vcnl4000_data *data = iio_priv(indio_dev);
976
+ int ret;
977
+
978
+ ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0);
979
+ if (ret < 0)
980
+ return ret;
981
+
982
+ return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0);
983
+}
984
+
985
+static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = {
986
+ .postenable = &vcnl4010_buffer_postenable,
987
+ .predisable = &vcnl4010_buffer_predisable,
988
+};
989
+
990
+static const struct iio_trigger_ops vcnl4010_trigger_ops = {
991
+ .validate_device = iio_trigger_validate_own_device,
992
+};
993
+
994
+static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)
995
+{
996
+ struct vcnl4000_data *data = iio_priv(indio_dev);
997
+ struct i2c_client *client = data->client;
998
+ struct iio_trigger *trigger;
999
+
1000
+ trigger = devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
1001
+ indio_dev->name, indio_dev->id);
1002
+ if (!trigger)
1003
+ return -ENOMEM;
1004
+
1005
+ trigger->dev.parent = &client->dev;
1006
+ trigger->ops = &vcnl4010_trigger_ops;
1007
+ iio_trigger_set_drvdata(trigger, indio_dev);
1008
+
1009
+ return devm_iio_trigger_register(&client->dev, trigger);
1010
+}
3301011
3311012 static int vcnl4000_probe(struct i2c_client *client,
3321013 const struct i2c_device_id *id)
....@@ -352,26 +1033,136 @@
3521033 dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n",
3531034 data->chip_spec->prod, data->rev);
3541035
355
- indio_dev->dev.parent = &client->dev;
356
- indio_dev->info = &vcnl4000_info;
357
- indio_dev->channels = vcnl4000_channels;
358
- indio_dev->num_channels = ARRAY_SIZE(vcnl4000_channels);
1036
+ if (device_property_read_u32(&client->dev, "proximity-near-level",
1037
+ &data->near_level))
1038
+ data->near_level = 0;
1039
+
1040
+ indio_dev->info = data->chip_spec->info;
1041
+ indio_dev->channels = data->chip_spec->channels;
1042
+ indio_dev->num_channels = data->chip_spec->num_channels;
3591043 indio_dev->name = VCNL4000_DRV_NAME;
3601044 indio_dev->modes = INDIO_DIRECT_MODE;
3611045
362
- return devm_iio_device_register(&client->dev, indio_dev);
1046
+ if (client->irq && data->chip_spec->irq_support) {
1047
+ ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
1048
+ NULL,
1049
+ vcnl4010_trigger_handler,
1050
+ &vcnl4010_buffer_ops);
1051
+ if (ret < 0) {
1052
+ dev_err(&client->dev,
1053
+ "unable to setup iio triggered buffer\n");
1054
+ return ret;
1055
+ }
1056
+
1057
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
1058
+ NULL, vcnl4010_irq_thread,
1059
+ IRQF_TRIGGER_FALLING |
1060
+ IRQF_ONESHOT,
1061
+ "vcnl4010_irq",
1062
+ indio_dev);
1063
+ if (ret < 0) {
1064
+ dev_err(&client->dev, "irq request failed\n");
1065
+ return ret;
1066
+ }
1067
+
1068
+ ret = vcnl4010_probe_trigger(indio_dev);
1069
+ if (ret < 0)
1070
+ return ret;
1071
+ }
1072
+
1073
+ ret = pm_runtime_set_active(&client->dev);
1074
+ if (ret < 0)
1075
+ goto fail_poweroff;
1076
+
1077
+ ret = iio_device_register(indio_dev);
1078
+ if (ret < 0)
1079
+ goto fail_poweroff;
1080
+
1081
+ pm_runtime_enable(&client->dev);
1082
+ pm_runtime_set_autosuspend_delay(&client->dev, VCNL4000_SLEEP_DELAY_MS);
1083
+ pm_runtime_use_autosuspend(&client->dev);
1084
+
1085
+ return 0;
1086
+fail_poweroff:
1087
+ data->chip_spec->set_power_state(data, false);
1088
+ return ret;
3631089 }
1090
+
1091
+static const struct of_device_id vcnl_4000_of_match[] = {
1092
+ {
1093
+ .compatible = "vishay,vcnl4000",
1094
+ .data = (void *)VCNL4000,
1095
+ },
1096
+ {
1097
+ .compatible = "vishay,vcnl4010",
1098
+ .data = (void *)VCNL4010,
1099
+ },
1100
+ {
1101
+ .compatible = "vishay,vcnl4020",
1102
+ .data = (void *)VCNL4010,
1103
+ },
1104
+ {
1105
+ .compatible = "vishay,vcnl4040",
1106
+ .data = (void *)VCNL4040,
1107
+ },
1108
+ {
1109
+ .compatible = "vishay,vcnl4200",
1110
+ .data = (void *)VCNL4200,
1111
+ },
1112
+ {},
1113
+};
1114
+MODULE_DEVICE_TABLE(of, vcnl_4000_of_match);
1115
+
1116
+static int vcnl4000_remove(struct i2c_client *client)
1117
+{
1118
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
1119
+ struct vcnl4000_data *data = iio_priv(indio_dev);
1120
+
1121
+ pm_runtime_dont_use_autosuspend(&client->dev);
1122
+ pm_runtime_disable(&client->dev);
1123
+ iio_device_unregister(indio_dev);
1124
+ pm_runtime_set_suspended(&client->dev);
1125
+
1126
+ return data->chip_spec->set_power_state(data, false);
1127
+}
1128
+
1129
+static int __maybe_unused vcnl4000_runtime_suspend(struct device *dev)
1130
+{
1131
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
1132
+ struct vcnl4000_data *data = iio_priv(indio_dev);
1133
+
1134
+ return data->chip_spec->set_power_state(data, false);
1135
+}
1136
+
1137
+static int __maybe_unused vcnl4000_runtime_resume(struct device *dev)
1138
+{
1139
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
1140
+ struct vcnl4000_data *data = iio_priv(indio_dev);
1141
+
1142
+ return data->chip_spec->set_power_state(data, true);
1143
+}
1144
+
1145
+static const struct dev_pm_ops vcnl4000_pm_ops = {
1146
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1147
+ pm_runtime_force_resume)
1148
+ SET_RUNTIME_PM_OPS(vcnl4000_runtime_suspend,
1149
+ vcnl4000_runtime_resume, NULL)
1150
+};
3641151
3651152 static struct i2c_driver vcnl4000_driver = {
3661153 .driver = {
3671154 .name = VCNL4000_DRV_NAME,
1155
+ .pm = &vcnl4000_pm_ops,
1156
+ .of_match_table = vcnl_4000_of_match,
3681157 },
3691158 .probe = vcnl4000_probe,
3701159 .id_table = vcnl4000_id,
1160
+ .remove = vcnl4000_remove,
3711161 };
3721162
3731163 module_i2c_driver(vcnl4000_driver);
3741164
3751165 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
1166
+MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
3761167 MODULE_DESCRIPTION("Vishay VCNL4000 proximity/ambient light sensor driver");
3771168 MODULE_LICENSE("GPL");