1// SPDX-License-Identifier: GPL-2.0
2/*
3 * VCNL4035 Ambient Light and Proximity Sensor - 7-bit I2C slave address 0x60
4 *
5 * Copyright (c) 2018, DENX Software Engineering GmbH
6 * Author: Parthiban Nallathambi <pn@denx.de>
7 *
8 * TODO: Proximity
9 */
10#include <linux/bitops.h>
11#include <linux/bitfield.h>
12#include <linux/i2c.h>
13#include <linux/module.h>
14#include <linux/pm_runtime.h>
15#include <linux/regmap.h>
16
17#include <linux/iio/buffer.h>
18#include <linux/iio/events.h>
19#include <linux/iio/iio.h>
20#include <linux/iio/sysfs.h>
21#include <linux/iio/trigger.h>
22#include <linux/iio/trigger_consumer.h>
23#include <linux/iio/triggered_buffer.h>
24
25#define VCNL4035_DRV_NAME	"vcnl4035"
26#define VCNL4035_IRQ_NAME	"vcnl4035_event"
27#define VCNL4035_REGMAP_NAME	"vcnl4035_regmap"
28
29/* Device registers */
30#define VCNL4035_ALS_CONF	0x00
31#define VCNL4035_ALS_THDH	0x01
32#define VCNL4035_ALS_THDL	0x02
33#define VCNL4035_ALS_DATA	0x0B
34#define VCNL4035_WHITE_DATA	0x0C
35#define VCNL4035_INT_FLAG	0x0D
36#define VCNL4035_DEV_ID		0x0E
37
38/* Register masks */
39#define VCNL4035_MODE_ALS_MASK		BIT(0)
40#define VCNL4035_MODE_ALS_WHITE_CHAN	BIT(8)
41#define VCNL4035_MODE_ALS_INT_MASK	BIT(1)
42#define VCNL4035_ALS_IT_MASK		GENMASK(7, 5)
43#define VCNL4035_ALS_PERS_MASK		GENMASK(3, 2)
44#define VCNL4035_INT_ALS_IF_H_MASK	BIT(12)
45#define VCNL4035_INT_ALS_IF_L_MASK	BIT(13)
46#define VCNL4035_DEV_ID_MASK		GENMASK(7, 0)
47
48/* Default values */
49#define VCNL4035_MODE_ALS_ENABLE	BIT(0)
50#define VCNL4035_MODE_ALS_DISABLE	0x00
51#define VCNL4035_MODE_ALS_INT_ENABLE	BIT(1)
52#define VCNL4035_MODE_ALS_INT_DISABLE	0
53#define VCNL4035_DEV_ID_VAL		0x80
54#define VCNL4035_ALS_IT_DEFAULT		0x01
55#define VCNL4035_ALS_PERS_DEFAULT	0x00
56#define VCNL4035_ALS_THDH_DEFAULT	5000
57#define VCNL4035_ALS_THDL_DEFAULT	100
58#define VCNL4035_SLEEP_DELAY_MS		2000
59
60struct vcnl4035_data {
61	struct i2c_client *client;
62	struct regmap *regmap;
63	unsigned int als_it_val;
64	unsigned int als_persistence;
65	unsigned int als_thresh_low;
66	unsigned int als_thresh_high;
67	struct iio_trigger *drdy_trigger0;
68};
69
70static inline bool vcnl4035_is_triggered(struct vcnl4035_data *data)
71{
72	int ret;
73	int reg;
74
75	ret = regmap_read(data->regmap, VCNL4035_INT_FLAG, &reg);
76	if (ret < 0)
77		return false;
78
79	return !!(reg &
80		(VCNL4035_INT_ALS_IF_H_MASK | VCNL4035_INT_ALS_IF_L_MASK));
81}
82
83static irqreturn_t vcnl4035_drdy_irq_thread(int irq, void *private)
84{
85	struct iio_dev *indio_dev = private;
86	struct vcnl4035_data *data = iio_priv(indio_dev);
87
88	if (vcnl4035_is_triggered(data)) {
89		iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
90							0,
91							IIO_EV_TYPE_THRESH,
92							IIO_EV_DIR_EITHER),
93				iio_get_time_ns(indio_dev));
94		iio_trigger_poll_chained(data->drdy_trigger0);
95		return IRQ_HANDLED;
96	}
97
98	return IRQ_NONE;
99}
100
101/* Triggered buffer */
102static irqreturn_t vcnl4035_trigger_consumer_handler(int irq, void *p)
103{
104	struct iio_poll_func *pf = p;
105	struct iio_dev *indio_dev = pf->indio_dev;
106	struct vcnl4035_data *data = iio_priv(indio_dev);
107	/* Ensure naturally aligned timestamp */
108	u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)]  __aligned(8);
109	int ret;
110
111	ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer);
112	if (ret < 0) {
113		dev_err(&data->client->dev,
114			"Trigger consumer can't read from sensor.\n");
115		goto fail_read;
116	}
117	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
118					iio_get_time_ns(indio_dev));
119
120fail_read:
121	iio_trigger_notify_done(indio_dev->trig);
122
123	return IRQ_HANDLED;
124}
125
126static int vcnl4035_als_drdy_set_state(struct iio_trigger *trigger,
127					bool enable_drdy)
128{
129	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trigger);
130	struct vcnl4035_data *data = iio_priv(indio_dev);
131	int val = enable_drdy ? VCNL4035_MODE_ALS_INT_ENABLE :
132					VCNL4035_MODE_ALS_INT_DISABLE;
133
134	return regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
135				 VCNL4035_MODE_ALS_INT_MASK,
136				 val);
137}
138
139static const struct iio_trigger_ops vcnl4035_trigger_ops = {
140	.validate_device = iio_trigger_validate_own_device,
141	.set_trigger_state = vcnl4035_als_drdy_set_state,
142};
143
144static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on)
145{
146	int ret;
147	struct device *dev = &data->client->dev;
148
149	if (on) {
150		ret = pm_runtime_get_sync(dev);
151		if (ret < 0)
152			pm_runtime_put_noidle(dev);
153	} else {
154		pm_runtime_mark_last_busy(dev);
155		ret = pm_runtime_put_autosuspend(dev);
156	}
157
158	return ret;
159}
160
161/*
162 *	Device IT	INT Time (ms)	Scale (lux/step)
163 *	000		50		0.064
164 *	001		100		0.032
165 *	010		200		0.016
166 *	100		400		0.008
167 *	101 - 111	800		0.004
168 * Values are proportional, so ALS INT is selected for input due to
169 * simplicity reason. Integration time value and scaling is
170 * calculated based on device INT value
171 *
172 * Raw value needs to be scaled using ALS steps
173 */
174static int vcnl4035_read_raw(struct iio_dev *indio_dev,
175			    struct iio_chan_spec const *chan, int *val,
176			    int *val2, long mask)
177{
178	struct vcnl4035_data *data = iio_priv(indio_dev);
179	int ret;
180	int raw_data;
181	unsigned int reg;
182
183	switch (mask) {
184	case IIO_CHAN_INFO_RAW:
185		ret = vcnl4035_set_pm_runtime_state(data, true);
186		if  (ret < 0)
187			return ret;
188
189		ret = iio_device_claim_direct_mode(indio_dev);
190		if (!ret) {
191			if (chan->channel)
192				reg = VCNL4035_ALS_DATA;
193			else
194				reg = VCNL4035_WHITE_DATA;
195			ret = regmap_read(data->regmap, reg, &raw_data);
196			iio_device_release_direct_mode(indio_dev);
197			if (!ret) {
198				*val = raw_data;
199				ret = IIO_VAL_INT;
200			}
201		}
202		vcnl4035_set_pm_runtime_state(data, false);
203		return ret;
204	case IIO_CHAN_INFO_INT_TIME:
205		*val = 50;
206		if (data->als_it_val)
207			*val = data->als_it_val * 100;
208		return IIO_VAL_INT;
209	case IIO_CHAN_INFO_SCALE:
210		*val = 64;
211		if (!data->als_it_val)
212			*val2 = 1000;
213		else
214			*val2 = data->als_it_val * 2 * 1000;
215		return IIO_VAL_FRACTIONAL;
216	default:
217		return -EINVAL;
218	}
219}
220
221static int vcnl4035_write_raw(struct iio_dev *indio_dev,
222				struct iio_chan_spec const *chan,
223				int val, int val2, long mask)
224{
225	int ret;
226	struct vcnl4035_data *data = iio_priv(indio_dev);
227
228	switch (mask) {
229	case IIO_CHAN_INFO_INT_TIME:
230		if (val <= 0 || val > 800)
231			return -EINVAL;
232
233		ret = vcnl4035_set_pm_runtime_state(data, true);
234		if  (ret < 0)
235			return ret;
236
237		ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
238					 VCNL4035_ALS_IT_MASK,
239					 val / 100);
240		if (!ret)
241			data->als_it_val = val / 100;
242
243		vcnl4035_set_pm_runtime_state(data, false);
244		return ret;
245	default:
246		return -EINVAL;
247	}
248}
249
250/* No direct ABI for persistence and threshold, so eventing */
251static int vcnl4035_read_thresh(struct iio_dev *indio_dev,
252		const struct iio_chan_spec *chan, enum iio_event_type type,
253		enum iio_event_direction dir, enum iio_event_info info,
254		int *val, int *val2)
255{
256	struct vcnl4035_data *data = iio_priv(indio_dev);
257
258	switch (info) {
259	case IIO_EV_INFO_VALUE:
260		switch (dir) {
261		case IIO_EV_DIR_RISING:
262			*val = data->als_thresh_high;
263			return IIO_VAL_INT;
264		case IIO_EV_DIR_FALLING:
265			*val = data->als_thresh_low;
266			return IIO_VAL_INT;
267		default:
268			return -EINVAL;
269		}
270		break;
271	case IIO_EV_INFO_PERIOD:
272		*val = data->als_persistence;
273		return IIO_VAL_INT;
274	default:
275		return -EINVAL;
276	}
277
278}
279
280static int vcnl4035_write_thresh(struct iio_dev *indio_dev,
281		const struct iio_chan_spec *chan, enum iio_event_type type,
282		enum iio_event_direction dir, enum iio_event_info info, int val,
283		int val2)
284{
285	struct vcnl4035_data *data = iio_priv(indio_dev);
286	int ret;
287
288	switch (info) {
289	case IIO_EV_INFO_VALUE:
290		/* 16 bit threshold range 0 - 65535 */
291		if (val < 0 || val > 65535)
292			return -EINVAL;
293		if (dir == IIO_EV_DIR_RISING) {
294			if (val < data->als_thresh_low)
295				return -EINVAL;
296			ret = regmap_write(data->regmap, VCNL4035_ALS_THDH,
297					   val);
298			if (ret)
299				return ret;
300			data->als_thresh_high = val;
301		} else {
302			if (val > data->als_thresh_high)
303				return -EINVAL;
304			ret = regmap_write(data->regmap, VCNL4035_ALS_THDL,
305					   val);
306			if (ret)
307				return ret;
308			data->als_thresh_low = val;
309		}
310		return ret;
311	case IIO_EV_INFO_PERIOD:
312		/* allow only 1 2 4 8 as persistence value */
313		if (val < 0 || val > 8 || hweight8(val) != 1)
314			return -EINVAL;
315		ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
316					 VCNL4035_ALS_PERS_MASK, val);
317		if (!ret)
318			data->als_persistence = val;
319		return ret;
320	default:
321		return -EINVAL;
322	}
323}
324
325static IIO_CONST_ATTR_INT_TIME_AVAIL("50 100 200 400 800");
326
327static struct attribute *vcnl4035_attributes[] = {
328	&iio_const_attr_integration_time_available.dev_attr.attr,
329	NULL,
330};
331
332static const struct attribute_group vcnl4035_attribute_group = {
333	.attrs = vcnl4035_attributes,
334};
335
336static const struct iio_info vcnl4035_info = {
337	.read_raw		= vcnl4035_read_raw,
338	.write_raw		= vcnl4035_write_raw,
339	.read_event_value	= vcnl4035_read_thresh,
340	.write_event_value	= vcnl4035_write_thresh,
341	.attrs			= &vcnl4035_attribute_group,
342};
343
344static const struct iio_event_spec vcnl4035_event_spec[] = {
345	{
346		.type = IIO_EV_TYPE_THRESH,
347		.dir = IIO_EV_DIR_RISING,
348		.mask_separate = BIT(IIO_EV_INFO_VALUE),
349	}, {
350		.type = IIO_EV_TYPE_THRESH,
351		.dir = IIO_EV_DIR_FALLING,
352		.mask_separate = BIT(IIO_EV_INFO_VALUE),
353	}, {
354		.type = IIO_EV_TYPE_THRESH,
355		.dir = IIO_EV_DIR_EITHER,
356		.mask_separate = BIT(IIO_EV_INFO_PERIOD),
357	},
358};
359
360enum vcnl4035_scan_index_order {
361	VCNL4035_CHAN_INDEX_LIGHT,
362	VCNL4035_CHAN_INDEX_WHITE_LED,
363};
364
365static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
366	.validate_scan_mask = &iio_validate_scan_mask_onehot,
367};
368
369static const struct iio_chan_spec vcnl4035_channels[] = {
370	{
371		.type = IIO_LIGHT,
372		.channel = 0,
373		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
374				BIT(IIO_CHAN_INFO_INT_TIME) |
375				BIT(IIO_CHAN_INFO_SCALE),
376		.event_spec = vcnl4035_event_spec,
377		.num_event_specs = ARRAY_SIZE(vcnl4035_event_spec),
378		.scan_index = VCNL4035_CHAN_INDEX_LIGHT,
379		.scan_type = {
380			.sign = 'u',
381			.realbits = 16,
382			.storagebits = 16,
383			.endianness = IIO_LE,
384		},
385	},
386	{
387		.type = IIO_INTENSITY,
388		.channel = 1,
389		.modified = 1,
390		.channel2 = IIO_MOD_LIGHT_BOTH,
391		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
392		.scan_index = VCNL4035_CHAN_INDEX_WHITE_LED,
393		.scan_type = {
394			.sign = 'u',
395			.realbits = 16,
396			.storagebits = 16,
397			.endianness = IIO_LE,
398		},
399	},
400};
401
402static int vcnl4035_set_als_power_state(struct vcnl4035_data *data, u8 status)
403{
404	return regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
405					VCNL4035_MODE_ALS_MASK,
406					status);
407}
408
409static int vcnl4035_init(struct vcnl4035_data *data)
410{
411	int ret;
412	int id;
413
414	ret = regmap_read(data->regmap, VCNL4035_DEV_ID, &id);
415	if (ret < 0) {
416		dev_err(&data->client->dev, "Failed to read DEV_ID register\n");
417		return ret;
418	}
419
420	id = FIELD_GET(VCNL4035_DEV_ID_MASK, id);
421	if (id != VCNL4035_DEV_ID_VAL) {
422		dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n",
423			id, VCNL4035_DEV_ID_VAL);
424		return -ENODEV;
425	}
426
427	ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
428	if (ret < 0)
429		return ret;
430
431	/* ALS white channel enable */
432	ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
433				 VCNL4035_MODE_ALS_WHITE_CHAN,
434				 1);
435	if (ret) {
436		dev_err(&data->client->dev, "set white channel enable %d\n",
437			ret);
438		return ret;
439	}
440
441	/* set default integration time - 100 ms for ALS */
442	ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
443				 VCNL4035_ALS_IT_MASK,
444				 VCNL4035_ALS_IT_DEFAULT);
445	if (ret) {
446		dev_err(&data->client->dev, "set default ALS IT returned %d\n",
447			ret);
448		return ret;
449	}
450	data->als_it_val = VCNL4035_ALS_IT_DEFAULT;
451
452	/* set default persistence time - 1 for ALS */
453	ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
454				 VCNL4035_ALS_PERS_MASK,
455				 VCNL4035_ALS_PERS_DEFAULT);
456	if (ret) {
457		dev_err(&data->client->dev, "set default PERS returned %d\n",
458			ret);
459		return ret;
460	}
461	data->als_persistence = VCNL4035_ALS_PERS_DEFAULT;
462
463	/* set default HIGH threshold for ALS */
464	ret = regmap_write(data->regmap, VCNL4035_ALS_THDH,
465				VCNL4035_ALS_THDH_DEFAULT);
466	if (ret) {
467		dev_err(&data->client->dev, "set default THDH returned %d\n",
468			ret);
469		return ret;
470	}
471	data->als_thresh_high = VCNL4035_ALS_THDH_DEFAULT;
472
473	/* set default LOW threshold for ALS */
474	ret = regmap_write(data->regmap, VCNL4035_ALS_THDL,
475				VCNL4035_ALS_THDL_DEFAULT);
476	if (ret) {
477		dev_err(&data->client->dev, "set default THDL returned %d\n",
478			ret);
479		return ret;
480	}
481	data->als_thresh_low = VCNL4035_ALS_THDL_DEFAULT;
482
483	return 0;
484}
485
486static bool vcnl4035_is_volatile_reg(struct device *dev, unsigned int reg)
487{
488	switch (reg) {
489	case VCNL4035_ALS_CONF:
490	case VCNL4035_DEV_ID:
491		return false;
492	default:
493		return true;
494	}
495}
496
497static const struct regmap_config vcnl4035_regmap_config = {
498	.name		= VCNL4035_REGMAP_NAME,
499	.reg_bits	= 8,
500	.val_bits	= 16,
501	.max_register	= VCNL4035_DEV_ID,
502	.cache_type	= REGCACHE_RBTREE,
503	.volatile_reg	= vcnl4035_is_volatile_reg,
504	.val_format_endian = REGMAP_ENDIAN_LITTLE,
505};
506
507static int vcnl4035_probe_trigger(struct iio_dev *indio_dev)
508{
509	int ret;
510	struct vcnl4035_data *data = iio_priv(indio_dev);
511
512	data->drdy_trigger0 = devm_iio_trigger_alloc(
513			indio_dev->dev.parent,
514			"%s-dev%d", indio_dev->name, indio_dev->id);
515	if (!data->drdy_trigger0)
516		return -ENOMEM;
517
518	data->drdy_trigger0->dev.parent = indio_dev->dev.parent;
519	data->drdy_trigger0->ops = &vcnl4035_trigger_ops;
520	iio_trigger_set_drvdata(data->drdy_trigger0, indio_dev);
521	ret = devm_iio_trigger_register(indio_dev->dev.parent,
522					data->drdy_trigger0);
523	if (ret) {
524		dev_err(&data->client->dev, "iio trigger register failed\n");
525		return ret;
526	}
527
528	/* Trigger setup */
529	ret = devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
530					NULL, vcnl4035_trigger_consumer_handler,
531					&iio_triggered_buffer_setup_ops);
532	if (ret < 0) {
533		dev_err(&data->client->dev, "iio triggered buffer setup failed\n");
534		return ret;
535	}
536
537	/* IRQ to trigger mapping */
538	ret = devm_request_threaded_irq(&data->client->dev, data->client->irq,
539			NULL, vcnl4035_drdy_irq_thread,
540			IRQF_TRIGGER_LOW | IRQF_ONESHOT,
541			VCNL4035_IRQ_NAME, indio_dev);
542	if (ret < 0)
543		dev_err(&data->client->dev, "request irq %d for trigger0 failed\n",
544				data->client->irq);
545	return ret;
546}
547
548static int vcnl4035_probe(struct i2c_client *client,
549				const struct i2c_device_id *id)
550{
551	struct vcnl4035_data *data;
552	struct iio_dev *indio_dev;
553	struct regmap *regmap;
554	int ret;
555
556	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
557	if (!indio_dev)
558		return -ENOMEM;
559
560	regmap = devm_regmap_init_i2c(client, &vcnl4035_regmap_config);
561	if (IS_ERR(regmap)) {
562		dev_err(&client->dev, "regmap_init failed!\n");
563		return PTR_ERR(regmap);
564	}
565
566	data = iio_priv(indio_dev);
567	i2c_set_clientdata(client, indio_dev);
568	data->client = client;
569	data->regmap = regmap;
570
571	indio_dev->info = &vcnl4035_info;
572	indio_dev->name = VCNL4035_DRV_NAME;
573	indio_dev->channels = vcnl4035_channels;
574	indio_dev->num_channels = ARRAY_SIZE(vcnl4035_channels);
575	indio_dev->modes = INDIO_DIRECT_MODE;
576
577	ret = vcnl4035_init(data);
578	if (ret < 0) {
579		dev_err(&client->dev, "vcnl4035 chip init failed\n");
580		return ret;
581	}
582
583	if (client->irq > 0) {
584		ret = vcnl4035_probe_trigger(indio_dev);
585		if (ret < 0) {
586			dev_err(&client->dev, "vcnl4035 unable init trigger\n");
587			goto fail_poweroff;
588		}
589	}
590
591	ret = pm_runtime_set_active(&client->dev);
592	if (ret < 0)
593		goto fail_poweroff;
594
595	ret = iio_device_register(indio_dev);
596	if (ret < 0)
597		goto fail_poweroff;
598
599	pm_runtime_enable(&client->dev);
600	pm_runtime_set_autosuspend_delay(&client->dev, VCNL4035_SLEEP_DELAY_MS);
601	pm_runtime_use_autosuspend(&client->dev);
602
603	return 0;
604
605fail_poweroff:
606	vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_DISABLE);
607	return ret;
608}
609
610static int vcnl4035_remove(struct i2c_client *client)
611{
612	struct iio_dev *indio_dev = i2c_get_clientdata(client);
613
614	pm_runtime_dont_use_autosuspend(&client->dev);
615	pm_runtime_disable(&client->dev);
616	iio_device_unregister(indio_dev);
617	pm_runtime_set_suspended(&client->dev);
618
619	return vcnl4035_set_als_power_state(iio_priv(indio_dev),
620					VCNL4035_MODE_ALS_DISABLE);
621}
622
623static int __maybe_unused vcnl4035_runtime_suspend(struct device *dev)
624{
625	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
626	struct vcnl4035_data *data = iio_priv(indio_dev);
627	int ret;
628
629	ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_DISABLE);
630	regcache_mark_dirty(data->regmap);
631
632	return ret;
633}
634
635static int __maybe_unused vcnl4035_runtime_resume(struct device *dev)
636{
637	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
638	struct vcnl4035_data *data = iio_priv(indio_dev);
639	int ret;
640
641	regcache_sync(data->regmap);
642	ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
643	if (ret < 0)
644		return ret;
645
646	/* wait for 1 ALS integration cycle */
647	msleep(data->als_it_val * 100);
648
649	return 0;
650}
651
652static const struct dev_pm_ops vcnl4035_pm_ops = {
653	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
654				pm_runtime_force_resume)
655	SET_RUNTIME_PM_OPS(vcnl4035_runtime_suspend,
656			   vcnl4035_runtime_resume, NULL)
657};
658
659static const struct of_device_id vcnl4035_of_match[] = {
660	{ .compatible = "vishay,vcnl4035", },
661	{ }
662};
663MODULE_DEVICE_TABLE(of, vcnl4035_of_match);
664
665static struct i2c_driver vcnl4035_driver = {
666	.driver = {
667		.name   = VCNL4035_DRV_NAME,
668		.pm	= &vcnl4035_pm_ops,
669		.of_match_table = vcnl4035_of_match,
670	},
671	.probe  = vcnl4035_probe,
672	.remove	= vcnl4035_remove,
673};
674
675module_i2c_driver(vcnl4035_driver);
676
677MODULE_AUTHOR("Parthiban Nallathambi <pn@denx.de>");
678MODULE_DESCRIPTION("VCNL4035 Ambient Light Sensor driver");
679MODULE_LICENSE("GPL v2");
680