.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * vl6180.c - Support for STMicroelectronics VL6180 ALS, range and proximity |
---|
3 | 4 | * sensor |
---|
.. | .. |
---|
5 | 6 | * Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net> |
---|
6 | 7 | * Copyright 2017 Manivannan Sadhasivam <manivannanece23@gmail.com> |
---|
7 | 8 | * |
---|
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. |
---|
11 | | - * |
---|
12 | 9 | * IIO driver for VL6180 (7-bit I2C slave address 0x29) |
---|
13 | 10 | * |
---|
14 | 11 | * Range: 0 to 100mm |
---|
15 | 12 | * ALS: < 1 Lux up to 100 kLux |
---|
16 | 13 | * IR: 850nm |
---|
17 | 14 | * |
---|
18 | | - * TODO: irq, threshold events, continuous mode, hardware buffer |
---|
| 15 | + * TODO: threshold events, continuous mode |
---|
19 | 16 | */ |
---|
20 | 17 | |
---|
21 | 18 | #include <linux/module.h> |
---|
| 19 | +#include <linux/mod_devicetable.h> |
---|
22 | 20 | #include <linux/i2c.h> |
---|
23 | 21 | #include <linux/mutex.h> |
---|
24 | 22 | #include <linux/err.h> |
---|
.. | .. |
---|
28 | 26 | |
---|
29 | 27 | #include <linux/iio/iio.h> |
---|
30 | 28 | #include <linux/iio/sysfs.h> |
---|
| 29 | +#include <linux/gpio.h> |
---|
| 30 | +#include <linux/of_gpio.h> |
---|
| 31 | +#include <linux/interrupt.h> |
---|
| 32 | +#include <linux/iio/triggered_buffer.h> |
---|
| 33 | +#include <linux/iio/kfifo_buf.h> |
---|
| 34 | +#include <linux/iio/buffer.h> |
---|
31 | 35 | |
---|
32 | 36 | #define VL6180_DRV_NAME "vl6180" |
---|
33 | 37 | |
---|
.. | .. |
---|
36 | 40 | #define VL6180_MODEL_ID_VAL 0xb4 |
---|
37 | 41 | |
---|
38 | 42 | /* Configuration registers */ |
---|
| 43 | +#define VL6180_SYS_MODE_GPIO1 0x011 |
---|
39 | 44 | #define VL6180_INTR_CONFIG 0x014 |
---|
40 | 45 | #define VL6180_INTR_CLEAR 0x015 |
---|
41 | 46 | #define VL6180_OUT_OF_RESET 0x016 |
---|
42 | 47 | #define VL6180_HOLD 0x017 |
---|
43 | 48 | #define VL6180_RANGE_START 0x018 |
---|
| 49 | +#define VL6180_RANGE_INTER_MES_PERIOD 0x01b |
---|
44 | 50 | #define VL6180_ALS_START 0x038 |
---|
| 51 | +#define VL6180_ALS_THRESH_HIGH 0x03a |
---|
| 52 | +#define VL6180_ALS_THRESH_LOW 0x03c |
---|
| 53 | +#define VL6180_ALS_INTER_MES_PERIOD 0x03e |
---|
45 | 54 | #define VL6180_ALS_GAIN 0x03f |
---|
46 | 55 | #define VL6180_ALS_IT 0x040 |
---|
47 | 56 | |
---|
.. | .. |
---|
55 | 64 | #define VL6180_RANGE_VALUE 0x062 |
---|
56 | 65 | #define VL6180_RANGE_RATE 0x066 |
---|
57 | 66 | |
---|
| 67 | +#define VL6180_RANGE_THRESH_HIGH 0x019 |
---|
| 68 | +#define VL6180_RANGE_THRESH_LOW 0x01a |
---|
| 69 | +#define VL6180_RANGE_MAX_CONVERGENCE_TIME 0x01c |
---|
| 70 | +#define VL6180_RANGE_CROSSTALK_COMPENSATION_RATE 0x01e |
---|
| 71 | +#define VL6180_RANGE_PART_TO_PART_RANGE_OFFSET 0x024 |
---|
| 72 | +#define VL6180_RANGE_RANGE_IGNORE_VALID_HEIGHT 0x025 |
---|
| 73 | +#define VL6180_RANGE_RANGE_IGNORE_THRESHOLD 0x026 |
---|
| 74 | +#define VL6180_RANGE_MAX_AMBIENT_LEVEL_MULT 0x02c |
---|
| 75 | +#define VL6180_RANGE_RANGE_CHECK_ENABLES 0x02d |
---|
| 76 | +#define VL6180_RANGE_VHV_RECALIBRATE 0x02e |
---|
| 77 | +#define VL6180_RANGE_VHV_REPEAT_RATE 0x031 |
---|
| 78 | +#define VL6180_READOUT_AVERAGING_SAMPLE_PERIOD 0x10a |
---|
| 79 | + |
---|
| 80 | +/* bits of the SYS_MODE_GPIO1 register */ |
---|
| 81 | +#define VL6180_SYS_GPIO1_POLARITY BIT(5) /* active high */ |
---|
| 82 | +#define VL6180_SYS_GPIO1_SELECT BIT(4) /* configure GPIO interrupt output */ |
---|
| 83 | + |
---|
58 | 84 | /* bits of the RANGE_START and ALS_START register */ |
---|
59 | 85 | #define VL6180_MODE_CONT BIT(1) /* continuous mode */ |
---|
60 | 86 | #define VL6180_STARTSTOP BIT(0) /* start measurement, auto-reset */ |
---|
61 | 87 | |
---|
62 | 88 | /* bits of the INTR_STATUS and INTR_CONFIG register */ |
---|
| 89 | +#define VL6180_ALS_LEVEL_LOW BIT(3) |
---|
| 90 | +#define VL6180_ALS_LEVEL_HIGH BIT(4) |
---|
| 91 | +#define VL6180_ALS_OUT_OF_WINDOW (BIT(3) | BIT(4)) |
---|
63 | 92 | #define VL6180_ALS_READY BIT(5) |
---|
| 93 | +#define VL6180_RANGE_LEVEL_LOW BIT(0) |
---|
| 94 | +#define VL6180_RANGE_LEVEL_HIGH BIT(1) |
---|
| 95 | +#define VL6180_RANGE_OUT_OF_WINDOW (BIT(0) | BIT(1)) |
---|
64 | 96 | #define VL6180_RANGE_READY BIT(2) |
---|
| 97 | +#define VL6180_INT_RANGE_GPIO_MASK GENMASK(2, 0) |
---|
| 98 | +#define VL6180_INT_ALS_GPIO_MASK GENMASK(5, 3) |
---|
| 99 | +#define VL6180_INT_ERR_GPIO_MASK GENMASK(7, 6) |
---|
65 | 100 | |
---|
66 | 101 | /* bits of the INTR_CLEAR register */ |
---|
67 | 102 | #define VL6180_CLEAR_ERROR BIT(2) |
---|
.. | .. |
---|
89 | 124 | struct mutex lock; |
---|
90 | 125 | unsigned int als_gain_milli; |
---|
91 | 126 | unsigned int als_it_ms; |
---|
| 127 | + struct gpio_desc *avdd; |
---|
| 128 | + struct gpio_desc *chip_enable; |
---|
| 129 | + |
---|
| 130 | + /* Ensure natural alignment of timestamp */ |
---|
| 131 | + struct { |
---|
| 132 | + u16 channels[3]; |
---|
| 133 | + u16 reserved; |
---|
| 134 | + s64 ts; |
---|
| 135 | + } scan; |
---|
92 | 136 | }; |
---|
93 | 137 | |
---|
94 | 138 | enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX }; |
---|
.. | .. |
---|
125 | 169 | .value_reg = VL6180_RANGE_RATE, |
---|
126 | 170 | .word = true, |
---|
127 | 171 | }, |
---|
| 172 | +}; |
---|
| 173 | + |
---|
| 174 | +/** |
---|
| 175 | + * struct vl6180_custom_data - Data for custom initialization |
---|
| 176 | + * @reg: Register |
---|
| 177 | + * @val: Value |
---|
| 178 | + */ |
---|
| 179 | +struct vl6180_custom_data { |
---|
| 180 | + u16 reg; |
---|
| 181 | + u8 val; |
---|
| 182 | +}; |
---|
| 183 | + |
---|
| 184 | +static const struct vl6180_custom_data vl6180_custom_data_table[] = { |
---|
| 185 | + { .reg = 0x207, .val = 0x01, }, |
---|
| 186 | + { .reg = 0x208, .val = 0x01, }, |
---|
| 187 | + { .reg = 0x096, .val = 0x00, }, |
---|
| 188 | + { .reg = 0x097, .val = 0xfd, }, |
---|
| 189 | + { .reg = 0x0e3, .val = 0x00, }, |
---|
| 190 | + { .reg = 0x0e4, .val = 0x04, }, |
---|
| 191 | + { .reg = 0x0e5, .val = 0x02, }, |
---|
| 192 | + { .reg = 0x0e6, .val = 0x01, }, |
---|
| 193 | + { .reg = 0x0e7, .val = 0x03, }, |
---|
| 194 | + { .reg = 0x0f5, .val = 0x02, }, |
---|
| 195 | + { .reg = 0x0d9, .val = 0x05, }, |
---|
| 196 | + { .reg = 0x0db, .val = 0xce, }, |
---|
| 197 | + { .reg = 0x0dc, .val = 0x03, }, |
---|
| 198 | + { .reg = 0x0dd, .val = 0xf8, }, |
---|
| 199 | + { .reg = 0x09f, .val = 0x00, }, |
---|
| 200 | + { .reg = 0x0a3, .val = 0x3c, }, |
---|
| 201 | + { .reg = 0x0b7, .val = 0x00, }, |
---|
| 202 | + { .reg = 0x0bb, .val = 0x3c, }, |
---|
| 203 | + { .reg = 0x0b2, .val = 0x09, }, |
---|
| 204 | + { .reg = 0x0ca, .val = 0x09, }, |
---|
| 205 | + { .reg = 0x198, .val = 0x01, }, |
---|
| 206 | + { .reg = 0x1b0, .val = 0x17, }, |
---|
| 207 | + { .reg = 0x1ad, .val = 0x00, }, |
---|
| 208 | + { .reg = 0x0ff, .val = 0x05, }, |
---|
| 209 | + { .reg = 0x100, .val = 0x05, }, |
---|
| 210 | + { .reg = 0x199, .val = 0x05, }, |
---|
| 211 | + { .reg = 0x1a6, .val = 0x1b, }, |
---|
| 212 | + { .reg = 0x1ac, .val = 0x3e, }, |
---|
| 213 | + { .reg = 0x1a7, .val = 0x1f, }, |
---|
| 214 | + { .reg = 0x030, .val = 0x00, }, |
---|
128 | 215 | }; |
---|
129 | 216 | |
---|
130 | 217 | static int vl6180_read(struct i2c_client *client, u16 cmd, void *databuf, |
---|
.. | .. |
---|
265 | 352 | BIT(IIO_CHAN_INFO_INT_TIME) | |
---|
266 | 353 | BIT(IIO_CHAN_INFO_SCALE) | |
---|
267 | 354 | BIT(IIO_CHAN_INFO_HARDWAREGAIN), |
---|
| 355 | + .scan_index = 0, |
---|
| 356 | + .scan_type = { |
---|
| 357 | + .sign = 'u', |
---|
| 358 | + .realbits = 16, |
---|
| 359 | + .storagebits = 16, |
---|
| 360 | + } |
---|
268 | 361 | }, { |
---|
269 | 362 | .type = IIO_DISTANCE, |
---|
270 | 363 | .address = VL6180_RANGE, |
---|
271 | 364 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
---|
272 | 365 | BIT(IIO_CHAN_INFO_SCALE), |
---|
| 366 | + .scan_index = 1, |
---|
| 367 | + .scan_type = { |
---|
| 368 | + .sign = 'u', |
---|
| 369 | + .realbits = 16, |
---|
| 370 | + .storagebits = 16, |
---|
| 371 | + } |
---|
273 | 372 | }, { |
---|
274 | 373 | .type = IIO_PROXIMITY, |
---|
275 | 374 | .address = VL6180_PROX, |
---|
276 | 375 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
---|
277 | | - } |
---|
| 376 | + .scan_index = 2, |
---|
| 377 | + .scan_type = { |
---|
| 378 | + .sign = 'u', |
---|
| 379 | + .realbits = 16, |
---|
| 380 | + .storagebits = 16, |
---|
| 381 | + } |
---|
| 382 | + }, |
---|
| 383 | + IIO_CHAN_SOFT_TIMESTAMP(3), |
---|
278 | 384 | }; |
---|
279 | 385 | |
---|
280 | 386 | /* |
---|
.. | .. |
---|
441 | 547 | .attrs = &vl6180_attribute_group, |
---|
442 | 548 | }; |
---|
443 | 549 | |
---|
| 550 | +static int vl6180_power_enable(struct vl6180_data *data) |
---|
| 551 | +{ |
---|
| 552 | + /* Enable power supply. */ |
---|
| 553 | + if (!IS_ERR_OR_NULL(data->avdd)) |
---|
| 554 | + gpiod_set_value_cansleep(data->avdd, 1); |
---|
| 555 | + |
---|
| 556 | + /* Power-up default is chip enable (CE). */ |
---|
| 557 | + if (!IS_ERR_OR_NULL(data->chip_enable)) { |
---|
| 558 | + gpiod_set_value_cansleep(data->chip_enable, 0); |
---|
| 559 | + usleep_range(500, 1000); |
---|
| 560 | + gpiod_set_value_cansleep(data->chip_enable, 1); |
---|
| 561 | + } |
---|
| 562 | + |
---|
| 563 | + return 0; |
---|
| 564 | +} |
---|
| 565 | + |
---|
| 566 | +static int vl6180_custom_init(struct vl6180_data *data) |
---|
| 567 | +{ |
---|
| 568 | + struct i2c_client *client = data->client; |
---|
| 569 | + int ret; |
---|
| 570 | + int i; |
---|
| 571 | + |
---|
| 572 | + /* REGISTER_TUNING_SR03_270514_CustomerView.txt */ |
---|
| 573 | + for (i = 0; i < ARRAY_SIZE(vl6180_custom_data_table); ++i) { |
---|
| 574 | + ret = vl6180_write_byte(client, |
---|
| 575 | + vl6180_custom_data_table[i].reg, |
---|
| 576 | + vl6180_custom_data_table[i].val); |
---|
| 577 | + |
---|
| 578 | + if (ret < 0) |
---|
| 579 | + break; |
---|
| 580 | + } |
---|
| 581 | + |
---|
| 582 | + return ret; |
---|
| 583 | +} |
---|
| 584 | + |
---|
| 585 | +static int vl6180_range_init(struct vl6180_data *data) |
---|
| 586 | +{ |
---|
| 587 | + struct i2c_client *client = data->client; |
---|
| 588 | + int ret; |
---|
| 589 | + u8 enables; |
---|
| 590 | + u8 offset; |
---|
| 591 | + u8 xtalk = 3; |
---|
| 592 | + |
---|
| 593 | + /* Enables polling for ‘New Sample ready’ when measurement completes */ |
---|
| 594 | + ret = vl6180_write_byte(client, VL6180_SYS_MODE_GPIO1, |
---|
| 595 | + (VL6180_SYS_GPIO1_POLARITY | |
---|
| 596 | + VL6180_SYS_GPIO1_SELECT)); |
---|
| 597 | + if (ret < 0) |
---|
| 598 | + goto out; |
---|
| 599 | + |
---|
| 600 | + /* Set the averaging sample period (compromise between lower noise and |
---|
| 601 | + * increased execution time), 0x30 equals to 4.3 ms. |
---|
| 602 | + */ |
---|
| 603 | + ret = vl6180_write_byte(client, VL6180_READOUT_AVERAGING_SAMPLE_PERIOD, |
---|
| 604 | + 0x30); |
---|
| 605 | + if (ret < 0) |
---|
| 606 | + goto out; |
---|
| 607 | + |
---|
| 608 | + /* Sets the # of range measurements after which auto calibration of |
---|
| 609 | + * system is performed |
---|
| 610 | + */ |
---|
| 611 | + ret = vl6180_write_byte(client, VL6180_RANGE_VHV_REPEAT_RATE, 0xff); |
---|
| 612 | + if (ret < 0) |
---|
| 613 | + goto out; |
---|
| 614 | + |
---|
| 615 | + /* Perform a single temperature calibration of the ranging sensor */ |
---|
| 616 | + ret = vl6180_write_byte(client, VL6180_RANGE_VHV_RECALIBRATE, 0x01); |
---|
| 617 | + if (ret < 0) |
---|
| 618 | + goto out; |
---|
| 619 | + |
---|
| 620 | + /* Set SNR limit to 0.06 */ |
---|
| 621 | + ret = vl6180_write_byte(client, VL6180_RANGE_MAX_AMBIENT_LEVEL_MULT, |
---|
| 622 | + 0xff); |
---|
| 623 | + if (ret < 0) |
---|
| 624 | + goto out; |
---|
| 625 | + |
---|
| 626 | + /* Set default ranging inter-measurement period to 100ms */ |
---|
| 627 | + ret = vl6180_write_byte(client, VL6180_RANGE_INTER_MES_PERIOD, 0x09); |
---|
| 628 | + if (ret < 0) |
---|
| 629 | + goto out; |
---|
| 630 | + |
---|
| 631 | + /* Copy registers */ |
---|
| 632 | + /* NOTE: 0x0da, 0x027, 0x0db, 0x028, 0x0dc, 0x029 and 0x0dd are |
---|
| 633 | + * unavailable on the datasheet. |
---|
| 634 | + */ |
---|
| 635 | + ret = vl6180_read_byte(client, VL6180_RANGE_RANGE_IGNORE_THRESHOLD); |
---|
| 636 | + if (ret < 0) |
---|
| 637 | + goto out; |
---|
| 638 | + |
---|
| 639 | + ret = vl6180_write_byte(client, 0x0da, ret); |
---|
| 640 | + if (ret < 0) |
---|
| 641 | + goto out; |
---|
| 642 | + |
---|
| 643 | + ret = vl6180_read_byte(client, 0x027); |
---|
| 644 | + if (ret < 0) |
---|
| 645 | + goto out; |
---|
| 646 | + |
---|
| 647 | + ret = vl6180_write_byte(client, 0x0db, ret); |
---|
| 648 | + if (ret < 0) |
---|
| 649 | + goto out; |
---|
| 650 | + |
---|
| 651 | + ret = vl6180_read_byte(client, 0x028); |
---|
| 652 | + if (ret < 0) |
---|
| 653 | + goto out; |
---|
| 654 | + |
---|
| 655 | + ret = vl6180_write_byte(client, 0x0dc, ret); |
---|
| 656 | + if (ret < 0) |
---|
| 657 | + goto out; |
---|
| 658 | + |
---|
| 659 | + ret = vl6180_read_byte(client, 0x029); |
---|
| 660 | + if (ret < 0) |
---|
| 661 | + goto out; |
---|
| 662 | + |
---|
| 663 | + ret = vl6180_write_byte(client, 0x0dd, ret); |
---|
| 664 | + if (ret < 0) |
---|
| 665 | + goto out; |
---|
| 666 | + |
---|
| 667 | + ret = vl6180_write_byte(client, VL6180_RANGE_MAX_CONVERGENCE_TIME, 0x32); |
---|
| 668 | + if (ret < 0) |
---|
| 669 | + goto out; |
---|
| 670 | + |
---|
| 671 | + ret = vl6180_read_byte(client, VL6180_RANGE_RANGE_CHECK_ENABLES); |
---|
| 672 | + if (ret < 0) |
---|
| 673 | + goto out; |
---|
| 674 | + |
---|
| 675 | + /* Disable early convergence */ |
---|
| 676 | + enables = ret & 0xfe; |
---|
| 677 | + ret = vl6180_write_byte(client, VL6180_RANGE_RANGE_CHECK_ENABLES, enables); |
---|
| 678 | + if (ret < 0) |
---|
| 679 | + goto out; |
---|
| 680 | + |
---|
| 681 | + ret = vl6180_write_byte(client, VL6180_RANGE_THRESH_HIGH, 0xc8); |
---|
| 682 | + if (ret < 0) |
---|
| 683 | + goto out; |
---|
| 684 | + |
---|
| 685 | + ret = vl6180_write_byte(client, VL6180_RANGE_THRESH_LOW, 0x00); |
---|
| 686 | + if (ret < 0) |
---|
| 687 | + goto out; |
---|
| 688 | + |
---|
| 689 | + ret = vl6180_write_byte(client, VL6180_ALS_IT, VL6180_ALS_IT_100); |
---|
| 690 | + if (ret < 0) |
---|
| 691 | + goto out; |
---|
| 692 | + |
---|
| 693 | + ret = vl6180_write_byte(client, VL6180_ALS_INTER_MES_PERIOD, 0x13); |
---|
| 694 | + if (ret < 0) |
---|
| 695 | + goto out; |
---|
| 696 | + |
---|
| 697 | + ret = vl6180_write_byte(client, VL6180_ALS_GAIN, VL6180_ALS_GAIN_1); |
---|
| 698 | + if (ret < 0) |
---|
| 699 | + goto out; |
---|
| 700 | + |
---|
| 701 | + ret = vl6180_write_byte(client, VL6180_ALS_THRESH_LOW, 0x00); |
---|
| 702 | + if (ret < 0) |
---|
| 703 | + goto out; |
---|
| 704 | + |
---|
| 705 | + ret = vl6180_write_byte(client, VL6180_ALS_THRESH_HIGH, 0xff); |
---|
| 706 | + if (ret < 0) |
---|
| 707 | + goto out; |
---|
| 708 | + |
---|
| 709 | + /* Cover glass ignore */ |
---|
| 710 | + ret = vl6180_write_byte(client, |
---|
| 711 | + VL6180_RANGE_RANGE_IGNORE_VALID_HEIGHT, 0xff); |
---|
| 712 | + if (ret < 0) |
---|
| 713 | + goto out; |
---|
| 714 | + |
---|
| 715 | + ret = vl6180_read_byte(client, VL6180_RANGE_PART_TO_PART_RANGE_OFFSET); |
---|
| 716 | + if (ret < 0) |
---|
| 717 | + goto out; |
---|
| 718 | + |
---|
| 719 | + /* Apply default calibration on part to part offset */ |
---|
| 720 | + offset = ret / 4; |
---|
| 721 | + ret = vl6180_write_byte(client, VL6180_RANGE_PART_TO_PART_RANGE_OFFSET, |
---|
| 722 | + offset); |
---|
| 723 | + if (ret < 0) |
---|
| 724 | + goto out; |
---|
| 725 | + |
---|
| 726 | + ret = vl6180_write_byte(client, |
---|
| 727 | + VL6180_RANGE_CROSSTALK_COMPENSATION_RATE, |
---|
| 728 | + 0x00); |
---|
| 729 | + if (ret < 0) |
---|
| 730 | + goto out; |
---|
| 731 | + |
---|
| 732 | + ret = vl6180_write_byte(client, 0x01f, xtalk); |
---|
| 733 | + |
---|
| 734 | +out: |
---|
| 735 | + return ret; |
---|
| 736 | +} |
---|
| 737 | + |
---|
444 | 738 | static int vl6180_init(struct vl6180_data *data) |
---|
445 | 739 | { |
---|
446 | 740 | struct i2c_client *client = data->client; |
---|
447 | 741 | int ret; |
---|
| 742 | + |
---|
| 743 | + ret = vl6180_power_enable(data); |
---|
| 744 | + if (ret) { |
---|
| 745 | + dev_err(&client->dev, "failed to configure power\n"); |
---|
| 746 | + return ret; |
---|
| 747 | + } |
---|
| 748 | + |
---|
| 749 | + /* |
---|
| 750 | + * After the MCU boot sequence the device enters software standby, |
---|
| 751 | + * host initialization can commence immediately after entering |
---|
| 752 | + * software standby. |
---|
| 753 | + */ |
---|
| 754 | + usleep_range(500, 1000); |
---|
448 | 755 | |
---|
449 | 756 | ret = vl6180_read_byte(client, VL6180_MODEL_ID); |
---|
450 | 757 | if (ret < 0) |
---|
.. | .. |
---|
470 | 777 | if (ret != 0x01) |
---|
471 | 778 | dev_info(&client->dev, "device is not fresh out of reset\n"); |
---|
472 | 779 | |
---|
473 | | - /* Enable ALS and Range ready interrupts */ |
---|
474 | | - ret = vl6180_write_byte(client, VL6180_INTR_CONFIG, |
---|
475 | | - VL6180_ALS_READY | VL6180_RANGE_READY); |
---|
476 | | - if (ret < 0) |
---|
477 | | - return ret; |
---|
478 | | - |
---|
479 | 780 | /* ALS integration time: 100ms */ |
---|
480 | 781 | data->als_it_ms = 100; |
---|
481 | 782 | ret = vl6180_write_word(client, VL6180_ALS_IT, VL6180_ALS_IT_100); |
---|
.. | .. |
---|
488 | 789 | if (ret < 0) |
---|
489 | 790 | return ret; |
---|
490 | 791 | |
---|
| 792 | + ret = vl6180_custom_init(data); |
---|
| 793 | + if (ret < 0) |
---|
| 794 | + return ret; |
---|
| 795 | + |
---|
| 796 | + ret = vl6180_range_init(data); |
---|
| 797 | + if (ret < 0) |
---|
| 798 | + return ret; |
---|
| 799 | + |
---|
| 800 | + ret = vl6180_write_byte(client, VL6180_RANGE_START, |
---|
| 801 | + (VL6180_STARTSTOP | VL6180_MODE_CONT)); |
---|
| 802 | + if (ret < 0) |
---|
| 803 | + return ret; |
---|
| 804 | + |
---|
491 | 805 | ret = vl6180_write_byte(client, VL6180_OUT_OF_RESET, 0x00); |
---|
492 | 806 | if (ret < 0) |
---|
493 | 807 | return ret; |
---|
.. | .. |
---|
495 | 809 | return vl6180_hold(data, false); |
---|
496 | 810 | } |
---|
497 | 811 | |
---|
| 812 | +static irqreturn_t vl6180_irq_thread(int irq, void *priv) |
---|
| 813 | +{ |
---|
| 814 | + struct vl6180_data *data = priv; |
---|
| 815 | + struct i2c_client *client = data->client; |
---|
| 816 | + struct iio_dev *indio_dev = i2c_get_clientdata(client); |
---|
| 817 | + int ret; |
---|
| 818 | + u8 val = 0; |
---|
| 819 | + |
---|
| 820 | + ret = vl6180_read_byte(client, VL6180_INTR_STATUS); |
---|
| 821 | + if (ret < 0) |
---|
| 822 | + goto out; |
---|
| 823 | + |
---|
| 824 | + if (ret & VL6180_INT_ALS_GPIO_MASK) |
---|
| 825 | + val |= VL6180_CLEAR_ALS; |
---|
| 826 | + |
---|
| 827 | + if (ret & VL6180_INT_RANGE_GPIO_MASK) |
---|
| 828 | + val |= VL6180_CLEAR_RANGE; |
---|
| 829 | + |
---|
| 830 | + if (ret & VL6180_INT_ERR_GPIO_MASK) |
---|
| 831 | + val |= VL6180_CLEAR_ERROR; |
---|
| 832 | + |
---|
| 833 | + vl6180_write_byte(client, VL6180_INTR_CLEAR, val); |
---|
| 834 | + |
---|
| 835 | + ret = vl6180_read_word(client, VL6180_ALS_VALUE); |
---|
| 836 | + if (ret < 0) |
---|
| 837 | + goto out; |
---|
| 838 | + data->scan.channels[VL6180_ALS] = ret; |
---|
| 839 | + |
---|
| 840 | + ret = vl6180_read_byte(client, VL6180_RANGE_VALUE); |
---|
| 841 | + if (ret < 0) |
---|
| 842 | + goto out; |
---|
| 843 | + data->scan.channels[VL6180_RANGE] = ret; |
---|
| 844 | + |
---|
| 845 | + ret = vl6180_read_word(client, VL6180_RANGE_RATE); |
---|
| 846 | + if (ret < 0) |
---|
| 847 | + goto out; |
---|
| 848 | + data->scan.channels[VL6180_PROX] = ret; |
---|
| 849 | + |
---|
| 850 | + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, |
---|
| 851 | + ktime_get_boottime_ns()); |
---|
| 852 | + |
---|
| 853 | +out: |
---|
| 854 | + return IRQ_HANDLED; |
---|
| 855 | +} |
---|
| 856 | + |
---|
| 857 | +static int vl6180_buffer_preenable(struct iio_dev *indio_dev) |
---|
| 858 | +{ |
---|
| 859 | + struct vl6180_data *data = iio_priv(indio_dev); |
---|
| 860 | + u8 val; |
---|
| 861 | + int ret; |
---|
| 862 | + |
---|
| 863 | + ret = vl6180_read_byte(data->client, VL6180_INTR_CONFIG); |
---|
| 864 | + if (ret < 0) |
---|
| 865 | + return ret; |
---|
| 866 | + |
---|
| 867 | + /* Enable ALS and Range ready interrupts */ |
---|
| 868 | + val = ret | VL6180_ALS_READY | VL6180_RANGE_READY; |
---|
| 869 | + ret = vl6180_write_byte(data->client, VL6180_INTR_CONFIG, val); |
---|
| 870 | + |
---|
| 871 | + return ret; |
---|
| 872 | +} |
---|
| 873 | + |
---|
| 874 | +static int vl6180_buffer_postdisable(struct iio_dev *indio_dev) |
---|
| 875 | +{ |
---|
| 876 | + struct vl6180_data *data = iio_priv(indio_dev); |
---|
| 877 | + u8 val; |
---|
| 878 | + int ret; |
---|
| 879 | + |
---|
| 880 | + ret = vl6180_read_byte(data->client, VL6180_INTR_CONFIG); |
---|
| 881 | + if (ret < 0) |
---|
| 882 | + return ret; |
---|
| 883 | + |
---|
| 884 | + /* Disable ALS and Range ready interrupts */ |
---|
| 885 | + val = ret & ~(VL6180_ALS_READY | VL6180_RANGE_READY); |
---|
| 886 | + ret = vl6180_write_byte(data->client, VL6180_INTR_CONFIG, val); |
---|
| 887 | + |
---|
| 888 | + return ret; |
---|
| 889 | +} |
---|
| 890 | + |
---|
| 891 | +static const struct iio_buffer_setup_ops vl6180_buffer_setup_ops = { |
---|
| 892 | + .preenable = vl6180_buffer_preenable, |
---|
| 893 | + .postdisable = vl6180_buffer_postdisable, |
---|
| 894 | +}; |
---|
| 895 | + |
---|
498 | 896 | static int vl6180_probe(struct i2c_client *client, |
---|
499 | 897 | const struct i2c_device_id *id) |
---|
500 | 898 | { |
---|
501 | 899 | struct vl6180_data *data; |
---|
502 | 900 | struct iio_dev *indio_dev; |
---|
| 901 | + struct iio_buffer *buffer; |
---|
| 902 | + u32 type; |
---|
503 | 903 | int ret; |
---|
504 | 904 | |
---|
505 | 905 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); |
---|
.. | .. |
---|
511 | 911 | data->client = client; |
---|
512 | 912 | mutex_init(&data->lock); |
---|
513 | 913 | |
---|
514 | | - indio_dev->dev.parent = &client->dev; |
---|
515 | 914 | indio_dev->info = &vl6180_info; |
---|
516 | 915 | indio_dev->channels = vl6180_channels; |
---|
517 | 916 | indio_dev->num_channels = ARRAY_SIZE(vl6180_channels); |
---|
518 | 917 | indio_dev->name = VL6180_DRV_NAME; |
---|
519 | 918 | indio_dev->modes = INDIO_DIRECT_MODE; |
---|
520 | 919 | |
---|
| 920 | + /* |
---|
| 921 | + * NOTE: If the power is controlled by gpio, the power |
---|
| 922 | + * configuration should match the power-up timing. |
---|
| 923 | + */ |
---|
| 924 | + data->avdd = devm_gpiod_get_optional(&client->dev, "avdd", |
---|
| 925 | + GPIOD_OUT_HIGH); |
---|
| 926 | + data->chip_enable = devm_gpiod_get_optional(&client->dev, "chip-enable", |
---|
| 927 | + GPIOD_OUT_HIGH); |
---|
| 928 | + |
---|
521 | 929 | ret = vl6180_init(data); |
---|
522 | 930 | if (ret < 0) |
---|
523 | 931 | return ret; |
---|
| 932 | + |
---|
| 933 | + if (client->irq) { |
---|
| 934 | + buffer = devm_iio_kfifo_allocate(&client->dev); |
---|
| 935 | + if (!buffer) |
---|
| 936 | + return -ENOMEM; |
---|
| 937 | + |
---|
| 938 | + iio_device_attach_buffer(indio_dev, buffer); |
---|
| 939 | + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; |
---|
| 940 | + indio_dev->setup_ops = &vl6180_buffer_setup_ops; |
---|
| 941 | + |
---|
| 942 | + type = irqd_get_trigger_type(irq_get_irq_data(client->irq)); |
---|
| 943 | + ret = devm_request_threaded_irq(&client->dev, client->irq, |
---|
| 944 | + NULL, vl6180_irq_thread, |
---|
| 945 | + type | IRQF_ONESHOT, "vl6180", |
---|
| 946 | + data); |
---|
| 947 | + if (ret) { |
---|
| 948 | + dev_err(&client->dev, |
---|
| 949 | + "failed to request vl6180 IRQ\n"); |
---|
| 950 | + return ret; |
---|
| 951 | + } |
---|
| 952 | + } |
---|
524 | 953 | |
---|
525 | 954 | return devm_iio_device_register(&client->dev, indio_dev); |
---|
526 | 955 | } |
---|
.. | .. |
---|
540 | 969 | static struct i2c_driver vl6180_driver = { |
---|
541 | 970 | .driver = { |
---|
542 | 971 | .name = VL6180_DRV_NAME, |
---|
543 | | - .of_match_table = of_match_ptr(vl6180_of_match), |
---|
| 972 | + .of_match_table = vl6180_of_match, |
---|
544 | 973 | }, |
---|
545 | 974 | .probe = vl6180_probe, |
---|
546 | 975 | .id_table = vl6180_id, |
---|