1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * vl6180.c - Support for STMicroelectronics VL6180 ALS, range and proximity
4*4882a593Smuzhiyun * sensor
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
7*4882a593Smuzhiyun * Copyright 2017 Manivannan Sadhasivam <manivannanece23@gmail.com>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * IIO driver for VL6180 (7-bit I2C slave address 0x29)
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Range: 0 to 100mm
12*4882a593Smuzhiyun * ALS: < 1 Lux up to 100 kLux
13*4882a593Smuzhiyun * IR: 850nm
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * TODO: threshold events, continuous mode
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <linux/module.h>
19*4882a593Smuzhiyun #include <linux/mod_devicetable.h>
20*4882a593Smuzhiyun #include <linux/i2c.h>
21*4882a593Smuzhiyun #include <linux/mutex.h>
22*4882a593Smuzhiyun #include <linux/err.h>
23*4882a593Smuzhiyun #include <linux/of.h>
24*4882a593Smuzhiyun #include <linux/delay.h>
25*4882a593Smuzhiyun #include <linux/util_macros.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include <linux/iio/iio.h>
28*4882a593Smuzhiyun #include <linux/iio/sysfs.h>
29*4882a593Smuzhiyun #include <linux/gpio.h>
30*4882a593Smuzhiyun #include <linux/of_gpio.h>
31*4882a593Smuzhiyun #include <linux/interrupt.h>
32*4882a593Smuzhiyun #include <linux/iio/triggered_buffer.h>
33*4882a593Smuzhiyun #include <linux/iio/kfifo_buf.h>
34*4882a593Smuzhiyun #include <linux/iio/buffer.h>
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define VL6180_DRV_NAME "vl6180"
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /* Device identification register and value */
39*4882a593Smuzhiyun #define VL6180_MODEL_ID 0x000
40*4882a593Smuzhiyun #define VL6180_MODEL_ID_VAL 0xb4
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /* Configuration registers */
43*4882a593Smuzhiyun #define VL6180_SYS_MODE_GPIO1 0x011
44*4882a593Smuzhiyun #define VL6180_INTR_CONFIG 0x014
45*4882a593Smuzhiyun #define VL6180_INTR_CLEAR 0x015
46*4882a593Smuzhiyun #define VL6180_OUT_OF_RESET 0x016
47*4882a593Smuzhiyun #define VL6180_HOLD 0x017
48*4882a593Smuzhiyun #define VL6180_RANGE_START 0x018
49*4882a593Smuzhiyun #define VL6180_RANGE_INTER_MES_PERIOD 0x01b
50*4882a593Smuzhiyun #define VL6180_ALS_START 0x038
51*4882a593Smuzhiyun #define VL6180_ALS_THRESH_HIGH 0x03a
52*4882a593Smuzhiyun #define VL6180_ALS_THRESH_LOW 0x03c
53*4882a593Smuzhiyun #define VL6180_ALS_INTER_MES_PERIOD 0x03e
54*4882a593Smuzhiyun #define VL6180_ALS_GAIN 0x03f
55*4882a593Smuzhiyun #define VL6180_ALS_IT 0x040
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /* Status registers */
58*4882a593Smuzhiyun #define VL6180_RANGE_STATUS 0x04d
59*4882a593Smuzhiyun #define VL6180_ALS_STATUS 0x04e
60*4882a593Smuzhiyun #define VL6180_INTR_STATUS 0x04f
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* Result value registers */
63*4882a593Smuzhiyun #define VL6180_ALS_VALUE 0x050
64*4882a593Smuzhiyun #define VL6180_RANGE_VALUE 0x062
65*4882a593Smuzhiyun #define VL6180_RANGE_RATE 0x066
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun #define VL6180_RANGE_THRESH_HIGH 0x019
68*4882a593Smuzhiyun #define VL6180_RANGE_THRESH_LOW 0x01a
69*4882a593Smuzhiyun #define VL6180_RANGE_MAX_CONVERGENCE_TIME 0x01c
70*4882a593Smuzhiyun #define VL6180_RANGE_CROSSTALK_COMPENSATION_RATE 0x01e
71*4882a593Smuzhiyun #define VL6180_RANGE_PART_TO_PART_RANGE_OFFSET 0x024
72*4882a593Smuzhiyun #define VL6180_RANGE_RANGE_IGNORE_VALID_HEIGHT 0x025
73*4882a593Smuzhiyun #define VL6180_RANGE_RANGE_IGNORE_THRESHOLD 0x026
74*4882a593Smuzhiyun #define VL6180_RANGE_MAX_AMBIENT_LEVEL_MULT 0x02c
75*4882a593Smuzhiyun #define VL6180_RANGE_RANGE_CHECK_ENABLES 0x02d
76*4882a593Smuzhiyun #define VL6180_RANGE_VHV_RECALIBRATE 0x02e
77*4882a593Smuzhiyun #define VL6180_RANGE_VHV_REPEAT_RATE 0x031
78*4882a593Smuzhiyun #define VL6180_READOUT_AVERAGING_SAMPLE_PERIOD 0x10a
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /* bits of the SYS_MODE_GPIO1 register */
81*4882a593Smuzhiyun #define VL6180_SYS_GPIO1_POLARITY BIT(5) /* active high */
82*4882a593Smuzhiyun #define VL6180_SYS_GPIO1_SELECT BIT(4) /* configure GPIO interrupt output */
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun /* bits of the RANGE_START and ALS_START register */
85*4882a593Smuzhiyun #define VL6180_MODE_CONT BIT(1) /* continuous mode */
86*4882a593Smuzhiyun #define VL6180_STARTSTOP BIT(0) /* start measurement, auto-reset */
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /* bits of the INTR_STATUS and INTR_CONFIG register */
89*4882a593Smuzhiyun #define VL6180_ALS_LEVEL_LOW BIT(3)
90*4882a593Smuzhiyun #define VL6180_ALS_LEVEL_HIGH BIT(4)
91*4882a593Smuzhiyun #define VL6180_ALS_OUT_OF_WINDOW (BIT(3) | BIT(4))
92*4882a593Smuzhiyun #define VL6180_ALS_READY BIT(5)
93*4882a593Smuzhiyun #define VL6180_RANGE_LEVEL_LOW BIT(0)
94*4882a593Smuzhiyun #define VL6180_RANGE_LEVEL_HIGH BIT(1)
95*4882a593Smuzhiyun #define VL6180_RANGE_OUT_OF_WINDOW (BIT(0) | BIT(1))
96*4882a593Smuzhiyun #define VL6180_RANGE_READY BIT(2)
97*4882a593Smuzhiyun #define VL6180_INT_RANGE_GPIO_MASK GENMASK(2, 0)
98*4882a593Smuzhiyun #define VL6180_INT_ALS_GPIO_MASK GENMASK(5, 3)
99*4882a593Smuzhiyun #define VL6180_INT_ERR_GPIO_MASK GENMASK(7, 6)
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* bits of the INTR_CLEAR register */
102*4882a593Smuzhiyun #define VL6180_CLEAR_ERROR BIT(2)
103*4882a593Smuzhiyun #define VL6180_CLEAR_ALS BIT(1)
104*4882a593Smuzhiyun #define VL6180_CLEAR_RANGE BIT(0)
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /* bits of the HOLD register */
107*4882a593Smuzhiyun #define VL6180_HOLD_ON BIT(0)
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /* default value for the ALS_IT register */
110*4882a593Smuzhiyun #define VL6180_ALS_IT_100 0x63 /* 100 ms */
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* values for the ALS_GAIN register */
113*4882a593Smuzhiyun #define VL6180_ALS_GAIN_1 0x46
114*4882a593Smuzhiyun #define VL6180_ALS_GAIN_1_25 0x45
115*4882a593Smuzhiyun #define VL6180_ALS_GAIN_1_67 0x44
116*4882a593Smuzhiyun #define VL6180_ALS_GAIN_2_5 0x43
117*4882a593Smuzhiyun #define VL6180_ALS_GAIN_5 0x42
118*4882a593Smuzhiyun #define VL6180_ALS_GAIN_10 0x41
119*4882a593Smuzhiyun #define VL6180_ALS_GAIN_20 0x40
120*4882a593Smuzhiyun #define VL6180_ALS_GAIN_40 0x47
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun struct vl6180_data {
123*4882a593Smuzhiyun struct i2c_client *client;
124*4882a593Smuzhiyun struct mutex lock;
125*4882a593Smuzhiyun unsigned int als_gain_milli;
126*4882a593Smuzhiyun unsigned int als_it_ms;
127*4882a593Smuzhiyun struct gpio_desc *avdd;
128*4882a593Smuzhiyun struct gpio_desc *chip_enable;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* Ensure natural alignment of timestamp */
131*4882a593Smuzhiyun struct {
132*4882a593Smuzhiyun u16 channels[3];
133*4882a593Smuzhiyun u16 reserved;
134*4882a593Smuzhiyun s64 ts;
135*4882a593Smuzhiyun } scan;
136*4882a593Smuzhiyun };
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX };
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /**
141*4882a593Smuzhiyun * struct vl6180_chan_regs - Registers for accessing channels
142*4882a593Smuzhiyun * @drdy_mask: Data ready bit in status register
143*4882a593Smuzhiyun * @start_reg: Conversion start register
144*4882a593Smuzhiyun * @value_reg: Result value register
145*4882a593Smuzhiyun * @word: Register word length
146*4882a593Smuzhiyun */
147*4882a593Smuzhiyun struct vl6180_chan_regs {
148*4882a593Smuzhiyun u8 drdy_mask;
149*4882a593Smuzhiyun u16 start_reg, value_reg;
150*4882a593Smuzhiyun bool word;
151*4882a593Smuzhiyun };
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun static const struct vl6180_chan_regs vl6180_chan_regs_table[] = {
154*4882a593Smuzhiyun [VL6180_ALS] = {
155*4882a593Smuzhiyun .drdy_mask = VL6180_ALS_READY,
156*4882a593Smuzhiyun .start_reg = VL6180_ALS_START,
157*4882a593Smuzhiyun .value_reg = VL6180_ALS_VALUE,
158*4882a593Smuzhiyun .word = true,
159*4882a593Smuzhiyun },
160*4882a593Smuzhiyun [VL6180_RANGE] = {
161*4882a593Smuzhiyun .drdy_mask = VL6180_RANGE_READY,
162*4882a593Smuzhiyun .start_reg = VL6180_RANGE_START,
163*4882a593Smuzhiyun .value_reg = VL6180_RANGE_VALUE,
164*4882a593Smuzhiyun .word = false,
165*4882a593Smuzhiyun },
166*4882a593Smuzhiyun [VL6180_PROX] = {
167*4882a593Smuzhiyun .drdy_mask = VL6180_RANGE_READY,
168*4882a593Smuzhiyun .start_reg = VL6180_RANGE_START,
169*4882a593Smuzhiyun .value_reg = VL6180_RANGE_RATE,
170*4882a593Smuzhiyun .word = true,
171*4882a593Smuzhiyun },
172*4882a593Smuzhiyun };
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /**
175*4882a593Smuzhiyun * struct vl6180_custom_data - Data for custom initialization
176*4882a593Smuzhiyun * @reg: Register
177*4882a593Smuzhiyun * @val: Value
178*4882a593Smuzhiyun */
179*4882a593Smuzhiyun struct vl6180_custom_data {
180*4882a593Smuzhiyun u16 reg;
181*4882a593Smuzhiyun u8 val;
182*4882a593Smuzhiyun };
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun static const struct vl6180_custom_data vl6180_custom_data_table[] = {
185*4882a593Smuzhiyun { .reg = 0x207, .val = 0x01, },
186*4882a593Smuzhiyun { .reg = 0x208, .val = 0x01, },
187*4882a593Smuzhiyun { .reg = 0x096, .val = 0x00, },
188*4882a593Smuzhiyun { .reg = 0x097, .val = 0xfd, },
189*4882a593Smuzhiyun { .reg = 0x0e3, .val = 0x00, },
190*4882a593Smuzhiyun { .reg = 0x0e4, .val = 0x04, },
191*4882a593Smuzhiyun { .reg = 0x0e5, .val = 0x02, },
192*4882a593Smuzhiyun { .reg = 0x0e6, .val = 0x01, },
193*4882a593Smuzhiyun { .reg = 0x0e7, .val = 0x03, },
194*4882a593Smuzhiyun { .reg = 0x0f5, .val = 0x02, },
195*4882a593Smuzhiyun { .reg = 0x0d9, .val = 0x05, },
196*4882a593Smuzhiyun { .reg = 0x0db, .val = 0xce, },
197*4882a593Smuzhiyun { .reg = 0x0dc, .val = 0x03, },
198*4882a593Smuzhiyun { .reg = 0x0dd, .val = 0xf8, },
199*4882a593Smuzhiyun { .reg = 0x09f, .val = 0x00, },
200*4882a593Smuzhiyun { .reg = 0x0a3, .val = 0x3c, },
201*4882a593Smuzhiyun { .reg = 0x0b7, .val = 0x00, },
202*4882a593Smuzhiyun { .reg = 0x0bb, .val = 0x3c, },
203*4882a593Smuzhiyun { .reg = 0x0b2, .val = 0x09, },
204*4882a593Smuzhiyun { .reg = 0x0ca, .val = 0x09, },
205*4882a593Smuzhiyun { .reg = 0x198, .val = 0x01, },
206*4882a593Smuzhiyun { .reg = 0x1b0, .val = 0x17, },
207*4882a593Smuzhiyun { .reg = 0x1ad, .val = 0x00, },
208*4882a593Smuzhiyun { .reg = 0x0ff, .val = 0x05, },
209*4882a593Smuzhiyun { .reg = 0x100, .val = 0x05, },
210*4882a593Smuzhiyun { .reg = 0x199, .val = 0x05, },
211*4882a593Smuzhiyun { .reg = 0x1a6, .val = 0x1b, },
212*4882a593Smuzhiyun { .reg = 0x1ac, .val = 0x3e, },
213*4882a593Smuzhiyun { .reg = 0x1a7, .val = 0x1f, },
214*4882a593Smuzhiyun { .reg = 0x030, .val = 0x00, },
215*4882a593Smuzhiyun };
216*4882a593Smuzhiyun
vl6180_read(struct i2c_client * client,u16 cmd,void * databuf,u8 len)217*4882a593Smuzhiyun static int vl6180_read(struct i2c_client *client, u16 cmd, void *databuf,
218*4882a593Smuzhiyun u8 len)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun __be16 cmdbuf = cpu_to_be16(cmd);
221*4882a593Smuzhiyun struct i2c_msg msgs[2] = {
222*4882a593Smuzhiyun { .addr = client->addr, .len = sizeof(cmdbuf), .buf = (u8 *) &cmdbuf },
223*4882a593Smuzhiyun { .addr = client->addr, .len = len, .buf = databuf,
224*4882a593Smuzhiyun .flags = I2C_M_RD } };
225*4882a593Smuzhiyun int ret;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
228*4882a593Smuzhiyun if (ret < 0)
229*4882a593Smuzhiyun dev_err(&client->dev, "failed reading register 0x%04x\n", cmd);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun return ret;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
vl6180_read_byte(struct i2c_client * client,u16 cmd)234*4882a593Smuzhiyun static int vl6180_read_byte(struct i2c_client *client, u16 cmd)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun u8 data;
237*4882a593Smuzhiyun int ret;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun ret = vl6180_read(client, cmd, &data, sizeof(data));
240*4882a593Smuzhiyun if (ret < 0)
241*4882a593Smuzhiyun return ret;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun return data;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
vl6180_read_word(struct i2c_client * client,u16 cmd)246*4882a593Smuzhiyun static int vl6180_read_word(struct i2c_client *client, u16 cmd)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun __be16 data;
249*4882a593Smuzhiyun int ret;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun ret = vl6180_read(client, cmd, &data, sizeof(data));
252*4882a593Smuzhiyun if (ret < 0)
253*4882a593Smuzhiyun return ret;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun return be16_to_cpu(data);
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
vl6180_write_byte(struct i2c_client * client,u16 cmd,u8 val)258*4882a593Smuzhiyun static int vl6180_write_byte(struct i2c_client *client, u16 cmd, u8 val)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun u8 buf[3];
261*4882a593Smuzhiyun struct i2c_msg msgs[1] = {
262*4882a593Smuzhiyun { .addr = client->addr, .len = sizeof(buf), .buf = (u8 *) &buf } };
263*4882a593Smuzhiyun int ret;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun buf[0] = cmd >> 8;
266*4882a593Smuzhiyun buf[1] = cmd & 0xff;
267*4882a593Smuzhiyun buf[2] = val;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
270*4882a593Smuzhiyun if (ret < 0) {
271*4882a593Smuzhiyun dev_err(&client->dev, "failed writing register 0x%04x\n", cmd);
272*4882a593Smuzhiyun return ret;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun return 0;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
vl6180_write_word(struct i2c_client * client,u16 cmd,u16 val)278*4882a593Smuzhiyun static int vl6180_write_word(struct i2c_client *client, u16 cmd, u16 val)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun __be16 buf[2];
281*4882a593Smuzhiyun struct i2c_msg msgs[1] = {
282*4882a593Smuzhiyun { .addr = client->addr, .len = sizeof(buf), .buf = (u8 *) &buf } };
283*4882a593Smuzhiyun int ret;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun buf[0] = cpu_to_be16(cmd);
286*4882a593Smuzhiyun buf[1] = cpu_to_be16(val);
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
289*4882a593Smuzhiyun if (ret < 0) {
290*4882a593Smuzhiyun dev_err(&client->dev, "failed writing register 0x%04x\n", cmd);
291*4882a593Smuzhiyun return ret;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun return 0;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
vl6180_measure(struct vl6180_data * data,int addr)297*4882a593Smuzhiyun static int vl6180_measure(struct vl6180_data *data, int addr)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun struct i2c_client *client = data->client;
300*4882a593Smuzhiyun int tries = 20, ret;
301*4882a593Smuzhiyun u16 value;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun mutex_lock(&data->lock);
304*4882a593Smuzhiyun /* Start single shot measurement */
305*4882a593Smuzhiyun ret = vl6180_write_byte(client,
306*4882a593Smuzhiyun vl6180_chan_regs_table[addr].start_reg, VL6180_STARTSTOP);
307*4882a593Smuzhiyun if (ret < 0)
308*4882a593Smuzhiyun goto fail;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun while (tries--) {
311*4882a593Smuzhiyun ret = vl6180_read_byte(client, VL6180_INTR_STATUS);
312*4882a593Smuzhiyun if (ret < 0)
313*4882a593Smuzhiyun goto fail;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun if (ret & vl6180_chan_regs_table[addr].drdy_mask)
316*4882a593Smuzhiyun break;
317*4882a593Smuzhiyun msleep(20);
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (tries < 0) {
321*4882a593Smuzhiyun ret = -EIO;
322*4882a593Smuzhiyun goto fail;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun /* Read result value from appropriate registers */
326*4882a593Smuzhiyun ret = vl6180_chan_regs_table[addr].word ?
327*4882a593Smuzhiyun vl6180_read_word(client, vl6180_chan_regs_table[addr].value_reg) :
328*4882a593Smuzhiyun vl6180_read_byte(client, vl6180_chan_regs_table[addr].value_reg);
329*4882a593Smuzhiyun if (ret < 0)
330*4882a593Smuzhiyun goto fail;
331*4882a593Smuzhiyun value = ret;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun /* Clear the interrupt flag after data read */
334*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_INTR_CLEAR,
335*4882a593Smuzhiyun VL6180_CLEAR_ERROR | VL6180_CLEAR_ALS | VL6180_CLEAR_RANGE);
336*4882a593Smuzhiyun if (ret < 0)
337*4882a593Smuzhiyun goto fail;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun ret = value;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun fail:
342*4882a593Smuzhiyun mutex_unlock(&data->lock);
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun return ret;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun static const struct iio_chan_spec vl6180_channels[] = {
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun .type = IIO_LIGHT,
350*4882a593Smuzhiyun .address = VL6180_ALS,
351*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
352*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_INT_TIME) |
353*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE) |
354*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_HARDWAREGAIN),
355*4882a593Smuzhiyun .scan_index = 0,
356*4882a593Smuzhiyun .scan_type = {
357*4882a593Smuzhiyun .sign = 'u',
358*4882a593Smuzhiyun .realbits = 16,
359*4882a593Smuzhiyun .storagebits = 16,
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun }, {
362*4882a593Smuzhiyun .type = IIO_DISTANCE,
363*4882a593Smuzhiyun .address = VL6180_RANGE,
364*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
365*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE),
366*4882a593Smuzhiyun .scan_index = 1,
367*4882a593Smuzhiyun .scan_type = {
368*4882a593Smuzhiyun .sign = 'u',
369*4882a593Smuzhiyun .realbits = 16,
370*4882a593Smuzhiyun .storagebits = 16,
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun }, {
373*4882a593Smuzhiyun .type = IIO_PROXIMITY,
374*4882a593Smuzhiyun .address = VL6180_PROX,
375*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
376*4882a593Smuzhiyun .scan_index = 2,
377*4882a593Smuzhiyun .scan_type = {
378*4882a593Smuzhiyun .sign = 'u',
379*4882a593Smuzhiyun .realbits = 16,
380*4882a593Smuzhiyun .storagebits = 16,
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun },
383*4882a593Smuzhiyun IIO_CHAN_SOFT_TIMESTAMP(3),
384*4882a593Smuzhiyun };
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun /*
387*4882a593Smuzhiyun * Available Ambient Light Sensor gain settings, 1/1000th, and
388*4882a593Smuzhiyun * corresponding setting for the VL6180_ALS_GAIN register
389*4882a593Smuzhiyun */
390*4882a593Smuzhiyun static const int vl6180_als_gain_tab[8] = {
391*4882a593Smuzhiyun 1000, 1250, 1670, 2500, 5000, 10000, 20000, 40000
392*4882a593Smuzhiyun };
393*4882a593Smuzhiyun static const u8 vl6180_als_gain_tab_bits[8] = {
394*4882a593Smuzhiyun VL6180_ALS_GAIN_1, VL6180_ALS_GAIN_1_25,
395*4882a593Smuzhiyun VL6180_ALS_GAIN_1_67, VL6180_ALS_GAIN_2_5,
396*4882a593Smuzhiyun VL6180_ALS_GAIN_5, VL6180_ALS_GAIN_10,
397*4882a593Smuzhiyun VL6180_ALS_GAIN_20, VL6180_ALS_GAIN_40
398*4882a593Smuzhiyun };
399*4882a593Smuzhiyun
vl6180_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)400*4882a593Smuzhiyun static int vl6180_read_raw(struct iio_dev *indio_dev,
401*4882a593Smuzhiyun struct iio_chan_spec const *chan,
402*4882a593Smuzhiyun int *val, int *val2, long mask)
403*4882a593Smuzhiyun {
404*4882a593Smuzhiyun struct vl6180_data *data = iio_priv(indio_dev);
405*4882a593Smuzhiyun int ret;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun switch (mask) {
408*4882a593Smuzhiyun case IIO_CHAN_INFO_RAW:
409*4882a593Smuzhiyun ret = vl6180_measure(data, chan->address);
410*4882a593Smuzhiyun if (ret < 0)
411*4882a593Smuzhiyun return ret;
412*4882a593Smuzhiyun *val = ret;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun return IIO_VAL_INT;
415*4882a593Smuzhiyun case IIO_CHAN_INFO_INT_TIME:
416*4882a593Smuzhiyun *val = data->als_it_ms;
417*4882a593Smuzhiyun *val2 = 1000;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun return IIO_VAL_FRACTIONAL;
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun case IIO_CHAN_INFO_SCALE:
422*4882a593Smuzhiyun switch (chan->type) {
423*4882a593Smuzhiyun case IIO_LIGHT:
424*4882a593Smuzhiyun /* one ALS count is 0.32 Lux @ gain 1, IT 100 ms */
425*4882a593Smuzhiyun *val = 32000; /* 0.32 * 1000 * 100 */
426*4882a593Smuzhiyun *val2 = data->als_gain_milli * data->als_it_ms;
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun return IIO_VAL_FRACTIONAL;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun case IIO_DISTANCE:
431*4882a593Smuzhiyun *val = 0; /* sensor reports mm, scale to meter */
432*4882a593Smuzhiyun *val2 = 1000;
433*4882a593Smuzhiyun break;
434*4882a593Smuzhiyun default:
435*4882a593Smuzhiyun return -EINVAL;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
439*4882a593Smuzhiyun case IIO_CHAN_INFO_HARDWAREGAIN:
440*4882a593Smuzhiyun *val = data->als_gain_milli;
441*4882a593Smuzhiyun *val2 = 1000;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun return IIO_VAL_FRACTIONAL;
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun default:
446*4882a593Smuzhiyun return -EINVAL;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun static IIO_CONST_ATTR(als_gain_available, "1 1.25 1.67 2.5 5 10 20 40");
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun static struct attribute *vl6180_attributes[] = {
453*4882a593Smuzhiyun &iio_const_attr_als_gain_available.dev_attr.attr,
454*4882a593Smuzhiyun NULL
455*4882a593Smuzhiyun };
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun static const struct attribute_group vl6180_attribute_group = {
458*4882a593Smuzhiyun .attrs = vl6180_attributes,
459*4882a593Smuzhiyun };
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun /* HOLD is needed before updating any config registers */
vl6180_hold(struct vl6180_data * data,bool hold)462*4882a593Smuzhiyun static int vl6180_hold(struct vl6180_data *data, bool hold)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun return vl6180_write_byte(data->client, VL6180_HOLD,
465*4882a593Smuzhiyun hold ? VL6180_HOLD_ON : 0);
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun
vl6180_set_als_gain(struct vl6180_data * data,int val,int val2)468*4882a593Smuzhiyun static int vl6180_set_als_gain(struct vl6180_data *data, int val, int val2)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun int i, ret, gain;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun if (val < 1 || val > 40)
473*4882a593Smuzhiyun return -EINVAL;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun gain = (val * 1000000 + val2) / 1000;
476*4882a593Smuzhiyun if (gain < 1 || gain > 40000)
477*4882a593Smuzhiyun return -EINVAL;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun i = find_closest(gain, vl6180_als_gain_tab,
480*4882a593Smuzhiyun ARRAY_SIZE(vl6180_als_gain_tab));
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun mutex_lock(&data->lock);
483*4882a593Smuzhiyun ret = vl6180_hold(data, true);
484*4882a593Smuzhiyun if (ret < 0)
485*4882a593Smuzhiyun goto fail;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun ret = vl6180_write_byte(data->client, VL6180_ALS_GAIN,
488*4882a593Smuzhiyun vl6180_als_gain_tab_bits[i]);
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun if (ret >= 0)
491*4882a593Smuzhiyun data->als_gain_milli = vl6180_als_gain_tab[i];
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun fail:
494*4882a593Smuzhiyun vl6180_hold(data, false);
495*4882a593Smuzhiyun mutex_unlock(&data->lock);
496*4882a593Smuzhiyun return ret;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
vl6180_set_it(struct vl6180_data * data,int val,int val2)499*4882a593Smuzhiyun static int vl6180_set_it(struct vl6180_data *data, int val, int val2)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun int ret, it_ms;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun it_ms = (val2 + 500) / 1000; /* round to ms */
504*4882a593Smuzhiyun if (val != 0 || it_ms < 1 || it_ms > 512)
505*4882a593Smuzhiyun return -EINVAL;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun mutex_lock(&data->lock);
508*4882a593Smuzhiyun ret = vl6180_hold(data, true);
509*4882a593Smuzhiyun if (ret < 0)
510*4882a593Smuzhiyun goto fail;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun ret = vl6180_write_word(data->client, VL6180_ALS_IT, it_ms - 1);
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun if (ret >= 0)
515*4882a593Smuzhiyun data->als_it_ms = it_ms;
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun fail:
518*4882a593Smuzhiyun vl6180_hold(data, false);
519*4882a593Smuzhiyun mutex_unlock(&data->lock);
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun return ret;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
vl6180_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)524*4882a593Smuzhiyun static int vl6180_write_raw(struct iio_dev *indio_dev,
525*4882a593Smuzhiyun struct iio_chan_spec const *chan,
526*4882a593Smuzhiyun int val, int val2, long mask)
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun struct vl6180_data *data = iio_priv(indio_dev);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun switch (mask) {
531*4882a593Smuzhiyun case IIO_CHAN_INFO_INT_TIME:
532*4882a593Smuzhiyun return vl6180_set_it(data, val, val2);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun case IIO_CHAN_INFO_HARDWAREGAIN:
535*4882a593Smuzhiyun if (chan->type != IIO_LIGHT)
536*4882a593Smuzhiyun return -EINVAL;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun return vl6180_set_als_gain(data, val, val2);
539*4882a593Smuzhiyun default:
540*4882a593Smuzhiyun return -EINVAL;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun static const struct iio_info vl6180_info = {
545*4882a593Smuzhiyun .read_raw = vl6180_read_raw,
546*4882a593Smuzhiyun .write_raw = vl6180_write_raw,
547*4882a593Smuzhiyun .attrs = &vl6180_attribute_group,
548*4882a593Smuzhiyun };
549*4882a593Smuzhiyun
vl6180_power_enable(struct vl6180_data * data)550*4882a593Smuzhiyun static int vl6180_power_enable(struct vl6180_data *data)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun /* Enable power supply. */
553*4882a593Smuzhiyun if (!IS_ERR_OR_NULL(data->avdd))
554*4882a593Smuzhiyun gpiod_set_value_cansleep(data->avdd, 1);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun /* Power-up default is chip enable (CE). */
557*4882a593Smuzhiyun if (!IS_ERR_OR_NULL(data->chip_enable)) {
558*4882a593Smuzhiyun gpiod_set_value_cansleep(data->chip_enable, 0);
559*4882a593Smuzhiyun usleep_range(500, 1000);
560*4882a593Smuzhiyun gpiod_set_value_cansleep(data->chip_enable, 1);
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun return 0;
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
vl6180_custom_init(struct vl6180_data * data)566*4882a593Smuzhiyun static int vl6180_custom_init(struct vl6180_data *data)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun struct i2c_client *client = data->client;
569*4882a593Smuzhiyun int ret;
570*4882a593Smuzhiyun int i;
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun /* REGISTER_TUNING_SR03_270514_CustomerView.txt */
573*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(vl6180_custom_data_table); ++i) {
574*4882a593Smuzhiyun ret = vl6180_write_byte(client,
575*4882a593Smuzhiyun vl6180_custom_data_table[i].reg,
576*4882a593Smuzhiyun vl6180_custom_data_table[i].val);
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun if (ret < 0)
579*4882a593Smuzhiyun break;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun return ret;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
vl6180_range_init(struct vl6180_data * data)585*4882a593Smuzhiyun static int vl6180_range_init(struct vl6180_data *data)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun struct i2c_client *client = data->client;
588*4882a593Smuzhiyun int ret;
589*4882a593Smuzhiyun u8 enables;
590*4882a593Smuzhiyun u8 offset;
591*4882a593Smuzhiyun u8 xtalk = 3;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun /* Enables polling for ‘New Sample ready’ when measurement completes */
594*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_SYS_MODE_GPIO1,
595*4882a593Smuzhiyun (VL6180_SYS_GPIO1_POLARITY |
596*4882a593Smuzhiyun VL6180_SYS_GPIO1_SELECT));
597*4882a593Smuzhiyun if (ret < 0)
598*4882a593Smuzhiyun goto out;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun /* Set the averaging sample period (compromise between lower noise and
601*4882a593Smuzhiyun * increased execution time), 0x30 equals to 4.3 ms.
602*4882a593Smuzhiyun */
603*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_READOUT_AVERAGING_SAMPLE_PERIOD,
604*4882a593Smuzhiyun 0x30);
605*4882a593Smuzhiyun if (ret < 0)
606*4882a593Smuzhiyun goto out;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun /* Sets the # of range measurements after which auto calibration of
609*4882a593Smuzhiyun * system is performed
610*4882a593Smuzhiyun */
611*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_RANGE_VHV_REPEAT_RATE, 0xff);
612*4882a593Smuzhiyun if (ret < 0)
613*4882a593Smuzhiyun goto out;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun /* Perform a single temperature calibration of the ranging sensor */
616*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_RANGE_VHV_RECALIBRATE, 0x01);
617*4882a593Smuzhiyun if (ret < 0)
618*4882a593Smuzhiyun goto out;
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun /* Set SNR limit to 0.06 */
621*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_RANGE_MAX_AMBIENT_LEVEL_MULT,
622*4882a593Smuzhiyun 0xff);
623*4882a593Smuzhiyun if (ret < 0)
624*4882a593Smuzhiyun goto out;
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun /* Set default ranging inter-measurement period to 100ms */
627*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_RANGE_INTER_MES_PERIOD, 0x09);
628*4882a593Smuzhiyun if (ret < 0)
629*4882a593Smuzhiyun goto out;
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun /* Copy registers */
632*4882a593Smuzhiyun /* NOTE: 0x0da, 0x027, 0x0db, 0x028, 0x0dc, 0x029 and 0x0dd are
633*4882a593Smuzhiyun * unavailable on the datasheet.
634*4882a593Smuzhiyun */
635*4882a593Smuzhiyun ret = vl6180_read_byte(client, VL6180_RANGE_RANGE_IGNORE_THRESHOLD);
636*4882a593Smuzhiyun if (ret < 0)
637*4882a593Smuzhiyun goto out;
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun ret = vl6180_write_byte(client, 0x0da, ret);
640*4882a593Smuzhiyun if (ret < 0)
641*4882a593Smuzhiyun goto out;
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun ret = vl6180_read_byte(client, 0x027);
644*4882a593Smuzhiyun if (ret < 0)
645*4882a593Smuzhiyun goto out;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun ret = vl6180_write_byte(client, 0x0db, ret);
648*4882a593Smuzhiyun if (ret < 0)
649*4882a593Smuzhiyun goto out;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun ret = vl6180_read_byte(client, 0x028);
652*4882a593Smuzhiyun if (ret < 0)
653*4882a593Smuzhiyun goto out;
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun ret = vl6180_write_byte(client, 0x0dc, ret);
656*4882a593Smuzhiyun if (ret < 0)
657*4882a593Smuzhiyun goto out;
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun ret = vl6180_read_byte(client, 0x029);
660*4882a593Smuzhiyun if (ret < 0)
661*4882a593Smuzhiyun goto out;
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun ret = vl6180_write_byte(client, 0x0dd, ret);
664*4882a593Smuzhiyun if (ret < 0)
665*4882a593Smuzhiyun goto out;
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_RANGE_MAX_CONVERGENCE_TIME, 0x32);
668*4882a593Smuzhiyun if (ret < 0)
669*4882a593Smuzhiyun goto out;
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun ret = vl6180_read_byte(client, VL6180_RANGE_RANGE_CHECK_ENABLES);
672*4882a593Smuzhiyun if (ret < 0)
673*4882a593Smuzhiyun goto out;
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun /* Disable early convergence */
676*4882a593Smuzhiyun enables = ret & 0xfe;
677*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_RANGE_RANGE_CHECK_ENABLES, enables);
678*4882a593Smuzhiyun if (ret < 0)
679*4882a593Smuzhiyun goto out;
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_RANGE_THRESH_HIGH, 0xc8);
682*4882a593Smuzhiyun if (ret < 0)
683*4882a593Smuzhiyun goto out;
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_RANGE_THRESH_LOW, 0x00);
686*4882a593Smuzhiyun if (ret < 0)
687*4882a593Smuzhiyun goto out;
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_ALS_IT, VL6180_ALS_IT_100);
690*4882a593Smuzhiyun if (ret < 0)
691*4882a593Smuzhiyun goto out;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_ALS_INTER_MES_PERIOD, 0x13);
694*4882a593Smuzhiyun if (ret < 0)
695*4882a593Smuzhiyun goto out;
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_ALS_GAIN, VL6180_ALS_GAIN_1);
698*4882a593Smuzhiyun if (ret < 0)
699*4882a593Smuzhiyun goto out;
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_ALS_THRESH_LOW, 0x00);
702*4882a593Smuzhiyun if (ret < 0)
703*4882a593Smuzhiyun goto out;
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_ALS_THRESH_HIGH, 0xff);
706*4882a593Smuzhiyun if (ret < 0)
707*4882a593Smuzhiyun goto out;
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun /* Cover glass ignore */
710*4882a593Smuzhiyun ret = vl6180_write_byte(client,
711*4882a593Smuzhiyun VL6180_RANGE_RANGE_IGNORE_VALID_HEIGHT, 0xff);
712*4882a593Smuzhiyun if (ret < 0)
713*4882a593Smuzhiyun goto out;
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun ret = vl6180_read_byte(client, VL6180_RANGE_PART_TO_PART_RANGE_OFFSET);
716*4882a593Smuzhiyun if (ret < 0)
717*4882a593Smuzhiyun goto out;
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun /* Apply default calibration on part to part offset */
720*4882a593Smuzhiyun offset = ret / 4;
721*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_RANGE_PART_TO_PART_RANGE_OFFSET,
722*4882a593Smuzhiyun offset);
723*4882a593Smuzhiyun if (ret < 0)
724*4882a593Smuzhiyun goto out;
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun ret = vl6180_write_byte(client,
727*4882a593Smuzhiyun VL6180_RANGE_CROSSTALK_COMPENSATION_RATE,
728*4882a593Smuzhiyun 0x00);
729*4882a593Smuzhiyun if (ret < 0)
730*4882a593Smuzhiyun goto out;
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun ret = vl6180_write_byte(client, 0x01f, xtalk);
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun out:
735*4882a593Smuzhiyun return ret;
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun
vl6180_init(struct vl6180_data * data)738*4882a593Smuzhiyun static int vl6180_init(struct vl6180_data *data)
739*4882a593Smuzhiyun {
740*4882a593Smuzhiyun struct i2c_client *client = data->client;
741*4882a593Smuzhiyun int ret;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun ret = vl6180_power_enable(data);
744*4882a593Smuzhiyun if (ret) {
745*4882a593Smuzhiyun dev_err(&client->dev, "failed to configure power\n");
746*4882a593Smuzhiyun return ret;
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun /*
750*4882a593Smuzhiyun * After the MCU boot sequence the device enters software standby,
751*4882a593Smuzhiyun * host initialization can commence immediately after entering
752*4882a593Smuzhiyun * software standby.
753*4882a593Smuzhiyun */
754*4882a593Smuzhiyun usleep_range(500, 1000);
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun ret = vl6180_read_byte(client, VL6180_MODEL_ID);
757*4882a593Smuzhiyun if (ret < 0)
758*4882a593Smuzhiyun return ret;
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun if (ret != VL6180_MODEL_ID_VAL) {
761*4882a593Smuzhiyun dev_err(&client->dev, "invalid model ID %02x\n", ret);
762*4882a593Smuzhiyun return -ENODEV;
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun ret = vl6180_hold(data, true);
766*4882a593Smuzhiyun if (ret < 0)
767*4882a593Smuzhiyun return ret;
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun ret = vl6180_read_byte(client, VL6180_OUT_OF_RESET);
770*4882a593Smuzhiyun if (ret < 0)
771*4882a593Smuzhiyun return ret;
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun /*
774*4882a593Smuzhiyun * Detect false reset condition here. This bit is always set when the
775*4882a593Smuzhiyun * system comes out of reset.
776*4882a593Smuzhiyun */
777*4882a593Smuzhiyun if (ret != 0x01)
778*4882a593Smuzhiyun dev_info(&client->dev, "device is not fresh out of reset\n");
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun /* ALS integration time: 100ms */
781*4882a593Smuzhiyun data->als_it_ms = 100;
782*4882a593Smuzhiyun ret = vl6180_write_word(client, VL6180_ALS_IT, VL6180_ALS_IT_100);
783*4882a593Smuzhiyun if (ret < 0)
784*4882a593Smuzhiyun return ret;
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun /* ALS gain: 1 */
787*4882a593Smuzhiyun data->als_gain_milli = 1000;
788*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_ALS_GAIN, VL6180_ALS_GAIN_1);
789*4882a593Smuzhiyun if (ret < 0)
790*4882a593Smuzhiyun return ret;
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun ret = vl6180_custom_init(data);
793*4882a593Smuzhiyun if (ret < 0)
794*4882a593Smuzhiyun return ret;
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun ret = vl6180_range_init(data);
797*4882a593Smuzhiyun if (ret < 0)
798*4882a593Smuzhiyun return ret;
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_RANGE_START,
801*4882a593Smuzhiyun (VL6180_STARTSTOP | VL6180_MODE_CONT));
802*4882a593Smuzhiyun if (ret < 0)
803*4882a593Smuzhiyun return ret;
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun ret = vl6180_write_byte(client, VL6180_OUT_OF_RESET, 0x00);
806*4882a593Smuzhiyun if (ret < 0)
807*4882a593Smuzhiyun return ret;
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun return vl6180_hold(data, false);
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun
vl6180_irq_thread(int irq,void * priv)812*4882a593Smuzhiyun static irqreturn_t vl6180_irq_thread(int irq, void *priv)
813*4882a593Smuzhiyun {
814*4882a593Smuzhiyun struct vl6180_data *data = priv;
815*4882a593Smuzhiyun struct i2c_client *client = data->client;
816*4882a593Smuzhiyun struct iio_dev *indio_dev = i2c_get_clientdata(client);
817*4882a593Smuzhiyun int ret;
818*4882a593Smuzhiyun u8 val = 0;
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun ret = vl6180_read_byte(client, VL6180_INTR_STATUS);
821*4882a593Smuzhiyun if (ret < 0)
822*4882a593Smuzhiyun goto out;
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun if (ret & VL6180_INT_ALS_GPIO_MASK)
825*4882a593Smuzhiyun val |= VL6180_CLEAR_ALS;
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun if (ret & VL6180_INT_RANGE_GPIO_MASK)
828*4882a593Smuzhiyun val |= VL6180_CLEAR_RANGE;
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun if (ret & VL6180_INT_ERR_GPIO_MASK)
831*4882a593Smuzhiyun val |= VL6180_CLEAR_ERROR;
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun vl6180_write_byte(client, VL6180_INTR_CLEAR, val);
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun ret = vl6180_read_word(client, VL6180_ALS_VALUE);
836*4882a593Smuzhiyun if (ret < 0)
837*4882a593Smuzhiyun goto out;
838*4882a593Smuzhiyun data->scan.channels[VL6180_ALS] = ret;
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun ret = vl6180_read_byte(client, VL6180_RANGE_VALUE);
841*4882a593Smuzhiyun if (ret < 0)
842*4882a593Smuzhiyun goto out;
843*4882a593Smuzhiyun data->scan.channels[VL6180_RANGE] = ret;
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun ret = vl6180_read_word(client, VL6180_RANGE_RATE);
846*4882a593Smuzhiyun if (ret < 0)
847*4882a593Smuzhiyun goto out;
848*4882a593Smuzhiyun data->scan.channels[VL6180_PROX] = ret;
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
851*4882a593Smuzhiyun ktime_get_boottime_ns());
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun out:
854*4882a593Smuzhiyun return IRQ_HANDLED;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun
vl6180_buffer_preenable(struct iio_dev * indio_dev)857*4882a593Smuzhiyun static int vl6180_buffer_preenable(struct iio_dev *indio_dev)
858*4882a593Smuzhiyun {
859*4882a593Smuzhiyun struct vl6180_data *data = iio_priv(indio_dev);
860*4882a593Smuzhiyun u8 val;
861*4882a593Smuzhiyun int ret;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun ret = vl6180_read_byte(data->client, VL6180_INTR_CONFIG);
864*4882a593Smuzhiyun if (ret < 0)
865*4882a593Smuzhiyun return ret;
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun /* Enable ALS and Range ready interrupts */
868*4882a593Smuzhiyun val = ret | VL6180_ALS_READY | VL6180_RANGE_READY;
869*4882a593Smuzhiyun ret = vl6180_write_byte(data->client, VL6180_INTR_CONFIG, val);
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun return ret;
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun
vl6180_buffer_postdisable(struct iio_dev * indio_dev)874*4882a593Smuzhiyun static int vl6180_buffer_postdisable(struct iio_dev *indio_dev)
875*4882a593Smuzhiyun {
876*4882a593Smuzhiyun struct vl6180_data *data = iio_priv(indio_dev);
877*4882a593Smuzhiyun u8 val;
878*4882a593Smuzhiyun int ret;
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun ret = vl6180_read_byte(data->client, VL6180_INTR_CONFIG);
881*4882a593Smuzhiyun if (ret < 0)
882*4882a593Smuzhiyun return ret;
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun /* Disable ALS and Range ready interrupts */
885*4882a593Smuzhiyun val = ret & ~(VL6180_ALS_READY | VL6180_RANGE_READY);
886*4882a593Smuzhiyun ret = vl6180_write_byte(data->client, VL6180_INTR_CONFIG, val);
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun return ret;
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun static const struct iio_buffer_setup_ops vl6180_buffer_setup_ops = {
892*4882a593Smuzhiyun .preenable = vl6180_buffer_preenable,
893*4882a593Smuzhiyun .postdisable = vl6180_buffer_postdisable,
894*4882a593Smuzhiyun };
895*4882a593Smuzhiyun
vl6180_probe(struct i2c_client * client,const struct i2c_device_id * id)896*4882a593Smuzhiyun static int vl6180_probe(struct i2c_client *client,
897*4882a593Smuzhiyun const struct i2c_device_id *id)
898*4882a593Smuzhiyun {
899*4882a593Smuzhiyun struct vl6180_data *data;
900*4882a593Smuzhiyun struct iio_dev *indio_dev;
901*4882a593Smuzhiyun struct iio_buffer *buffer;
902*4882a593Smuzhiyun u32 type;
903*4882a593Smuzhiyun int ret;
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
906*4882a593Smuzhiyun if (!indio_dev)
907*4882a593Smuzhiyun return -ENOMEM;
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun data = iio_priv(indio_dev);
910*4882a593Smuzhiyun i2c_set_clientdata(client, indio_dev);
911*4882a593Smuzhiyun data->client = client;
912*4882a593Smuzhiyun mutex_init(&data->lock);
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun indio_dev->info = &vl6180_info;
915*4882a593Smuzhiyun indio_dev->channels = vl6180_channels;
916*4882a593Smuzhiyun indio_dev->num_channels = ARRAY_SIZE(vl6180_channels);
917*4882a593Smuzhiyun indio_dev->name = VL6180_DRV_NAME;
918*4882a593Smuzhiyun indio_dev->modes = INDIO_DIRECT_MODE;
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun /*
921*4882a593Smuzhiyun * NOTE: If the power is controlled by gpio, the power
922*4882a593Smuzhiyun * configuration should match the power-up timing.
923*4882a593Smuzhiyun */
924*4882a593Smuzhiyun data->avdd = devm_gpiod_get_optional(&client->dev, "avdd",
925*4882a593Smuzhiyun GPIOD_OUT_HIGH);
926*4882a593Smuzhiyun data->chip_enable = devm_gpiod_get_optional(&client->dev, "chip-enable",
927*4882a593Smuzhiyun GPIOD_OUT_HIGH);
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun ret = vl6180_init(data);
930*4882a593Smuzhiyun if (ret < 0)
931*4882a593Smuzhiyun return ret;
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun if (client->irq) {
934*4882a593Smuzhiyun buffer = devm_iio_kfifo_allocate(&client->dev);
935*4882a593Smuzhiyun if (!buffer)
936*4882a593Smuzhiyun return -ENOMEM;
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun iio_device_attach_buffer(indio_dev, buffer);
939*4882a593Smuzhiyun indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
940*4882a593Smuzhiyun indio_dev->setup_ops = &vl6180_buffer_setup_ops;
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun type = irqd_get_trigger_type(irq_get_irq_data(client->irq));
943*4882a593Smuzhiyun ret = devm_request_threaded_irq(&client->dev, client->irq,
944*4882a593Smuzhiyun NULL, vl6180_irq_thread,
945*4882a593Smuzhiyun type | IRQF_ONESHOT, "vl6180",
946*4882a593Smuzhiyun data);
947*4882a593Smuzhiyun if (ret) {
948*4882a593Smuzhiyun dev_err(&client->dev,
949*4882a593Smuzhiyun "failed to request vl6180 IRQ\n");
950*4882a593Smuzhiyun return ret;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun return devm_iio_device_register(&client->dev, indio_dev);
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun static const struct of_device_id vl6180_of_match[] = {
958*4882a593Smuzhiyun { .compatible = "st,vl6180", },
959*4882a593Smuzhiyun { },
960*4882a593Smuzhiyun };
961*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, vl6180_of_match);
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun static const struct i2c_device_id vl6180_id[] = {
964*4882a593Smuzhiyun { "vl6180", 0 },
965*4882a593Smuzhiyun { }
966*4882a593Smuzhiyun };
967*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, vl6180_id);
968*4882a593Smuzhiyun
969*4882a593Smuzhiyun static struct i2c_driver vl6180_driver = {
970*4882a593Smuzhiyun .driver = {
971*4882a593Smuzhiyun .name = VL6180_DRV_NAME,
972*4882a593Smuzhiyun .of_match_table = vl6180_of_match,
973*4882a593Smuzhiyun },
974*4882a593Smuzhiyun .probe = vl6180_probe,
975*4882a593Smuzhiyun .id_table = vl6180_id,
976*4882a593Smuzhiyun };
977*4882a593Smuzhiyun
978*4882a593Smuzhiyun module_i2c_driver(vl6180_driver);
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
981*4882a593Smuzhiyun MODULE_AUTHOR("Manivannan Sadhasivam <manivannanece23@gmail.com>");
982*4882a593Smuzhiyun MODULE_DESCRIPTION("STMicro VL6180 ALS, range and proximity sensor driver");
983*4882a593Smuzhiyun MODULE_LICENSE("GPL");
984