xref: /linux/drivers/iio/light/vcnl4000.c (revision ebd457d55911b5b5bc79404d460e1b72df806dea)
162a1efb9SPeter Meerwald /*
2be38866fSTomas Novotny  * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4200 combined ambient
3d978bfddSPeter Meerwald-Stadler  * light and proximity sensor
462a1efb9SPeter Meerwald  *
562a1efb9SPeter Meerwald  * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
662a1efb9SPeter Meerwald  *
762a1efb9SPeter Meerwald  * This file is subject to the terms and conditions of version 2 of
862a1efb9SPeter Meerwald  * the GNU General Public License.  See the file COPYING in the main
962a1efb9SPeter Meerwald  * directory of this archive for more details.
1062a1efb9SPeter Meerwald  *
11be38866fSTomas Novotny  * IIO driver for:
12be38866fSTomas Novotny  *   VCNL4000/10/20 (7-bit I2C slave address 0x13)
13be38866fSTomas Novotny  *   VCNL4200 (7-bit I2C slave address 0x51)
1462a1efb9SPeter Meerwald  *
1562a1efb9SPeter Meerwald  * TODO:
1662a1efb9SPeter Meerwald  *   allow to adjust IR current
1762a1efb9SPeter Meerwald  *   proximity threshold and event handling
18d978bfddSPeter Meerwald-Stadler  *   periodic ALS/proximity measurement (VCNL4010/20)
19be38866fSTomas Novotny  *   interrupts (VCNL4010/20, VCNL4200)
2062a1efb9SPeter Meerwald  */
2162a1efb9SPeter Meerwald 
2262a1efb9SPeter Meerwald #include <linux/module.h>
2362a1efb9SPeter Meerwald #include <linux/i2c.h>
2462a1efb9SPeter Meerwald #include <linux/err.h>
2562a1efb9SPeter Meerwald #include <linux/delay.h>
2662a1efb9SPeter Meerwald 
2762a1efb9SPeter Meerwald #include <linux/iio/iio.h>
2862a1efb9SPeter Meerwald #include <linux/iio/sysfs.h>
2962a1efb9SPeter Meerwald 
3062a1efb9SPeter Meerwald #define VCNL4000_DRV_NAME "vcnl4000"
311ebc787aSTomas Novotny #define VCNL4000_PROD_ID	0x01
321ebc787aSTomas Novotny #define VCNL4010_PROD_ID	0x02 /* for VCNL4020, VCNL4010 */
33be38866fSTomas Novotny #define VCNL4200_PROD_ID	0x58
3462a1efb9SPeter Meerwald 
3562a1efb9SPeter Meerwald #define VCNL4000_COMMAND	0x80 /* Command register */
3662a1efb9SPeter Meerwald #define VCNL4000_PROD_REV	0x81 /* Product ID and Revision ID */
3762a1efb9SPeter Meerwald #define VCNL4000_LED_CURRENT	0x83 /* IR LED current for proximity mode */
3862a1efb9SPeter Meerwald #define VCNL4000_AL_PARAM	0x84 /* Ambient light parameter register */
3962a1efb9SPeter Meerwald #define VCNL4000_AL_RESULT_HI	0x85 /* Ambient light result register, MSB */
4062a1efb9SPeter Meerwald #define VCNL4000_AL_RESULT_LO	0x86 /* Ambient light result register, LSB */
4162a1efb9SPeter Meerwald #define VCNL4000_PS_RESULT_HI	0x87 /* Proximity result register, MSB */
4262a1efb9SPeter Meerwald #define VCNL4000_PS_RESULT_LO	0x88 /* Proximity result register, LSB */
4362a1efb9SPeter Meerwald #define VCNL4000_PS_MEAS_FREQ	0x89 /* Proximity test signal frequency */
4462a1efb9SPeter Meerwald #define VCNL4000_PS_MOD_ADJ	0x8a /* Proximity modulator timing adjustment */
4562a1efb9SPeter Meerwald 
46be38866fSTomas Novotny #define VCNL4200_AL_CONF	0x00 /* Ambient light configuration */
47be38866fSTomas Novotny #define VCNL4200_PS_CONF1	0x03 /* Proximity configuration */
48be38866fSTomas Novotny #define VCNL4200_PS_DATA	0x08 /* Proximity data */
49be38866fSTomas Novotny #define VCNL4200_AL_DATA	0x09 /* Ambient light data */
50be38866fSTomas Novotny #define VCNL4200_DEV_ID		0x0e /* Device ID, slave address and version */
51be38866fSTomas Novotny 
5262a1efb9SPeter Meerwald /* Bit masks for COMMAND register */
53ff6a5259SPeter Meerwald-Stadler #define VCNL4000_AL_RDY		BIT(6) /* ALS data ready? */
54ff6a5259SPeter Meerwald-Stadler #define VCNL4000_PS_RDY		BIT(5) /* proximity data ready? */
55ff6a5259SPeter Meerwald-Stadler #define VCNL4000_AL_OD		BIT(4) /* start on-demand ALS measurement */
56ff6a5259SPeter Meerwald-Stadler #define VCNL4000_PS_OD		BIT(3) /* start on-demand proximity measurement */
5762a1efb9SPeter Meerwald 
581ebc787aSTomas Novotny enum vcnl4000_device_ids {
591ebc787aSTomas Novotny 	VCNL4000,
6050c50b97STomas Novotny 	VCNL4010,
61be38866fSTomas Novotny 	VCNL4200,
62be38866fSTomas Novotny };
63be38866fSTomas Novotny 
64be38866fSTomas Novotny struct vcnl4200_channel {
65be38866fSTomas Novotny 	u8 reg;
66be38866fSTomas Novotny 	ktime_t last_measurement;
67be38866fSTomas Novotny 	ktime_t sampling_rate;
68be38866fSTomas Novotny 	struct mutex lock;
691ebc787aSTomas Novotny };
701ebc787aSTomas Novotny 
7162a1efb9SPeter Meerwald struct vcnl4000_data {
7262a1efb9SPeter Meerwald 	struct i2c_client *client;
731ebc787aSTomas Novotny 	enum vcnl4000_device_ids id;
741ebc787aSTomas Novotny 	int rev;
751ebc787aSTomas Novotny 	int al_scale;
761ebc787aSTomas Novotny 	const struct vcnl4000_chip_spec *chip_spec;
77be38866fSTomas Novotny 	struct mutex vcnl4000_lock;
78be38866fSTomas Novotny 	struct vcnl4200_channel vcnl4200_al;
79be38866fSTomas Novotny 	struct vcnl4200_channel vcnl4200_ps;
8062a1efb9SPeter Meerwald };
8162a1efb9SPeter Meerwald 
821ebc787aSTomas Novotny struct vcnl4000_chip_spec {
831ebc787aSTomas Novotny 	const char *prod;
841ebc787aSTomas Novotny 	int (*init)(struct vcnl4000_data *data);
851ebc787aSTomas Novotny 	int (*measure_light)(struct vcnl4000_data *data, int *val);
861ebc787aSTomas Novotny 	int (*measure_proximity)(struct vcnl4000_data *data, int *val);
871ebc787aSTomas Novotny };
881ebc787aSTomas Novotny 
8962a1efb9SPeter Meerwald static const struct i2c_device_id vcnl4000_id[] = {
901ebc787aSTomas Novotny 	{ "vcnl4000", VCNL4000 },
9150c50b97STomas Novotny 	{ "vcnl4010", VCNL4010 },
9250c50b97STomas Novotny 	{ "vcnl4020", VCNL4010 },
93be38866fSTomas Novotny 	{ "vcnl4200", VCNL4200 },
9462a1efb9SPeter Meerwald 	{ }
9562a1efb9SPeter Meerwald };
9662a1efb9SPeter Meerwald MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
9762a1efb9SPeter Meerwald 
981ebc787aSTomas Novotny static int vcnl4000_init(struct vcnl4000_data *data)
991ebc787aSTomas Novotny {
1001ebc787aSTomas Novotny 	int ret, prod_id;
1011ebc787aSTomas Novotny 
1021ebc787aSTomas Novotny 	ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
1031ebc787aSTomas Novotny 	if (ret < 0)
1041ebc787aSTomas Novotny 		return ret;
1051ebc787aSTomas Novotny 
1061ebc787aSTomas Novotny 	prod_id = ret >> 4;
10758bf9aceSTomas Novotny 	switch (prod_id) {
10858bf9aceSTomas Novotny 	case VCNL4000_PROD_ID:
10958bf9aceSTomas Novotny 		if (data->id != VCNL4000)
11058bf9aceSTomas Novotny 			dev_warn(&data->client->dev,
11158bf9aceSTomas Novotny 					"wrong device id, use vcnl4000");
11258bf9aceSTomas Novotny 		break;
11358bf9aceSTomas Novotny 	case VCNL4010_PROD_ID:
11458bf9aceSTomas Novotny 		if (data->id != VCNL4010)
11558bf9aceSTomas Novotny 			dev_warn(&data->client->dev,
11658bf9aceSTomas Novotny 					"wrong device id, use vcnl4010/4020");
11758bf9aceSTomas Novotny 		break;
11858bf9aceSTomas Novotny 	default:
1191ebc787aSTomas Novotny 		return -ENODEV;
12058bf9aceSTomas Novotny 	}
1211ebc787aSTomas Novotny 
1221ebc787aSTomas Novotny 	data->rev = ret & 0xf;
1231ebc787aSTomas Novotny 	data->al_scale = 250000;
124be38866fSTomas Novotny 	mutex_init(&data->vcnl4000_lock);
125be38866fSTomas Novotny 
126be38866fSTomas Novotny 	return 0;
127be38866fSTomas Novotny };
128be38866fSTomas Novotny 
129be38866fSTomas Novotny static int vcnl4200_init(struct vcnl4000_data *data)
130be38866fSTomas Novotny {
131be38866fSTomas Novotny 	int ret;
132be38866fSTomas Novotny 
133be38866fSTomas Novotny 	ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
134be38866fSTomas Novotny 	if (ret < 0)
135be38866fSTomas Novotny 		return ret;
136be38866fSTomas Novotny 
137be38866fSTomas Novotny 	if ((ret & 0xff) != VCNL4200_PROD_ID)
138be38866fSTomas Novotny 		return -ENODEV;
139be38866fSTomas Novotny 
140be38866fSTomas Novotny 	data->rev = (ret >> 8) & 0xf;
141be38866fSTomas Novotny 
142be38866fSTomas Novotny 	/* Set defaults and enable both channels */
14378ed050dSAngus Ainslie (Purism) 	ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, 0);
144be38866fSTomas Novotny 	if (ret < 0)
145be38866fSTomas Novotny 		return ret;
14678ed050dSAngus Ainslie (Purism) 	ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, 0);
147be38866fSTomas Novotny 	if (ret < 0)
148be38866fSTomas Novotny 		return ret;
149be38866fSTomas Novotny 
150be38866fSTomas Novotny 	data->al_scale = 24000;
151be38866fSTomas Novotny 	data->vcnl4200_al.reg = VCNL4200_AL_DATA;
152be38866fSTomas Novotny 	data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
153be38866fSTomas Novotny 	/* Integration time is 50ms, but the experiments show 54ms in total. */
154be38866fSTomas Novotny 	data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000);
155be38866fSTomas Novotny 	data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000);
156be38866fSTomas Novotny 	data->vcnl4200_al.last_measurement = ktime_set(0, 0);
157be38866fSTomas Novotny 	data->vcnl4200_ps.last_measurement = ktime_set(0, 0);
158be38866fSTomas Novotny 	mutex_init(&data->vcnl4200_al.lock);
159be38866fSTomas Novotny 	mutex_init(&data->vcnl4200_ps.lock);
1601ebc787aSTomas Novotny 
1611ebc787aSTomas Novotny 	return 0;
1621ebc787aSTomas Novotny };
1631ebc787aSTomas Novotny 
16462a1efb9SPeter Meerwald static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
16562a1efb9SPeter Meerwald 				u8 rdy_mask, u8 data_reg, int *val)
16662a1efb9SPeter Meerwald {
16762a1efb9SPeter Meerwald 	int tries = 20;
16891f197e0SLars-Peter Clausen 	__be16 buf;
16962a1efb9SPeter Meerwald 	int ret;
17062a1efb9SPeter Meerwald 
171be38866fSTomas Novotny 	mutex_lock(&data->vcnl4000_lock);
172ff34ed6dSPeter Meerwald-Stadler 
17362a1efb9SPeter Meerwald 	ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
17462a1efb9SPeter Meerwald 					req_mask);
17562a1efb9SPeter Meerwald 	if (ret < 0)
176ff34ed6dSPeter Meerwald-Stadler 		goto fail;
17762a1efb9SPeter Meerwald 
17862a1efb9SPeter Meerwald 	/* wait for data to become ready */
17962a1efb9SPeter Meerwald 	while (tries--) {
18062a1efb9SPeter Meerwald 		ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
18162a1efb9SPeter Meerwald 		if (ret < 0)
182ff34ed6dSPeter Meerwald-Stadler 			goto fail;
18362a1efb9SPeter Meerwald 		if (ret & rdy_mask)
18462a1efb9SPeter Meerwald 			break;
18562a1efb9SPeter Meerwald 		msleep(20); /* measurement takes up to 100 ms */
18662a1efb9SPeter Meerwald 	}
18762a1efb9SPeter Meerwald 
18862a1efb9SPeter Meerwald 	if (tries < 0) {
18962a1efb9SPeter Meerwald 		dev_err(&data->client->dev,
19062a1efb9SPeter Meerwald 			"vcnl4000_measure() failed, data not ready\n");
191ff34ed6dSPeter Meerwald-Stadler 		ret = -EIO;
192ff34ed6dSPeter Meerwald-Stadler 		goto fail;
19362a1efb9SPeter Meerwald 	}
19462a1efb9SPeter Meerwald 
19562a1efb9SPeter Meerwald 	ret = i2c_smbus_read_i2c_block_data(data->client,
19662a1efb9SPeter Meerwald 		data_reg, sizeof(buf), (u8 *) &buf);
19762a1efb9SPeter Meerwald 	if (ret < 0)
198ff34ed6dSPeter Meerwald-Stadler 		goto fail;
19962a1efb9SPeter Meerwald 
200be38866fSTomas Novotny 	mutex_unlock(&data->vcnl4000_lock);
20162a1efb9SPeter Meerwald 	*val = be16_to_cpu(buf);
20262a1efb9SPeter Meerwald 
20362a1efb9SPeter Meerwald 	return 0;
204ff34ed6dSPeter Meerwald-Stadler 
205ff34ed6dSPeter Meerwald-Stadler fail:
206be38866fSTomas Novotny 	mutex_unlock(&data->vcnl4000_lock);
207ff34ed6dSPeter Meerwald-Stadler 	return ret;
20862a1efb9SPeter Meerwald }
20962a1efb9SPeter Meerwald 
210be38866fSTomas Novotny static int vcnl4200_measure(struct vcnl4000_data *data,
211be38866fSTomas Novotny 		struct vcnl4200_channel *chan, int *val)
212be38866fSTomas Novotny {
213be38866fSTomas Novotny 	int ret;
214be38866fSTomas Novotny 	s64 delta;
215be38866fSTomas Novotny 	ktime_t next_measurement;
216be38866fSTomas Novotny 
217be38866fSTomas Novotny 	mutex_lock(&chan->lock);
218be38866fSTomas Novotny 
219be38866fSTomas Novotny 	next_measurement = ktime_add(chan->last_measurement,
220be38866fSTomas Novotny 			chan->sampling_rate);
221be38866fSTomas Novotny 	delta = ktime_us_delta(next_measurement, ktime_get());
222be38866fSTomas Novotny 	if (delta > 0)
223be38866fSTomas Novotny 		usleep_range(delta, delta + 500);
224be38866fSTomas Novotny 	chan->last_measurement = ktime_get();
225be38866fSTomas Novotny 
226be38866fSTomas Novotny 	mutex_unlock(&chan->lock);
227be38866fSTomas Novotny 
228be38866fSTomas Novotny 	ret = i2c_smbus_read_word_data(data->client, chan->reg);
229be38866fSTomas Novotny 	if (ret < 0)
230be38866fSTomas Novotny 		return ret;
231be38866fSTomas Novotny 
232be38866fSTomas Novotny 	*val = ret;
233be38866fSTomas Novotny 
234be38866fSTomas Novotny 	return 0;
235be38866fSTomas Novotny }
236be38866fSTomas Novotny 
2371ebc787aSTomas Novotny static int vcnl4000_measure_light(struct vcnl4000_data *data, int *val)
2381ebc787aSTomas Novotny {
2391ebc787aSTomas Novotny 	return vcnl4000_measure(data,
2401ebc787aSTomas Novotny 			VCNL4000_AL_OD, VCNL4000_AL_RDY,
2411ebc787aSTomas Novotny 			VCNL4000_AL_RESULT_HI, val);
2421ebc787aSTomas Novotny }
2431ebc787aSTomas Novotny 
244be38866fSTomas Novotny static int vcnl4200_measure_light(struct vcnl4000_data *data, int *val)
245be38866fSTomas Novotny {
246be38866fSTomas Novotny 	return vcnl4200_measure(data, &data->vcnl4200_al, val);
247be38866fSTomas Novotny }
248be38866fSTomas Novotny 
2491ebc787aSTomas Novotny static int vcnl4000_measure_proximity(struct vcnl4000_data *data, int *val)
2501ebc787aSTomas Novotny {
2511ebc787aSTomas Novotny 	return vcnl4000_measure(data,
2521ebc787aSTomas Novotny 			VCNL4000_PS_OD, VCNL4000_PS_RDY,
2531ebc787aSTomas Novotny 			VCNL4000_PS_RESULT_HI, val);
2541ebc787aSTomas Novotny }
2551ebc787aSTomas Novotny 
256be38866fSTomas Novotny static int vcnl4200_measure_proximity(struct vcnl4000_data *data, int *val)
257be38866fSTomas Novotny {
258be38866fSTomas Novotny 	return vcnl4200_measure(data, &data->vcnl4200_ps, val);
259be38866fSTomas Novotny }
260be38866fSTomas Novotny 
2611ebc787aSTomas Novotny static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
2621ebc787aSTomas Novotny 	[VCNL4000] = {
2631ebc787aSTomas Novotny 		.prod = "VCNL4000",
2641ebc787aSTomas Novotny 		.init = vcnl4000_init,
2651ebc787aSTomas Novotny 		.measure_light = vcnl4000_measure_light,
2661ebc787aSTomas Novotny 		.measure_proximity = vcnl4000_measure_proximity,
2671ebc787aSTomas Novotny 	},
26850c50b97STomas Novotny 	[VCNL4010] = {
26950c50b97STomas Novotny 		.prod = "VCNL4010/4020",
27050c50b97STomas Novotny 		.init = vcnl4000_init,
27150c50b97STomas Novotny 		.measure_light = vcnl4000_measure_light,
27250c50b97STomas Novotny 		.measure_proximity = vcnl4000_measure_proximity,
27350c50b97STomas Novotny 	},
274be38866fSTomas Novotny 	[VCNL4200] = {
275be38866fSTomas Novotny 		.prod = "VCNL4200",
276be38866fSTomas Novotny 		.init = vcnl4200_init,
277be38866fSTomas Novotny 		.measure_light = vcnl4200_measure_light,
278be38866fSTomas Novotny 		.measure_proximity = vcnl4200_measure_proximity,
279be38866fSTomas Novotny 	},
2801ebc787aSTomas Novotny };
2811ebc787aSTomas Novotny 
28262a1efb9SPeter Meerwald static const struct iio_chan_spec vcnl4000_channels[] = {
28362a1efb9SPeter Meerwald 	{
28462a1efb9SPeter Meerwald 		.type = IIO_LIGHT,
285bb7c5940SJonathan Cameron 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
286bb7c5940SJonathan Cameron 			BIT(IIO_CHAN_INFO_SCALE),
28762a1efb9SPeter Meerwald 	}, {
28862a1efb9SPeter Meerwald 		.type = IIO_PROXIMITY,
289bb7c5940SJonathan Cameron 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
29062a1efb9SPeter Meerwald 	}
29162a1efb9SPeter Meerwald };
29262a1efb9SPeter Meerwald 
29362a1efb9SPeter Meerwald static int vcnl4000_read_raw(struct iio_dev *indio_dev,
29462a1efb9SPeter Meerwald 				struct iio_chan_spec const *chan,
29562a1efb9SPeter Meerwald 				int *val, int *val2, long mask)
29662a1efb9SPeter Meerwald {
2975d693139SPeter Meerwald-Stadler 	int ret;
29862a1efb9SPeter Meerwald 	struct vcnl4000_data *data = iio_priv(indio_dev);
29962a1efb9SPeter Meerwald 
30062a1efb9SPeter Meerwald 	switch (mask) {
30162a1efb9SPeter Meerwald 	case IIO_CHAN_INFO_RAW:
30262a1efb9SPeter Meerwald 		switch (chan->type) {
30362a1efb9SPeter Meerwald 		case IIO_LIGHT:
3041ebc787aSTomas Novotny 			ret = data->chip_spec->measure_light(data, val);
30562a1efb9SPeter Meerwald 			if (ret < 0)
30662a1efb9SPeter Meerwald 				return ret;
3075d693139SPeter Meerwald-Stadler 			return IIO_VAL_INT;
30862a1efb9SPeter Meerwald 		case IIO_PROXIMITY:
3091ebc787aSTomas Novotny 			ret = data->chip_spec->measure_proximity(data, val);
31062a1efb9SPeter Meerwald 			if (ret < 0)
31162a1efb9SPeter Meerwald 				return ret;
3125d693139SPeter Meerwald-Stadler 			return IIO_VAL_INT;
31362a1efb9SPeter Meerwald 		default:
3145d693139SPeter Meerwald-Stadler 			return -EINVAL;
31562a1efb9SPeter Meerwald 		}
31662a1efb9SPeter Meerwald 	case IIO_CHAN_INFO_SCALE:
3175d693139SPeter Meerwald-Stadler 		if (chan->type != IIO_LIGHT)
3185d693139SPeter Meerwald-Stadler 			return -EINVAL;
3195d693139SPeter Meerwald-Stadler 
32062a1efb9SPeter Meerwald 		*val = 0;
3211ebc787aSTomas Novotny 		*val2 = data->al_scale;
3225d693139SPeter Meerwald-Stadler 		return IIO_VAL_INT_PLUS_MICRO;
32362a1efb9SPeter Meerwald 	default:
3245d693139SPeter Meerwald-Stadler 		return -EINVAL;
32562a1efb9SPeter Meerwald 	}
32662a1efb9SPeter Meerwald }
32762a1efb9SPeter Meerwald 
32862a1efb9SPeter Meerwald static const struct iio_info vcnl4000_info = {
32962a1efb9SPeter Meerwald 	.read_raw = vcnl4000_read_raw,
33062a1efb9SPeter Meerwald };
33162a1efb9SPeter Meerwald 
332fc52692cSGreg Kroah-Hartman static int vcnl4000_probe(struct i2c_client *client,
33362a1efb9SPeter Meerwald 			  const struct i2c_device_id *id)
33462a1efb9SPeter Meerwald {
33562a1efb9SPeter Meerwald 	struct vcnl4000_data *data;
33662a1efb9SPeter Meerwald 	struct iio_dev *indio_dev;
3371ebc787aSTomas Novotny 	int ret;
33862a1efb9SPeter Meerwald 
3392669d723SPeter Meerwald 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
34062a1efb9SPeter Meerwald 	if (!indio_dev)
34162a1efb9SPeter Meerwald 		return -ENOMEM;
34262a1efb9SPeter Meerwald 
34362a1efb9SPeter Meerwald 	data = iio_priv(indio_dev);
34462a1efb9SPeter Meerwald 	i2c_set_clientdata(client, indio_dev);
34562a1efb9SPeter Meerwald 	data->client = client;
3461ebc787aSTomas Novotny 	data->id = id->driver_data;
3471ebc787aSTomas Novotny 	data->chip_spec = &vcnl4000_chip_spec_cfg[data->id];
34862a1efb9SPeter Meerwald 
3491ebc787aSTomas Novotny 	ret = data->chip_spec->init(data);
35062a1efb9SPeter Meerwald 	if (ret < 0)
3512669d723SPeter Meerwald 		return ret;
35262a1efb9SPeter Meerwald 
353d978bfddSPeter Meerwald-Stadler 	dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n",
3541ebc787aSTomas Novotny 		data->chip_spec->prod, data->rev);
35562a1efb9SPeter Meerwald 
35662a1efb9SPeter Meerwald 	indio_dev->dev.parent = &client->dev;
35762a1efb9SPeter Meerwald 	indio_dev->info = &vcnl4000_info;
35862a1efb9SPeter Meerwald 	indio_dev->channels = vcnl4000_channels;
35962a1efb9SPeter Meerwald 	indio_dev->num_channels = ARRAY_SIZE(vcnl4000_channels);
36062a1efb9SPeter Meerwald 	indio_dev->name = VCNL4000_DRV_NAME;
36162a1efb9SPeter Meerwald 	indio_dev->modes = INDIO_DIRECT_MODE;
36262a1efb9SPeter Meerwald 
363691dab42SSachin Kamat 	return devm_iio_device_register(&client->dev, indio_dev);
36462a1efb9SPeter Meerwald }
36562a1efb9SPeter Meerwald 
366*ebd457d5SAngus Ainslie (Purism) static const struct of_device_id vcnl_4000_of_match[] = {
367*ebd457d5SAngus Ainslie (Purism) 	{
368*ebd457d5SAngus Ainslie (Purism) 		.compatible = "vishay,vcnl4000",
369*ebd457d5SAngus Ainslie (Purism) 		.data = "VCNL4000",
370*ebd457d5SAngus Ainslie (Purism) 	},
371*ebd457d5SAngus Ainslie (Purism) 	{
372*ebd457d5SAngus Ainslie (Purism) 		.compatible = "vishay,vcnl4010",
373*ebd457d5SAngus Ainslie (Purism) 		.data = "VCNL4010",
374*ebd457d5SAngus Ainslie (Purism) 	},
375*ebd457d5SAngus Ainslie (Purism) 	{
376*ebd457d5SAngus Ainslie (Purism) 		.compatible = "vishay,vcnl4010",
377*ebd457d5SAngus Ainslie (Purism) 		.data = "VCNL4020",
378*ebd457d5SAngus Ainslie (Purism) 	},
379*ebd457d5SAngus Ainslie (Purism) 	{
380*ebd457d5SAngus Ainslie (Purism) 		.compatible = "vishay,vcnl4200",
381*ebd457d5SAngus Ainslie (Purism) 		.data = "VCNL4200",
382*ebd457d5SAngus Ainslie (Purism) 	},
383*ebd457d5SAngus Ainslie (Purism) 	{},
384*ebd457d5SAngus Ainslie (Purism) };
385*ebd457d5SAngus Ainslie (Purism) MODULE_DEVICE_TABLE(of, vcnl_4000_of_match);
386*ebd457d5SAngus Ainslie (Purism) 
38762a1efb9SPeter Meerwald static struct i2c_driver vcnl4000_driver = {
38862a1efb9SPeter Meerwald 	.driver = {
38962a1efb9SPeter Meerwald 		.name   = VCNL4000_DRV_NAME,
390*ebd457d5SAngus Ainslie (Purism) 		.of_match_table = vcnl_4000_of_match,
39162a1efb9SPeter Meerwald 	},
39262a1efb9SPeter Meerwald 	.probe  = vcnl4000_probe,
39362a1efb9SPeter Meerwald 	.id_table = vcnl4000_id,
39462a1efb9SPeter Meerwald };
39562a1efb9SPeter Meerwald 
39662a1efb9SPeter Meerwald module_i2c_driver(vcnl4000_driver);
39762a1efb9SPeter Meerwald 
39862a1efb9SPeter Meerwald MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
39962a1efb9SPeter Meerwald MODULE_DESCRIPTION("Vishay VCNL4000 proximity/ambient light sensor driver");
40062a1efb9SPeter Meerwald MODULE_LICENSE("GPL");
401