1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Support for Vishay VCNL3020 proximity sensor on i2c bus.
4 * Based on Vishay VCNL4000 driver code.
5 */
6
7#include <linux/module.h>
8#include <linux/i2c.h>
9#include <linux/err.h>
10#include <linux/delay.h>
11#include <linux/regmap.h>
12#include <linux/interrupt.h>
13
14#include <linux/iio/iio.h>
15#include <linux/iio/events.h>
16
17#define VCNL3020_PROD_ID	0x21
18
19#define VCNL_COMMAND		0x80 /* Command register */
20#define VCNL_PROD_REV		0x81 /* Product ID and Revision ID */
21#define VCNL_PROXIMITY_RATE	0x82 /* Rate of Proximity Measurement */
22#define VCNL_LED_CURRENT	0x83 /* IR LED current for proximity mode */
23#define VCNL_PS_RESULT_HI	0x87 /* Proximity result register, MSB */
24#define VCNL_PS_RESULT_LO	0x88 /* Proximity result register, LSB */
25#define VCNL_PS_ICR		0x89 /* Interrupt Control Register */
26#define VCNL_PS_LO_THR_HI	0x8a /* High byte of low threshold value */
27#define VCNL_PS_LO_THR_LO	0x8b /* Low byte of low threshold value */
28#define VCNL_PS_HI_THR_HI	0x8c /* High byte of high threshold value */
29#define VCNL_PS_HI_THR_LO	0x8d /* Low byte of high threshold value */
30#define VCNL_ISR		0x8e /* Interrupt Status Register */
31#define VCNL_PS_MOD_ADJ		0x8f /* Proximity Modulator Timing Adjustment */
32
33/* Bit masks for COMMAND register */
34#define VCNL_PS_RDY		BIT(5) /* proximity data ready? */
35#define VCNL_PS_OD		BIT(3) /* start on-demand proximity
36					* measurement
37					*/
38
39/* Enables periodic proximity measurement */
40#define VCNL_PS_EN		BIT(1)
41
42/* Enables state machine and LP oscillator for self timed  measurements */
43#define VCNL_PS_SELFTIMED_EN	BIT(0)
44
45/* Bit masks for ICR */
46
47/* Enable interrupts on low or high thresholds */
48#define  VCNL_ICR_THRES_EN	BIT(1)
49
50/* Bit masks for ISR */
51#define VCNL_INT_TH_HI		BIT(0)	/* High threshold hit */
52#define VCNL_INT_TH_LOW		BIT(1)	/* Low threshold hit */
53
54#define VCNL_ON_DEMAND_TIMEOUT_US	100000
55#define VCNL_POLL_US			20000
56
57static const int vcnl3020_prox_sampling_frequency[][2] = {
58	{1, 950000},
59	{3, 906250},
60	{7, 812500},
61	{16, 625000},
62	{31, 250000},
63	{62, 500000},
64	{125, 0},
65	{250, 0},
66};
67
68/**
69 * struct vcnl3020_data - vcnl3020 specific data.
70 * @regmap:	device register map.
71 * @dev:	vcnl3020 device.
72 * @rev:	revision id.
73 * @lock:	lock for protecting access to device hardware registers.
74 * @buf:	__be16 buffer.
75 */
76struct vcnl3020_data {
77	struct regmap *regmap;
78	struct device *dev;
79	u8 rev;
80	struct mutex lock;
81	__be16 buf;
82};
83
84/**
85 * struct vcnl3020_property - vcnl3020 property.
86 * @name:	property name.
87 * @reg:	i2c register offset.
88 * @conversion_func:	conversion function.
89 */
90struct vcnl3020_property {
91	const char *name;
92	u32 reg;
93	u32 (*conversion_func)(u32 *val);
94};
95
96static u32 microamp_to_reg(u32 *val)
97{
98	/*
99	 * An example of conversion from uA to reg val:
100	 * 200000 uA == 200 mA == 20
101	 */
102	return *val /= 10000;
103};
104
105static struct vcnl3020_property vcnl3020_led_current_property = {
106	.name = "vishay,led-current-microamp",
107	.reg = VCNL_LED_CURRENT,
108	.conversion_func = microamp_to_reg,
109};
110
111static int vcnl3020_get_and_apply_property(struct vcnl3020_data *data,
112					   struct vcnl3020_property prop)
113{
114	int rc;
115	u32 val;
116
117	rc = device_property_read_u32(data->dev, prop.name, &val);
118	if (rc)
119		return 0;
120
121	if (prop.conversion_func)
122		prop.conversion_func(&val);
123
124	rc = regmap_write(data->regmap, prop.reg, val);
125	if (rc) {
126		dev_err(data->dev, "Error (%d) setting property (%s)\n",
127			rc, prop.name);
128	}
129
130	return rc;
131}
132
133static int vcnl3020_init(struct vcnl3020_data *data)
134{
135	int rc;
136	unsigned int reg;
137
138	rc = regmap_read(data->regmap, VCNL_PROD_REV, &reg);
139	if (rc) {
140		dev_err(data->dev,
141			"Error (%d) reading product revision\n", rc);
142		return rc;
143	}
144
145	if (reg != VCNL3020_PROD_ID) {
146		dev_err(data->dev,
147			"Product id (%x) did not match vcnl3020 (%x)\n", reg,
148			VCNL3020_PROD_ID);
149		return -ENODEV;
150	}
151
152	data->rev = reg;
153	mutex_init(&data->lock);
154
155	return vcnl3020_get_and_apply_property(data,
156					       vcnl3020_led_current_property);
157};
158
159static bool vcnl3020_is_in_periodic_mode(struct vcnl3020_data *data)
160{
161	int rc;
162	unsigned int cmd;
163
164	rc = regmap_read(data->regmap, VCNL_COMMAND, &cmd);
165	if (rc) {
166		dev_err(data->dev,
167			"Error (%d) reading command register\n", rc);
168		return false;
169	}
170
171	return !!(cmd & VCNL_PS_SELFTIMED_EN);
172}
173
174static int vcnl3020_measure_proximity(struct vcnl3020_data *data, int *val)
175{
176	int rc;
177	unsigned int reg;
178
179	mutex_lock(&data->lock);
180
181	/* Protect against event capture. */
182	if (vcnl3020_is_in_periodic_mode(data)) {
183		rc = -EBUSY;
184		goto err_unlock;
185	}
186
187	rc = regmap_write(data->regmap, VCNL_COMMAND, VCNL_PS_OD);
188	if (rc)
189		goto err_unlock;
190
191	/* wait for data to become ready */
192	rc = regmap_read_poll_timeout(data->regmap, VCNL_COMMAND, reg,
193				      reg & VCNL_PS_RDY, VCNL_POLL_US,
194				      VCNL_ON_DEMAND_TIMEOUT_US);
195	if (rc) {
196		dev_err(data->dev,
197			"Error (%d) reading vcnl3020 command register\n", rc);
198		goto err_unlock;
199	}
200
201	/* high & low result bytes read */
202	rc = regmap_bulk_read(data->regmap, VCNL_PS_RESULT_HI, &data->buf,
203			      sizeof(data->buf));
204	if (rc)
205		goto err_unlock;
206
207	*val = be16_to_cpu(data->buf);
208
209err_unlock:
210	mutex_unlock(&data->lock);
211
212	return rc;
213}
214
215static int vcnl3020_read_proxy_samp_freq(struct vcnl3020_data *data, int *val,
216					 int *val2)
217{
218	int rc;
219	unsigned int prox_rate;
220
221	rc = regmap_read(data->regmap, VCNL_PROXIMITY_RATE, &prox_rate);
222	if (rc)
223		return rc;
224
225	if (prox_rate >= ARRAY_SIZE(vcnl3020_prox_sampling_frequency))
226		return -EINVAL;
227
228	*val = vcnl3020_prox_sampling_frequency[prox_rate][0];
229	*val2 = vcnl3020_prox_sampling_frequency[prox_rate][1];
230
231	return 0;
232}
233
234static int vcnl3020_write_proxy_samp_freq(struct vcnl3020_data *data, int val,
235					  int val2)
236{
237	unsigned int i;
238	int index = -1;
239	int rc;
240
241	mutex_lock(&data->lock);
242
243	/* Protect against event capture. */
244	if (vcnl3020_is_in_periodic_mode(data)) {
245		rc = -EBUSY;
246		goto err_unlock;
247	}
248
249	for (i = 0; i < ARRAY_SIZE(vcnl3020_prox_sampling_frequency); i++) {
250		if (val == vcnl3020_prox_sampling_frequency[i][0] &&
251		    val2 == vcnl3020_prox_sampling_frequency[i][1]) {
252			index = i;
253			break;
254		}
255	}
256
257	if (index < 0) {
258		rc = -EINVAL;
259		goto err_unlock;
260	}
261
262	rc = regmap_write(data->regmap, VCNL_PROXIMITY_RATE, index);
263	if (rc)
264		dev_err(data->dev,
265			"Error (%d) writing proximity rate register\n", rc);
266
267err_unlock:
268	mutex_unlock(&data->lock);
269
270	return rc;
271}
272
273static bool vcnl3020_is_thr_enabled(struct vcnl3020_data *data)
274{
275	int rc;
276	unsigned int icr;
277
278	rc = regmap_read(data->regmap, VCNL_PS_ICR, &icr);
279	if (rc) {
280		dev_err(data->dev,
281			"Error (%d) reading ICR register\n", rc);
282		return false;
283	}
284
285	return !!(icr & VCNL_ICR_THRES_EN);
286}
287
288static int vcnl3020_read_event(struct iio_dev *indio_dev,
289			       const struct iio_chan_spec *chan,
290			       enum iio_event_type type,
291			       enum iio_event_direction dir,
292			       enum iio_event_info info,
293			       int *val, int *val2)
294{
295	int rc;
296	struct vcnl3020_data *data = iio_priv(indio_dev);
297
298	switch (info) {
299	case IIO_EV_INFO_VALUE:
300		switch (dir) {
301		case IIO_EV_DIR_RISING:
302			rc = regmap_bulk_read(data->regmap, VCNL_PS_HI_THR_HI,
303					      &data->buf, sizeof(data->buf));
304			if (rc < 0)
305				return rc;
306			*val = be16_to_cpu(data->buf);
307			return IIO_VAL_INT;
308		case IIO_EV_DIR_FALLING:
309			rc = regmap_bulk_read(data->regmap, VCNL_PS_LO_THR_HI,
310					      &data->buf, sizeof(data->buf));
311			if (rc < 0)
312				return rc;
313			*val = be16_to_cpu(data->buf);
314			return IIO_VAL_INT;
315		default:
316			return -EINVAL;
317		}
318	default:
319		return -EINVAL;
320	}
321}
322
323static int vcnl3020_write_event(struct iio_dev *indio_dev,
324				const struct iio_chan_spec *chan,
325				enum iio_event_type type,
326				enum iio_event_direction dir,
327				enum iio_event_info info,
328				int val, int val2)
329{
330	int rc;
331	struct vcnl3020_data *data = iio_priv(indio_dev);
332
333	mutex_lock(&data->lock);
334
335	switch (info) {
336	case IIO_EV_INFO_VALUE:
337		switch (dir) {
338		case IIO_EV_DIR_RISING:
339			/* 16 bit word/ low * high */
340			data->buf = cpu_to_be16(val);
341			rc = regmap_bulk_write(data->regmap, VCNL_PS_HI_THR_HI,
342					       &data->buf, sizeof(data->buf));
343			if (rc < 0)
344				goto err_unlock;
345			rc = IIO_VAL_INT;
346			goto err_unlock;
347		case IIO_EV_DIR_FALLING:
348			data->buf = cpu_to_be16(val);
349			rc = regmap_bulk_write(data->regmap, VCNL_PS_LO_THR_HI,
350					       &data->buf, sizeof(data->buf));
351			if (rc < 0)
352				goto err_unlock;
353			rc = IIO_VAL_INT;
354			goto err_unlock;
355		default:
356			rc = -EINVAL;
357			goto err_unlock;
358		}
359	default:
360		rc = -EINVAL;
361		goto err_unlock;
362	}
363err_unlock:
364	mutex_unlock(&data->lock);
365
366	return rc;
367}
368
369static int vcnl3020_enable_periodic(struct iio_dev *indio_dev,
370				    struct vcnl3020_data *data)
371{
372	int rc;
373	int cmd;
374
375	mutex_lock(&data->lock);
376
377	/* Enable periodic measurement of proximity data. */
378	cmd = VCNL_PS_EN | VCNL_PS_SELFTIMED_EN;
379
380	rc = regmap_write(data->regmap, VCNL_COMMAND, cmd);
381	if (rc) {
382		dev_err(data->dev,
383			"Error (%d) writing command register\n", rc);
384		goto err_unlock;
385	}
386
387	/*
388	 * Enable interrupts on threshold, for proximity data by
389	 * default.
390	 */
391	rc = regmap_write(data->regmap, VCNL_PS_ICR, VCNL_ICR_THRES_EN);
392	if (rc)
393		dev_err(data->dev,
394			"Error (%d) reading ICR register\n", rc);
395
396err_unlock:
397	mutex_unlock(&data->lock);
398
399	return rc;
400}
401
402static int vcnl3020_disable_periodic(struct iio_dev *indio_dev,
403				     struct vcnl3020_data *data)
404{
405	int rc;
406
407	mutex_lock(&data->lock);
408
409	rc = regmap_write(data->regmap, VCNL_COMMAND, 0);
410	if (rc) {
411		dev_err(data->dev,
412			"Error (%d) writing command register\n", rc);
413		goto err_unlock;
414	}
415
416	rc = regmap_write(data->regmap, VCNL_PS_ICR, 0);
417	if (rc) {
418		dev_err(data->dev,
419			"Error (%d) writing ICR register\n", rc);
420		goto err_unlock;
421	}
422
423	/* Clear interrupt flag bit */
424	rc = regmap_write(data->regmap, VCNL_ISR, 0);
425	if (rc)
426		dev_err(data->dev,
427			"Error (%d) writing ISR register\n", rc);
428
429err_unlock:
430	mutex_unlock(&data->lock);
431
432	return rc;
433}
434
435static int vcnl3020_config_threshold(struct iio_dev *indio_dev, bool state)
436{
437	struct vcnl3020_data *data = iio_priv(indio_dev);
438
439	if (state) {
440		return vcnl3020_enable_periodic(indio_dev, data);
441	} else {
442		if (!vcnl3020_is_thr_enabled(data))
443			return 0;
444		return vcnl3020_disable_periodic(indio_dev, data);
445	}
446}
447
448static int vcnl3020_write_event_config(struct iio_dev *indio_dev,
449				       const struct iio_chan_spec *chan,
450				       enum iio_event_type type,
451				       enum iio_event_direction dir,
452				       int state)
453{
454	switch (chan->type) {
455	case IIO_PROXIMITY:
456		return vcnl3020_config_threshold(indio_dev, state);
457	default:
458		return -EINVAL;
459	}
460}
461
462static int vcnl3020_read_event_config(struct iio_dev *indio_dev,
463				      const struct iio_chan_spec *chan,
464				      enum iio_event_type type,
465				      enum iio_event_direction dir)
466{
467	struct vcnl3020_data *data = iio_priv(indio_dev);
468
469	switch (chan->type) {
470	case IIO_PROXIMITY:
471		return vcnl3020_is_thr_enabled(data);
472	default:
473		return -EINVAL;
474	}
475}
476
477static const struct iio_event_spec vcnl3020_event_spec[] = {
478	{
479		.type = IIO_EV_TYPE_THRESH,
480		.dir = IIO_EV_DIR_RISING,
481		.mask_separate = BIT(IIO_EV_INFO_VALUE),
482	}, {
483		.type = IIO_EV_TYPE_THRESH,
484		.dir = IIO_EV_DIR_FALLING,
485		.mask_separate = BIT(IIO_EV_INFO_VALUE),
486	}, {
487		.type = IIO_EV_TYPE_THRESH,
488		.dir = IIO_EV_DIR_EITHER,
489		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
490	},
491};
492
493static const struct iio_chan_spec vcnl3020_channels[] = {
494	{
495		.type = IIO_PROXIMITY,
496		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
497				      BIT(IIO_CHAN_INFO_SAMP_FREQ),
498		.info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
499		.event_spec = vcnl3020_event_spec,
500		.num_event_specs = ARRAY_SIZE(vcnl3020_event_spec),
501	},
502};
503
504static int vcnl3020_read_raw(struct iio_dev *indio_dev,
505			     struct iio_chan_spec const *chan, int *val,
506			     int *val2, long mask)
507{
508	int rc;
509	struct vcnl3020_data *data = iio_priv(indio_dev);
510
511	switch (mask) {
512	case IIO_CHAN_INFO_RAW:
513		rc = vcnl3020_measure_proximity(data, val);
514		if (rc)
515			return rc;
516		return IIO_VAL_INT;
517	case IIO_CHAN_INFO_SAMP_FREQ:
518		rc = vcnl3020_read_proxy_samp_freq(data, val, val2);
519		if (rc < 0)
520			return rc;
521		return IIO_VAL_INT_PLUS_MICRO;
522	default:
523		return -EINVAL;
524	}
525}
526
527static int vcnl3020_write_raw(struct iio_dev *indio_dev,
528			      struct iio_chan_spec const *chan,
529			      int val, int val2, long mask)
530{
531	struct vcnl3020_data *data = iio_priv(indio_dev);
532
533	switch (mask) {
534	case IIO_CHAN_INFO_SAMP_FREQ:
535		return vcnl3020_write_proxy_samp_freq(data, val, val2);
536	default:
537		return -EINVAL;
538	}
539}
540
541static int vcnl3020_read_avail(struct iio_dev *indio_dev,
542			       struct iio_chan_spec const *chan,
543			       const int **vals, int *type, int *length,
544			       long mask)
545{
546	switch (mask) {
547	case IIO_CHAN_INFO_SAMP_FREQ:
548		*vals = (int *)vcnl3020_prox_sampling_frequency;
549		*type = IIO_VAL_INT_PLUS_MICRO;
550		*length = 2 * ARRAY_SIZE(vcnl3020_prox_sampling_frequency);
551		return IIO_AVAIL_LIST;
552	default:
553		return -EINVAL;
554	}
555}
556
557static const struct iio_info vcnl3020_info = {
558	.read_raw = vcnl3020_read_raw,
559	.write_raw = vcnl3020_write_raw,
560	.read_avail = vcnl3020_read_avail,
561	.read_event_value = vcnl3020_read_event,
562	.write_event_value = vcnl3020_write_event,
563	.read_event_config = vcnl3020_read_event_config,
564	.write_event_config = vcnl3020_write_event_config,
565};
566
567static const struct regmap_config vcnl3020_regmap_config = {
568	.reg_bits	= 8,
569	.val_bits	= 8,
570	.max_register	= VCNL_PS_MOD_ADJ,
571};
572
573static irqreturn_t vcnl3020_handle_irq_thread(int irq, void *p)
574{
575	struct iio_dev *indio_dev = p;
576	struct vcnl3020_data *data = iio_priv(indio_dev);
577	unsigned int isr;
578	int rc;
579
580	rc = regmap_read(data->regmap, VCNL_ISR, &isr);
581	if (rc) {
582		dev_err(data->dev, "Error (%d) reading reg (0x%x)\n",
583			rc, VCNL_ISR);
584		return IRQ_HANDLED;
585	}
586
587	if (!(isr & VCNL_ICR_THRES_EN))
588		return IRQ_NONE;
589
590	iio_push_event(indio_dev,
591		       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1,
592				            IIO_EV_TYPE_THRESH,
593				            IIO_EV_DIR_RISING),
594		       iio_get_time_ns(indio_dev));
595
596	rc = regmap_write(data->regmap, VCNL_ISR, isr & VCNL_ICR_THRES_EN);
597	if (rc)
598		dev_err(data->dev, "Error (%d) writing in reg (0x%x)\n",
599			rc, VCNL_ISR);
600
601	return IRQ_HANDLED;
602}
603
604static int vcnl3020_probe(struct i2c_client *client)
605{
606	struct vcnl3020_data *data;
607	struct iio_dev *indio_dev;
608	struct regmap *regmap;
609	int rc;
610
611	regmap = devm_regmap_init_i2c(client, &vcnl3020_regmap_config);
612	if (IS_ERR(regmap)) {
613		dev_err(&client->dev, "regmap_init failed\n");
614		return PTR_ERR(regmap);
615	}
616
617	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
618	if (!indio_dev)
619		return -ENOMEM;
620
621	data = iio_priv(indio_dev);
622	i2c_set_clientdata(client, indio_dev);
623	data->regmap = regmap;
624	data->dev = &client->dev;
625
626	rc = vcnl3020_init(data);
627	if (rc)
628		return rc;
629
630	indio_dev->info = &vcnl3020_info;
631	indio_dev->channels = vcnl3020_channels;
632	indio_dev->num_channels = ARRAY_SIZE(vcnl3020_channels);
633	indio_dev->name = "vcnl3020";
634	indio_dev->modes = INDIO_DIRECT_MODE;
635
636	if (client->irq) {
637		rc = devm_request_threaded_irq(&client->dev, client->irq,
638					       NULL, vcnl3020_handle_irq_thread,
639					       IRQF_ONESHOT, indio_dev->name,
640					       indio_dev);
641		if (rc) {
642			dev_err(&client->dev,
643				"Error (%d) irq request failed (%u)\n", rc,
644				client->irq);
645			return rc;
646		}
647	}
648
649	return devm_iio_device_register(&client->dev, indio_dev);
650}
651
652static const struct of_device_id vcnl3020_of_match[] = {
653	{
654		.compatible = "vishay,vcnl3020",
655	},
656	{}
657};
658MODULE_DEVICE_TABLE(of, vcnl3020_of_match);
659
660static struct i2c_driver vcnl3020_driver = {
661	.driver = {
662		.name   = "vcnl3020",
663		.of_match_table = vcnl3020_of_match,
664	},
665	.probe      = vcnl3020_probe,
666};
667module_i2c_driver(vcnl3020_driver);
668
669MODULE_AUTHOR("Ivan Mikhaylov <i.mikhaylov@yadro.com>");
670MODULE_DESCRIPTION("Vishay VCNL3020 proximity sensor driver");
671MODULE_LICENSE("GPL");
672