2 * vl6180.c - Support for STMicroelectronics VL6180 ALS, range and proximity
5 * Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
6 * Copyright 2017 Manivannan Sadhasivam <manivannanece23@gmail.com>
8 * This file is subject to the terms and conditions of version 2 of
9 * the GNU General Public License. See the file COPYING in the main
10 * directory of this archive for more details.
12 * IIO driver for VL6180 (7-bit I2C slave address 0x29)
15 * ALS: < 1 Lux up to 100 kLux
18 * TODO: irq, threshold events, continuous mode, hardware buffer
21 #include <linux/module.h>
22 #include <linux/i2c.h>
23 #include <linux/mutex.h>
24 #include <linux/err.h>
26 #include <linux/delay.h>
27 #include <linux/util_macros.h>
29 #include <linux/iio/iio.h>
30 #include <linux/iio/sysfs.h>
32 #define VL6180_DRV_NAME "vl6180"
34 /* Device identification register and value */
35 #define VL6180_MODEL_ID 0x000
36 #define VL6180_MODEL_ID_VAL 0xb4
38 /* Configuration registers */
39 #define VL6180_INTR_CONFIG 0x014
40 #define VL6180_INTR_CLEAR 0x015
41 #define VL6180_OUT_OF_RESET 0x016
42 #define VL6180_HOLD 0x017
43 #define VL6180_RANGE_START 0x018
44 #define VL6180_ALS_START 0x038
45 #define VL6180_ALS_GAIN 0x03f
46 #define VL6180_ALS_IT 0x040
48 /* Status registers */
49 #define VL6180_RANGE_STATUS 0x04d
50 #define VL6180_ALS_STATUS 0x04e
51 #define VL6180_INTR_STATUS 0x04f
53 /* Result value registers */
54 #define VL6180_ALS_VALUE 0x050
55 #define VL6180_RANGE_VALUE 0x062
56 #define VL6180_RANGE_RATE 0x066
58 /* bits of the RANGE_START and ALS_START register */
59 #define VL6180_MODE_CONT BIT(1) /* continuous mode */
60 #define VL6180_STARTSTOP BIT(0) /* start measurement, auto-reset */
62 /* bits of the INTR_STATUS and INTR_CONFIG register */
63 #define VL6180_ALS_READY BIT(5)
64 #define VL6180_RANGE_READY BIT(2)
66 /* bits of the INTR_CLEAR register */
67 #define VL6180_CLEAR_ERROR BIT(2)
68 #define VL6180_CLEAR_ALS BIT(1)
69 #define VL6180_CLEAR_RANGE BIT(0)
71 /* bits of the HOLD register */
72 #define VL6180_HOLD_ON BIT(0)
74 /* default value for the ALS_IT register */
75 #define VL6180_ALS_IT_100 0x63 /* 100 ms */
77 /* values for the ALS_GAIN register */
78 #define VL6180_ALS_GAIN_1 0x46
79 #define VL6180_ALS_GAIN_1_25 0x45
80 #define VL6180_ALS_GAIN_1_67 0x44
81 #define VL6180_ALS_GAIN_2_5 0x43
82 #define VL6180_ALS_GAIN_5 0x42
83 #define VL6180_ALS_GAIN_10 0x41
84 #define VL6180_ALS_GAIN_20 0x40
85 #define VL6180_ALS_GAIN_40 0x47
88 struct i2c_client
*client
;
90 unsigned int als_gain_milli
;
91 unsigned int als_it_ms
;
94 enum { VL6180_ALS
, VL6180_RANGE
, VL6180_PROX
};
97 * struct vl6180_chan_regs - Registers for accessing channels
98 * @drdy_mask: Data ready bit in status register
99 * @start_reg: Conversion start register
100 * @value_reg: Result value register
101 * @word: Register word length
103 struct vl6180_chan_regs
{
105 u16 start_reg
, value_reg
;
109 static const struct vl6180_chan_regs vl6180_chan_regs_table
[] = {
111 .drdy_mask
= VL6180_ALS_READY
,
112 .start_reg
= VL6180_ALS_START
,
113 .value_reg
= VL6180_ALS_VALUE
,
117 .drdy_mask
= VL6180_RANGE_READY
,
118 .start_reg
= VL6180_RANGE_START
,
119 .value_reg
= VL6180_RANGE_VALUE
,
123 .drdy_mask
= VL6180_RANGE_READY
,
124 .start_reg
= VL6180_RANGE_START
,
125 .value_reg
= VL6180_RANGE_RATE
,
130 static int vl6180_read(struct i2c_client
*client
, u16 cmd
, void *databuf
,
133 __be16 cmdbuf
= cpu_to_be16(cmd
);
134 struct i2c_msg msgs
[2] = {
135 { .addr
= client
->addr
, .len
= sizeof(cmdbuf
), .buf
= (u8
*) &cmdbuf
},
136 { .addr
= client
->addr
, .len
= len
, .buf
= databuf
,
137 .flags
= I2C_M_RD
} };
140 ret
= i2c_transfer(client
->adapter
, msgs
, ARRAY_SIZE(msgs
));
142 dev_err(&client
->dev
, "failed reading register 0x%04x\n", cmd
);
147 static int vl6180_read_byte(struct i2c_client
*client
, u16 cmd
)
152 ret
= vl6180_read(client
, cmd
, &data
, sizeof(data
));
159 static int vl6180_read_word(struct i2c_client
*client
, u16 cmd
)
164 ret
= vl6180_read(client
, cmd
, &data
, sizeof(data
));
168 return be16_to_cpu(data
);
171 static int vl6180_write_byte(struct i2c_client
*client
, u16 cmd
, u8 val
)
174 struct i2c_msg msgs
[1] = {
175 { .addr
= client
->addr
, .len
= sizeof(buf
), .buf
= (u8
*) &buf
} };
182 ret
= i2c_transfer(client
->adapter
, msgs
, ARRAY_SIZE(msgs
));
184 dev_err(&client
->dev
, "failed writing register 0x%04x\n", cmd
);
191 static int vl6180_write_word(struct i2c_client
*client
, u16 cmd
, u16 val
)
194 struct i2c_msg msgs
[1] = {
195 { .addr
= client
->addr
, .len
= sizeof(buf
), .buf
= (u8
*) &buf
} };
198 buf
[0] = cpu_to_be16(cmd
);
199 buf
[1] = cpu_to_be16(val
);
201 ret
= i2c_transfer(client
->adapter
, msgs
, ARRAY_SIZE(msgs
));
203 dev_err(&client
->dev
, "failed writing register 0x%04x\n", cmd
);
210 static int vl6180_measure(struct vl6180_data
*data
, int addr
)
212 struct i2c_client
*client
= data
->client
;
216 mutex_lock(&data
->lock
);
217 /* Start single shot measurement */
218 ret
= vl6180_write_byte(client
,
219 vl6180_chan_regs_table
[addr
].start_reg
, VL6180_STARTSTOP
);
224 ret
= vl6180_read_byte(client
, VL6180_INTR_STATUS
);
228 if (ret
& vl6180_chan_regs_table
[addr
].drdy_mask
)
238 /* Read result value from appropriate registers */
239 ret
= vl6180_chan_regs_table
[addr
].word
?
240 vl6180_read_word(client
, vl6180_chan_regs_table
[addr
].value_reg
) :
241 vl6180_read_byte(client
, vl6180_chan_regs_table
[addr
].value_reg
);
246 /* Clear the interrupt flag after data read */
247 ret
= vl6180_write_byte(client
, VL6180_INTR_CLEAR
,
248 VL6180_CLEAR_ERROR
| VL6180_CLEAR_ALS
| VL6180_CLEAR_RANGE
);
255 mutex_unlock(&data
->lock
);
260 static const struct iio_chan_spec vl6180_channels
[] = {
263 .address
= VL6180_ALS
,
264 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
) |
265 BIT(IIO_CHAN_INFO_INT_TIME
) |
266 BIT(IIO_CHAN_INFO_SCALE
) |
267 BIT(IIO_CHAN_INFO_HARDWAREGAIN
),
269 .type
= IIO_DISTANCE
,
270 .address
= VL6180_RANGE
,
271 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
) |
272 BIT(IIO_CHAN_INFO_SCALE
),
274 .type
= IIO_PROXIMITY
,
275 .address
= VL6180_PROX
,
276 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
),
281 * Available Ambient Light Sensor gain settings, 1/1000th, and
282 * corresponding setting for the VL6180_ALS_GAIN register
284 static const int vl6180_als_gain_tab
[8] = {
285 1000, 1250, 1670, 2500, 5000, 10000, 20000, 40000
287 static const u8 vl6180_als_gain_tab_bits
[8] = {
288 VL6180_ALS_GAIN_1
, VL6180_ALS_GAIN_1_25
,
289 VL6180_ALS_GAIN_1_67
, VL6180_ALS_GAIN_2_5
,
290 VL6180_ALS_GAIN_5
, VL6180_ALS_GAIN_10
,
291 VL6180_ALS_GAIN_20
, VL6180_ALS_GAIN_40
294 static int vl6180_read_raw(struct iio_dev
*indio_dev
,
295 struct iio_chan_spec
const *chan
,
296 int *val
, int *val2
, long mask
)
298 struct vl6180_data
*data
= iio_priv(indio_dev
);
302 case IIO_CHAN_INFO_RAW
:
303 ret
= vl6180_measure(data
, chan
->address
);
309 case IIO_CHAN_INFO_INT_TIME
:
310 *val
= data
->als_it_ms
;
313 return IIO_VAL_FRACTIONAL
;
315 case IIO_CHAN_INFO_SCALE
:
316 switch (chan
->type
) {
318 /* one ALS count is 0.32 Lux @ gain 1, IT 100 ms */
319 *val
= 32000; /* 0.32 * 1000 * 100 */
320 *val2
= data
->als_gain_milli
* data
->als_it_ms
;
322 return IIO_VAL_FRACTIONAL
;
325 *val
= 0; /* sensor reports mm, scale to meter */
332 return IIO_VAL_INT_PLUS_MICRO
;
333 case IIO_CHAN_INFO_HARDWAREGAIN
:
334 *val
= data
->als_gain_milli
;
337 return IIO_VAL_FRACTIONAL
;
344 static IIO_CONST_ATTR(als_gain_available
, "1 1.25 1.67 2.5 5 10 20 40");
346 static struct attribute
*vl6180_attributes
[] = {
347 &iio_const_attr_als_gain_available
.dev_attr
.attr
,
351 static const struct attribute_group vl6180_attribute_group
= {
352 .attrs
= vl6180_attributes
,
355 /* HOLD is needed before updating any config registers */
356 static int vl6180_hold(struct vl6180_data
*data
, bool hold
)
358 return vl6180_write_byte(data
->client
, VL6180_HOLD
,
359 hold
? VL6180_HOLD_ON
: 0);
362 static int vl6180_set_als_gain(struct vl6180_data
*data
, int val
, int val2
)
366 if (val
< 1 || val
> 40)
369 gain
= (val
* 1000000 + val2
) / 1000;
370 if (gain
< 1 || gain
> 40000)
373 i
= find_closest(gain
, vl6180_als_gain_tab
,
374 ARRAY_SIZE(vl6180_als_gain_tab
));
376 mutex_lock(&data
->lock
);
377 ret
= vl6180_hold(data
, true);
381 ret
= vl6180_write_byte(data
->client
, VL6180_ALS_GAIN
,
382 vl6180_als_gain_tab_bits
[i
]);
385 data
->als_gain_milli
= vl6180_als_gain_tab
[i
];
388 vl6180_hold(data
, false);
389 mutex_unlock(&data
->lock
);
393 static int vl6180_set_it(struct vl6180_data
*data
, int val
, int val2
)
397 it_ms
= (val2
+ 500) / 1000; /* round to ms */
398 if (val
!= 0 || it_ms
< 1 || it_ms
> 512)
401 mutex_lock(&data
->lock
);
402 ret
= vl6180_hold(data
, true);
406 ret
= vl6180_write_word(data
->client
, VL6180_ALS_IT
, it_ms
- 1);
409 data
->als_it_ms
= it_ms
;
412 vl6180_hold(data
, false);
413 mutex_unlock(&data
->lock
);
418 static int vl6180_write_raw(struct iio_dev
*indio_dev
,
419 struct iio_chan_spec
const *chan
,
420 int val
, int val2
, long mask
)
422 struct vl6180_data
*data
= iio_priv(indio_dev
);
425 case IIO_CHAN_INFO_INT_TIME
:
426 return vl6180_set_it(data
, val
, val2
);
428 case IIO_CHAN_INFO_HARDWAREGAIN
:
429 if (chan
->type
!= IIO_LIGHT
)
432 return vl6180_set_als_gain(data
, val
, val2
);
438 static const struct iio_info vl6180_info
= {
439 .read_raw
= vl6180_read_raw
,
440 .write_raw
= vl6180_write_raw
,
441 .attrs
= &vl6180_attribute_group
,
444 static int vl6180_init(struct vl6180_data
*data
)
446 struct i2c_client
*client
= data
->client
;
449 ret
= vl6180_read_byte(client
, VL6180_MODEL_ID
);
453 if (ret
!= VL6180_MODEL_ID_VAL
) {
454 dev_err(&client
->dev
, "invalid model ID %02x\n", ret
);
458 ret
= vl6180_hold(data
, true);
462 ret
= vl6180_read_byte(client
, VL6180_OUT_OF_RESET
);
467 * Detect false reset condition here. This bit is always set when the
468 * system comes out of reset.
471 dev_info(&client
->dev
, "device is not fresh out of reset\n");
473 /* Enable ALS and Range ready interrupts */
474 ret
= vl6180_write_byte(client
, VL6180_INTR_CONFIG
,
475 VL6180_ALS_READY
| VL6180_RANGE_READY
);
479 /* ALS integration time: 100ms */
480 data
->als_it_ms
= 100;
481 ret
= vl6180_write_word(client
, VL6180_ALS_IT
, VL6180_ALS_IT_100
);
486 data
->als_gain_milli
= 1000;
487 ret
= vl6180_write_byte(client
, VL6180_ALS_GAIN
, VL6180_ALS_GAIN_1
);
491 ret
= vl6180_write_byte(client
, VL6180_OUT_OF_RESET
, 0x00);
495 return vl6180_hold(data
, false);
498 static int vl6180_probe(struct i2c_client
*client
,
499 const struct i2c_device_id
*id
)
501 struct vl6180_data
*data
;
502 struct iio_dev
*indio_dev
;
505 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*data
));
509 data
= iio_priv(indio_dev
);
510 i2c_set_clientdata(client
, indio_dev
);
511 data
->client
= client
;
512 mutex_init(&data
->lock
);
514 indio_dev
->dev
.parent
= &client
->dev
;
515 indio_dev
->info
= &vl6180_info
;
516 indio_dev
->channels
= vl6180_channels
;
517 indio_dev
->num_channels
= ARRAY_SIZE(vl6180_channels
);
518 indio_dev
->name
= VL6180_DRV_NAME
;
519 indio_dev
->modes
= INDIO_DIRECT_MODE
;
521 ret
= vl6180_init(data
);
525 return devm_iio_device_register(&client
->dev
, indio_dev
);
528 static const struct of_device_id vl6180_of_match
[] = {
529 { .compatible
= "st,vl6180", },
532 MODULE_DEVICE_TABLE(of
, vl6180_of_match
);
534 static const struct i2c_device_id vl6180_id
[] = {
538 MODULE_DEVICE_TABLE(i2c
, vl6180_id
);
540 static struct i2c_driver vl6180_driver
= {
542 .name
= VL6180_DRV_NAME
,
543 .of_match_table
= of_match_ptr(vl6180_of_match
),
545 .probe
= vl6180_probe
,
546 .id_table
= vl6180_id
,
549 module_i2c_driver(vl6180_driver
);
551 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
552 MODULE_AUTHOR("Manivannan Sadhasivam <manivannanece23@gmail.com>");
553 MODULE_DESCRIPTION("STMicro VL6180 ALS, range and proximity sensor driver");
554 MODULE_LICENSE("GPL");