136edc939SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
262a1efb9SPeter Meerwald /*
35a441aadSAngus Ainslie (Purism) * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4040/4200 combined ambient
4d978bfddSPeter Meerwald-Stadler * light and proximity sensor
562a1efb9SPeter Meerwald *
662a1efb9SPeter Meerwald * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
75a441aadSAngus Ainslie (Purism) * Copyright 2019 Pursim SPC
88fe78d52SMathieu Othacehe * Copyright 2020 Mathieu Othacehe <m.othacehe@gmail.com>
962a1efb9SPeter Meerwald *
10be38866fSTomas Novotny * IIO driver for:
11be38866fSTomas Novotny * VCNL4000/10/20 (7-bit I2C slave address 0x13)
125a441aadSAngus Ainslie (Purism) * VCNL4040 (7-bit I2C slave address 0x60)
13be38866fSTomas Novotny * VCNL4200 (7-bit I2C slave address 0x51)
1462a1efb9SPeter Meerwald *
1562a1efb9SPeter Meerwald * TODO:
1662a1efb9SPeter Meerwald * allow to adjust IR current
178fe78d52SMathieu Othacehe * interrupts (VCNL4040, VCNL4200)
1862a1efb9SPeter Meerwald */
1962a1efb9SPeter Meerwald
2085e2c6a2SMårten Lindahl #include <linux/bitfield.h>
2162a1efb9SPeter Meerwald #include <linux/module.h>
2262a1efb9SPeter Meerwald #include <linux/i2c.h>
2362a1efb9SPeter Meerwald #include <linux/err.h>
2462a1efb9SPeter Meerwald #include <linux/delay.h>
255e00708dSGuido Günther #include <linux/pm_runtime.h>
26d35567fcSMathieu Othacehe #include <linux/interrupt.h>
277f865127SAstrid Rost #include <linux/units.h>
2862a1efb9SPeter Meerwald
298fe78d52SMathieu Othacehe #include <linux/iio/buffer.h>
30d35567fcSMathieu Othacehe #include <linux/iio/events.h>
3162a1efb9SPeter Meerwald #include <linux/iio/iio.h>
3262a1efb9SPeter Meerwald #include <linux/iio/sysfs.h>
338fe78d52SMathieu Othacehe #include <linux/iio/trigger.h>
348fe78d52SMathieu Othacehe #include <linux/iio/trigger_consumer.h>
358fe78d52SMathieu Othacehe #include <linux/iio/triggered_buffer.h>
3662a1efb9SPeter Meerwald
3762a1efb9SPeter Meerwald #define VCNL4000_DRV_NAME "vcnl4000"
381ebc787aSTomas Novotny #define VCNL4000_PROD_ID 0x01
391ebc787aSTomas Novotny #define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */
405a441aadSAngus Ainslie (Purism) #define VCNL4040_PROD_ID 0x86
41be38866fSTomas Novotny #define VCNL4200_PROD_ID 0x58
4262a1efb9SPeter Meerwald
4362a1efb9SPeter Meerwald #define VCNL4000_COMMAND 0x80 /* Command register */
4462a1efb9SPeter Meerwald #define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */
45d35567fcSMathieu Othacehe #define VCNL4010_PROX_RATE 0x82 /* Proximity rate */
4662a1efb9SPeter Meerwald #define VCNL4000_LED_CURRENT 0x83 /* IR LED current for proximity mode */
4762a1efb9SPeter Meerwald #define VCNL4000_AL_PARAM 0x84 /* Ambient light parameter register */
48d35567fcSMathieu Othacehe #define VCNL4010_ALS_PARAM 0x84 /* ALS rate */
4962a1efb9SPeter Meerwald #define VCNL4000_AL_RESULT_HI 0x85 /* Ambient light result register, MSB */
5062a1efb9SPeter Meerwald #define VCNL4000_AL_RESULT_LO 0x86 /* Ambient light result register, LSB */
5162a1efb9SPeter Meerwald #define VCNL4000_PS_RESULT_HI 0x87 /* Proximity result register, MSB */
5262a1efb9SPeter Meerwald #define VCNL4000_PS_RESULT_LO 0x88 /* Proximity result register, LSB */
5362a1efb9SPeter Meerwald #define VCNL4000_PS_MEAS_FREQ 0x89 /* Proximity test signal frequency */
54d35567fcSMathieu Othacehe #define VCNL4010_INT_CTRL 0x89 /* Interrupt control */
5562a1efb9SPeter Meerwald #define VCNL4000_PS_MOD_ADJ 0x8a /* Proximity modulator timing adjustment */
56d35567fcSMathieu Othacehe #define VCNL4010_LOW_THR_HI 0x8a /* Low threshold, MSB */
57d35567fcSMathieu Othacehe #define VCNL4010_LOW_THR_LO 0x8b /* Low threshold, LSB */
58d35567fcSMathieu Othacehe #define VCNL4010_HIGH_THR_HI 0x8c /* High threshold, MSB */
59d35567fcSMathieu Othacehe #define VCNL4010_HIGH_THR_LO 0x8d /* High threshold, LSB */
60d35567fcSMathieu Othacehe #define VCNL4010_ISR 0x8e /* Interrupt status */
6162a1efb9SPeter Meerwald
62be38866fSTomas Novotny #define VCNL4200_AL_CONF 0x00 /* Ambient light configuration */
63be38866fSTomas Novotny #define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */
64add98466SAstrid Rost #define VCNL4200_PS_CONF3 0x04 /* Proximity configuration */
6554667612SMårten Lindahl #define VCNL4040_PS_THDL_LM 0x06 /* Proximity threshold low */
6654667612SMårten Lindahl #define VCNL4040_PS_THDH_LM 0x07 /* Proximity threshold high */
67bc292aafSAstrid Rost #define VCNL4040_ALS_THDL_LM 0x02 /* Ambient light threshold low */
68bc292aafSAstrid Rost #define VCNL4040_ALS_THDH_LM 0x01 /* Ambient light threshold high */
69be38866fSTomas Novotny #define VCNL4200_PS_DATA 0x08 /* Proximity data */
70be38866fSTomas Novotny #define VCNL4200_AL_DATA 0x09 /* Ambient light data */
7154667612SMårten Lindahl #define VCNL4040_INT_FLAGS 0x0b /* Interrupt register */
72854965b7SAstrid Rost #define VCNL4200_INT_FLAGS 0x0d /* Interrupt register */
73be38866fSTomas Novotny #define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */
74be38866fSTomas Novotny
755a441aadSAngus Ainslie (Purism) #define VCNL4040_DEV_ID 0x0c /* Device ID and version */
765a441aadSAngus Ainslie (Purism)
7762a1efb9SPeter Meerwald /* Bit masks for COMMAND register */
78ff6a5259SPeter Meerwald-Stadler #define VCNL4000_AL_RDY BIT(6) /* ALS data ready? */
79ff6a5259SPeter Meerwald-Stadler #define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */
80ff6a5259SPeter Meerwald-Stadler #define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */
81ff6a5259SPeter Meerwald-Stadler #define VCNL4000_PS_OD BIT(3) /* start on-demand proximity measurement */
82d35567fcSMathieu Othacehe #define VCNL4000_ALS_EN BIT(2) /* start ALS measurement */
83d35567fcSMathieu Othacehe #define VCNL4000_PROX_EN BIT(1) /* start proximity measurement */
84d35567fcSMathieu Othacehe #define VCNL4000_SELF_TIMED_EN BIT(0) /* start self-timed measurement */
85d35567fcSMathieu Othacehe
86e21b5b1fSMårten Lindahl #define VCNL4040_ALS_CONF_ALS_SHUTDOWN BIT(0)
87fea2c97dSAstrid Rost #define VCNL4040_ALS_CONF_IT GENMASK(7, 6) /* Ambient integration time */
88bc292aafSAstrid Rost #define VCNL4040_ALS_CONF_INT_EN BIT(1) /* Ambient light Interrupt enable */
897f865127SAstrid Rost #define VCNL4040_ALS_CONF_PERS GENMASK(3, 2) /* Ambient interrupt persistence setting */
90e21b5b1fSMårten Lindahl #define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0)
9185e2c6a2SMårten Lindahl #define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */
927f865127SAstrid Rost #define VCNL4040_CONF1_PS_PERS GENMASK(5, 4) /* Proximity interrupt persistence setting */
93*44b90383SMårten Lindahl #define VCNL4040_PS_CONF2_PS_HD BIT(11) /* Proximity high definition */
9454667612SMårten Lindahl #define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */
95add98466SAstrid Rost #define VCNL4040_PS_CONF3_MPS GENMASK(6, 5) /* Proximity multi pulse number */
96bb33e751SAstrid Rost #define VCNL4040_PS_MS_LED_I GENMASK(10, 8) /* Proximity current */
9754667612SMårten Lindahl #define VCNL4040_PS_IF_AWAY BIT(8) /* Proximity event cross low threshold */
9854667612SMårten Lindahl #define VCNL4040_PS_IF_CLOSE BIT(9) /* Proximity event cross high threshold */
99bc292aafSAstrid Rost #define VCNL4040_ALS_RISING BIT(12) /* Ambient Light cross high threshold */
100bc292aafSAstrid Rost #define VCNL4040_ALS_FALLING BIT(13) /* Ambient Light cross low threshold */
101e21b5b1fSMårten Lindahl
102d35567fcSMathieu Othacehe /* Bit masks for interrupt registers. */
103d35567fcSMathieu Othacehe #define VCNL4010_INT_THR_SEL BIT(0) /* Select threshold interrupt source */
104d35567fcSMathieu Othacehe #define VCNL4010_INT_THR_EN BIT(1) /* Threshold interrupt type */
105d35567fcSMathieu Othacehe #define VCNL4010_INT_ALS_EN BIT(2) /* Enable on ALS data ready */
106d35567fcSMathieu Othacehe #define VCNL4010_INT_PROX_EN BIT(3) /* Enable on proximity data ready */
107d35567fcSMathieu Othacehe
108d35567fcSMathieu Othacehe #define VCNL4010_INT_THR_HIGH 0 /* High threshold exceeded */
109d35567fcSMathieu Othacehe #define VCNL4010_INT_THR_LOW 1 /* Low threshold exceeded */
110d35567fcSMathieu Othacehe #define VCNL4010_INT_ALS 2 /* ALS data ready */
111d35567fcSMathieu Othacehe #define VCNL4010_INT_PROXIMITY 3 /* Proximity data ready */
112d35567fcSMathieu Othacehe
113d35567fcSMathieu Othacehe #define VCNL4010_INT_THR \
114d35567fcSMathieu Othacehe (BIT(VCNL4010_INT_THR_LOW) | BIT(VCNL4010_INT_THR_HIGH))
115d35567fcSMathieu Othacehe #define VCNL4010_INT_DRDY \
116d35567fcSMathieu Othacehe (BIT(VCNL4010_INT_PROXIMITY) | BIT(VCNL4010_INT_ALS))
117d35567fcSMathieu Othacehe
118*44b90383SMårten Lindahl #define VCNL4040_CONF3_PS_MPS_16BITS 3 /* 8 multi pulses */
119*44b90383SMårten Lindahl #define VCNL4040_CONF3_PS_LED_I_16BITS 3 /* 120 mA */
120*44b90383SMårten Lindahl
121*44b90383SMårten Lindahl #define VCNL4040_CONF3_PS_SAMPLE_16BITS \
122*44b90383SMårten Lindahl (FIELD_PREP(VCNL4040_PS_CONF3_MPS, VCNL4040_CONF3_PS_MPS_16BITS) | \
123*44b90383SMårten Lindahl FIELD_PREP(VCNL4040_PS_MS_LED_I, VCNL4040_CONF3_PS_LED_I_16BITS))
124*44b90383SMårten Lindahl
125f6889c1bSMathieu Othacehe static const int vcnl4010_prox_sampling_frequency[][2] = {
126f6889c1bSMathieu Othacehe {1, 950000},
127f6889c1bSMathieu Othacehe {3, 906250},
128f6889c1bSMathieu Othacehe {7, 812500},
129f6889c1bSMathieu Othacehe {16, 625000},
130f6889c1bSMathieu Othacehe {31, 250000},
131f6889c1bSMathieu Othacehe {62, 500000},
132f6889c1bSMathieu Othacehe {125, 0},
133f6889c1bSMathieu Othacehe {250, 0},
134f6889c1bSMathieu Othacehe };
13562a1efb9SPeter Meerwald
13685e2c6a2SMårten Lindahl static const int vcnl4040_ps_it_times[][2] = {
13785e2c6a2SMårten Lindahl {0, 100},
13885e2c6a2SMårten Lindahl {0, 150},
13985e2c6a2SMårten Lindahl {0, 200},
14085e2c6a2SMårten Lindahl {0, 250},
14185e2c6a2SMårten Lindahl {0, 300},
14285e2c6a2SMårten Lindahl {0, 350},
14385e2c6a2SMårten Lindahl {0, 400},
14485e2c6a2SMårten Lindahl {0, 800},
14585e2c6a2SMårten Lindahl };
14685e2c6a2SMårten Lindahl
147e55c96daSAstrid Rost static const int vcnl4200_ps_it_times[][2] = {
148e55c96daSAstrid Rost {0, 96},
149e55c96daSAstrid Rost {0, 144},
150e55c96daSAstrid Rost {0, 192},
151e55c96daSAstrid Rost {0, 384},
152e55c96daSAstrid Rost {0, 768},
153e55c96daSAstrid Rost {0, 864},
154e55c96daSAstrid Rost };
155e55c96daSAstrid Rost
156fea2c97dSAstrid Rost static const int vcnl4040_als_it_times[][2] = {
157fea2c97dSAstrid Rost {0, 80000},
158fea2c97dSAstrid Rost {0, 160000},
159fea2c97dSAstrid Rost {0, 320000},
160fea2c97dSAstrid Rost {0, 640000},
161fea2c97dSAstrid Rost };
162fea2c97dSAstrid Rost
163fea2c97dSAstrid Rost static const int vcnl4200_als_it_times[][2] = {
164fea2c97dSAstrid Rost {0, 50000},
165fea2c97dSAstrid Rost {0, 100000},
166fea2c97dSAstrid Rost {0, 200000},
167fea2c97dSAstrid Rost {0, 400000},
168fea2c97dSAstrid Rost };
169fea2c97dSAstrid Rost
170bb33e751SAstrid Rost static const int vcnl4040_ps_calibbias_ua[][2] = {
171bb33e751SAstrid Rost {0, 50000},
172bb33e751SAstrid Rost {0, 75000},
173bb33e751SAstrid Rost {0, 100000},
174bb33e751SAstrid Rost {0, 120000},
175bb33e751SAstrid Rost {0, 140000},
176bb33e751SAstrid Rost {0, 160000},
177bb33e751SAstrid Rost {0, 180000},
178bb33e751SAstrid Rost {0, 200000},
179bb33e751SAstrid Rost };
180bb33e751SAstrid Rost
1817f865127SAstrid Rost static const int vcnl4040_als_persistence[] = {1, 2, 4, 8};
1827f865127SAstrid Rost static const int vcnl4040_ps_persistence[] = {1, 2, 3, 4};
183add98466SAstrid Rost static const int vcnl4040_ps_oversampling_ratio[] = {1, 2, 4, 8};
1847f865127SAstrid Rost
1855e00708dSGuido Günther #define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */
1865e00708dSGuido Günther
1871ebc787aSTomas Novotny enum vcnl4000_device_ids {
1881ebc787aSTomas Novotny VCNL4000,
18950c50b97STomas Novotny VCNL4010,
1905a441aadSAngus Ainslie (Purism) VCNL4040,
191be38866fSTomas Novotny VCNL4200,
192be38866fSTomas Novotny };
193be38866fSTomas Novotny
194be38866fSTomas Novotny struct vcnl4200_channel {
195be38866fSTomas Novotny u8 reg;
196be38866fSTomas Novotny ktime_t last_measurement;
197be38866fSTomas Novotny ktime_t sampling_rate;
198be38866fSTomas Novotny struct mutex lock;
1991ebc787aSTomas Novotny };
2001ebc787aSTomas Novotny
20162a1efb9SPeter Meerwald struct vcnl4000_data {
20262a1efb9SPeter Meerwald struct i2c_client *client;
2031ebc787aSTomas Novotny enum vcnl4000_device_ids id;
2041ebc787aSTomas Novotny int rev;
2051ebc787aSTomas Novotny int al_scale;
206*44b90383SMårten Lindahl int ps_scale;
20754667612SMårten Lindahl u8 ps_int; /* proximity interrupt mode */
208bc292aafSAstrid Rost u8 als_int; /* ambient light interrupt mode*/
2091ebc787aSTomas Novotny const struct vcnl4000_chip_spec *chip_spec;
210be38866fSTomas Novotny struct mutex vcnl4000_lock;
211be38866fSTomas Novotny struct vcnl4200_channel vcnl4200_al;
212be38866fSTomas Novotny struct vcnl4200_channel vcnl4200_ps;
213f5a98e1fSGuido Günther uint32_t near_level;
21462a1efb9SPeter Meerwald };
21562a1efb9SPeter Meerwald
2161ebc787aSTomas Novotny struct vcnl4000_chip_spec {
2171ebc787aSTomas Novotny const char *prod;
218d35567fcSMathieu Othacehe struct iio_chan_spec const *channels;
219d35567fcSMathieu Othacehe const int num_channels;
220d35567fcSMathieu Othacehe const struct iio_info *info;
221bfb6cfeeSMårten Lindahl const struct iio_buffer_setup_ops *buffer_setup_ops;
2221ebc787aSTomas Novotny int (*init)(struct vcnl4000_data *data);
2231ebc787aSTomas Novotny int (*measure_light)(struct vcnl4000_data *data, int *val);
2241ebc787aSTomas Novotny int (*measure_proximity)(struct vcnl4000_data *data, int *val);
2255e00708dSGuido Günther int (*set_power_state)(struct vcnl4000_data *data, bool on);
226bfb6cfeeSMårten Lindahl irqreturn_t (*irq_thread)(int irq, void *priv);
227bfb6cfeeSMårten Lindahl irqreturn_t (*trig_buffer_func)(int irq, void *priv);
228854965b7SAstrid Rost
229854965b7SAstrid Rost u8 int_reg;
230e55c96daSAstrid Rost const int(*ps_it_times)[][2];
231e55c96daSAstrid Rost const int num_ps_it_times;
232fea2c97dSAstrid Rost const int(*als_it_times)[][2];
233fea2c97dSAstrid Rost const int num_als_it_times;
234fea2c97dSAstrid Rost const unsigned int ulux_step;
2351ebc787aSTomas Novotny };
2361ebc787aSTomas Novotny
23762a1efb9SPeter Meerwald static const struct i2c_device_id vcnl4000_id[] = {
2381ebc787aSTomas Novotny { "vcnl4000", VCNL4000 },
23950c50b97STomas Novotny { "vcnl4010", VCNL4010 },
24050c50b97STomas Novotny { "vcnl4020", VCNL4010 },
2415a441aadSAngus Ainslie (Purism) { "vcnl4040", VCNL4040 },
242be38866fSTomas Novotny { "vcnl4200", VCNL4200 },
24362a1efb9SPeter Meerwald { }
24462a1efb9SPeter Meerwald };
24562a1efb9SPeter Meerwald MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
24662a1efb9SPeter Meerwald
vcnl4000_set_power_state(struct vcnl4000_data * data,bool on)2475e00708dSGuido Günther static int vcnl4000_set_power_state(struct vcnl4000_data *data, bool on)
2485e00708dSGuido Günther {
2495e00708dSGuido Günther /* no suspend op */
2505e00708dSGuido Günther return 0;
2515e00708dSGuido Günther }
2525e00708dSGuido Günther
vcnl4000_init(struct vcnl4000_data * data)2531ebc787aSTomas Novotny static int vcnl4000_init(struct vcnl4000_data *data)
2541ebc787aSTomas Novotny {
2551ebc787aSTomas Novotny int ret, prod_id;
2561ebc787aSTomas Novotny
2571ebc787aSTomas Novotny ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
2581ebc787aSTomas Novotny if (ret < 0)
2591ebc787aSTomas Novotny return ret;
2601ebc787aSTomas Novotny
2611ebc787aSTomas Novotny prod_id = ret >> 4;
26258bf9aceSTomas Novotny switch (prod_id) {
26358bf9aceSTomas Novotny case VCNL4000_PROD_ID:
26458bf9aceSTomas Novotny if (data->id != VCNL4000)
26558bf9aceSTomas Novotny dev_warn(&data->client->dev,
26658bf9aceSTomas Novotny "wrong device id, use vcnl4000");
26758bf9aceSTomas Novotny break;
26858bf9aceSTomas Novotny case VCNL4010_PROD_ID:
26958bf9aceSTomas Novotny if (data->id != VCNL4010)
27058bf9aceSTomas Novotny dev_warn(&data->client->dev,
27158bf9aceSTomas Novotny "wrong device id, use vcnl4010/4020");
27258bf9aceSTomas Novotny break;
27358bf9aceSTomas Novotny default:
2741ebc787aSTomas Novotny return -ENODEV;
27558bf9aceSTomas Novotny }
2761ebc787aSTomas Novotny
2771ebc787aSTomas Novotny data->rev = ret & 0xf;
2781ebc787aSTomas Novotny data->al_scale = 250000;
279be38866fSTomas Novotny
2805e00708dSGuido Günther return data->chip_spec->set_power_state(data, true);
281be38866fSTomas Novotny };
282be38866fSTomas Novotny
vcnl4000_write_als_enable(struct vcnl4000_data * data,bool en)283e21b5b1fSMårten Lindahl static ssize_t vcnl4000_write_als_enable(struct vcnl4000_data *data, bool en)
2845e00708dSGuido Günther {
2855e00708dSGuido Günther int ret;
2865e00708dSGuido Günther
287e21b5b1fSMårten Lindahl mutex_lock(&data->vcnl4000_lock);
288e21b5b1fSMårten Lindahl
289e21b5b1fSMårten Lindahl ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
290e21b5b1fSMårten Lindahl if (ret < 0)
291e21b5b1fSMårten Lindahl goto out;
292e21b5b1fSMårten Lindahl
293e21b5b1fSMårten Lindahl if (en)
294e21b5b1fSMårten Lindahl ret &= ~VCNL4040_ALS_CONF_ALS_SHUTDOWN;
295e21b5b1fSMårten Lindahl else
296e21b5b1fSMårten Lindahl ret |= VCNL4040_ALS_CONF_ALS_SHUTDOWN;
297e21b5b1fSMårten Lindahl
298e21b5b1fSMårten Lindahl ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, ret);
299e21b5b1fSMårten Lindahl
300e21b5b1fSMårten Lindahl out:
301e21b5b1fSMårten Lindahl mutex_unlock(&data->vcnl4000_lock);
302e21b5b1fSMårten Lindahl
303e21b5b1fSMårten Lindahl return ret;
304e21b5b1fSMårten Lindahl }
305e21b5b1fSMårten Lindahl
vcnl4000_write_ps_enable(struct vcnl4000_data * data,bool en)306e21b5b1fSMårten Lindahl static ssize_t vcnl4000_write_ps_enable(struct vcnl4000_data *data, bool en)
307e21b5b1fSMårten Lindahl {
308e21b5b1fSMårten Lindahl int ret;
309e21b5b1fSMårten Lindahl
310e21b5b1fSMårten Lindahl mutex_lock(&data->vcnl4000_lock);
311e21b5b1fSMårten Lindahl
312e21b5b1fSMårten Lindahl ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
313e21b5b1fSMårten Lindahl if (ret < 0)
314e21b5b1fSMårten Lindahl goto out;
315e21b5b1fSMårten Lindahl
316e21b5b1fSMårten Lindahl if (en)
317e21b5b1fSMårten Lindahl ret &= ~VCNL4040_PS_CONF1_PS_SHUTDOWN;
318e21b5b1fSMårten Lindahl else
319e21b5b1fSMårten Lindahl ret |= VCNL4040_PS_CONF1_PS_SHUTDOWN;
320e21b5b1fSMårten Lindahl
321e21b5b1fSMårten Lindahl ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, ret);
322e21b5b1fSMårten Lindahl
323e21b5b1fSMårten Lindahl out:
324e21b5b1fSMårten Lindahl mutex_unlock(&data->vcnl4000_lock);
325e21b5b1fSMårten Lindahl
326e21b5b1fSMårten Lindahl return ret;
327e21b5b1fSMårten Lindahl }
328e21b5b1fSMårten Lindahl
vcnl4200_set_power_state(struct vcnl4000_data * data,bool on)329e21b5b1fSMårten Lindahl static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
330e21b5b1fSMårten Lindahl {
331e21b5b1fSMårten Lindahl int ret;
332e21b5b1fSMårten Lindahl
33354667612SMårten Lindahl /* Do not power down if interrupts are enabled */
334bc292aafSAstrid Rost if (!on && (data->ps_int || data->als_int))
33554667612SMårten Lindahl return 0;
33654667612SMårten Lindahl
337e21b5b1fSMårten Lindahl ret = vcnl4000_write_als_enable(data, on);
3385e00708dSGuido Günther if (ret < 0)
3395e00708dSGuido Günther return ret;
3405e00708dSGuido Günther
341e21b5b1fSMårten Lindahl ret = vcnl4000_write_ps_enable(data, on);
3425e00708dSGuido Günther if (ret < 0)
3435e00708dSGuido Günther return ret;
3445e00708dSGuido Günther
3455e00708dSGuido Günther if (on) {
3465e00708dSGuido Günther /* Wait at least one integration cycle before fetching data */
3475e00708dSGuido Günther data->vcnl4200_al.last_measurement = ktime_get();
3485e00708dSGuido Günther data->vcnl4200_ps.last_measurement = ktime_get();
3495e00708dSGuido Günther }
3505e00708dSGuido Günther
3515e00708dSGuido Günther return 0;
3525e00708dSGuido Günther }
3535e00708dSGuido Günther
vcnl4200_init(struct vcnl4000_data * data)354be38866fSTomas Novotny static int vcnl4200_init(struct vcnl4000_data *data)
355be38866fSTomas Novotny {
3565a441aadSAngus Ainslie (Purism) int ret, id;
357*44b90383SMårten Lindahl u16 regval;
358be38866fSTomas Novotny
359be38866fSTomas Novotny ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
360be38866fSTomas Novotny if (ret < 0)
361be38866fSTomas Novotny return ret;
362be38866fSTomas Novotny
3635a441aadSAngus Ainslie (Purism) id = ret & 0xff;
3645a441aadSAngus Ainslie (Purism)
3655a441aadSAngus Ainslie (Purism) if (id != VCNL4200_PROD_ID) {
3665a441aadSAngus Ainslie (Purism) ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID);
3675a441aadSAngus Ainslie (Purism) if (ret < 0)
3685a441aadSAngus Ainslie (Purism) return ret;
3695a441aadSAngus Ainslie (Purism)
3705a441aadSAngus Ainslie (Purism) id = ret & 0xff;
3715a441aadSAngus Ainslie (Purism)
3725a441aadSAngus Ainslie (Purism) if (id != VCNL4040_PROD_ID)
373be38866fSTomas Novotny return -ENODEV;
3745a441aadSAngus Ainslie (Purism) }
3755a441aadSAngus Ainslie (Purism)
3765a441aadSAngus Ainslie (Purism) dev_dbg(&data->client->dev, "device id 0x%x", id);
377be38866fSTomas Novotny
378be38866fSTomas Novotny data->rev = (ret >> 8) & 0xf;
37954667612SMårten Lindahl data->ps_int = 0;
380bc292aafSAstrid Rost data->als_int = 0;
381be38866fSTomas Novotny
382be38866fSTomas Novotny data->vcnl4200_al.reg = VCNL4200_AL_DATA;
383be38866fSTomas Novotny data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
3845a441aadSAngus Ainslie (Purism) switch (id) {
3855a441aadSAngus Ainslie (Purism) case VCNL4200_PROD_ID:
386b42aa97eSTomas Novotny /* Default wait time is 50ms, add 20% tolerance. */
387b42aa97eSTomas Novotny data->vcnl4200_al.sampling_rate = ktime_set(0, 60000 * 1000);
388b42aa97eSTomas Novotny /* Default wait time is 4.8ms, add 20% tolerance. */
389b42aa97eSTomas Novotny data->vcnl4200_ps.sampling_rate = ktime_set(0, 5760 * 1000);
3905a441aadSAngus Ainslie (Purism) break;
3915a441aadSAngus Ainslie (Purism) case VCNL4040_PROD_ID:
3922ca5a879STomas Novotny /* Default wait time is 80ms, add 20% tolerance. */
3932ca5a879STomas Novotny data->vcnl4200_al.sampling_rate = ktime_set(0, 96000 * 1000);
3942ca5a879STomas Novotny /* Default wait time is 5ms, add 20% tolerance. */
3952ca5a879STomas Novotny data->vcnl4200_ps.sampling_rate = ktime_set(0, 6000 * 1000);
3965a441aadSAngus Ainslie (Purism) break;
3975a441aadSAngus Ainslie (Purism) }
398fea2c97dSAstrid Rost data->al_scale = data->chip_spec->ulux_step;
399*44b90383SMårten Lindahl data->ps_scale = 16;
400be38866fSTomas Novotny mutex_init(&data->vcnl4200_al.lock);
401be38866fSTomas Novotny mutex_init(&data->vcnl4200_ps.lock);
4021ebc787aSTomas Novotny
403*44b90383SMårten Lindahl /* Use 16 bits proximity sensor readings */
404*44b90383SMårten Lindahl ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
405*44b90383SMårten Lindahl if (ret < 0)
406*44b90383SMårten Lindahl return ret;
407*44b90383SMårten Lindahl
408*44b90383SMårten Lindahl regval = ret | VCNL4040_PS_CONF2_PS_HD;
409*44b90383SMårten Lindahl ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
410*44b90383SMårten Lindahl regval);
411*44b90383SMårten Lindahl if (ret < 0)
412*44b90383SMårten Lindahl return ret;
413*44b90383SMårten Lindahl
414*44b90383SMårten Lindahl /* Align proximity sensor sample rate to 16 bits data width */
415*44b90383SMårten Lindahl ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
416*44b90383SMårten Lindahl if (ret < 0)
417*44b90383SMårten Lindahl return ret;
418*44b90383SMårten Lindahl
419*44b90383SMårten Lindahl regval = ret | VCNL4040_CONF3_PS_SAMPLE_16BITS;
420*44b90383SMårten Lindahl ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,
421*44b90383SMårten Lindahl regval);
422*44b90383SMårten Lindahl if (ret < 0)
423*44b90383SMårten Lindahl return ret;
424*44b90383SMårten Lindahl
4255e00708dSGuido Günther ret = data->chip_spec->set_power_state(data, true);
4265e00708dSGuido Günther if (ret < 0)
4275e00708dSGuido Günther return ret;
4285e00708dSGuido Günther
4291ebc787aSTomas Novotny return 0;
4301ebc787aSTomas Novotny };
4311ebc787aSTomas Novotny
vcnl4000_read_data(struct vcnl4000_data * data,u8 data_reg,int * val)432816956c3SMathieu Othacehe static int vcnl4000_read_data(struct vcnl4000_data *data, u8 data_reg, int *val)
433816956c3SMathieu Othacehe {
434816956c3SMathieu Othacehe s32 ret;
435816956c3SMathieu Othacehe
436816956c3SMathieu Othacehe ret = i2c_smbus_read_word_swapped(data->client, data_reg);
437816956c3SMathieu Othacehe if (ret < 0)
438816956c3SMathieu Othacehe return ret;
439816956c3SMathieu Othacehe
440816956c3SMathieu Othacehe *val = ret;
441816956c3SMathieu Othacehe return 0;
442816956c3SMathieu Othacehe }
443816956c3SMathieu Othacehe
vcnl4000_write_data(struct vcnl4000_data * data,u8 data_reg,int val)444816956c3SMathieu Othacehe static int vcnl4000_write_data(struct vcnl4000_data *data, u8 data_reg, int val)
445816956c3SMathieu Othacehe {
446816956c3SMathieu Othacehe if (val > U16_MAX)
447816956c3SMathieu Othacehe return -ERANGE;
448816956c3SMathieu Othacehe
449816956c3SMathieu Othacehe return i2c_smbus_write_word_swapped(data->client, data_reg, val);
450816956c3SMathieu Othacehe }
451816956c3SMathieu Othacehe
452816956c3SMathieu Othacehe
vcnl4000_measure(struct vcnl4000_data * data,u8 req_mask,u8 rdy_mask,u8 data_reg,int * val)45362a1efb9SPeter Meerwald static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
45462a1efb9SPeter Meerwald u8 rdy_mask, u8 data_reg, int *val)
45562a1efb9SPeter Meerwald {
45662a1efb9SPeter Meerwald int tries = 20;
45762a1efb9SPeter Meerwald int ret;
45862a1efb9SPeter Meerwald
459be38866fSTomas Novotny mutex_lock(&data->vcnl4000_lock);
460ff34ed6dSPeter Meerwald-Stadler
46162a1efb9SPeter Meerwald ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
46262a1efb9SPeter Meerwald req_mask);
46362a1efb9SPeter Meerwald if (ret < 0)
464ff34ed6dSPeter Meerwald-Stadler goto fail;
46562a1efb9SPeter Meerwald
46662a1efb9SPeter Meerwald /* wait for data to become ready */
46762a1efb9SPeter Meerwald while (tries--) {
46862a1efb9SPeter Meerwald ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
46962a1efb9SPeter Meerwald if (ret < 0)
470ff34ed6dSPeter Meerwald-Stadler goto fail;
47162a1efb9SPeter Meerwald if (ret & rdy_mask)
47262a1efb9SPeter Meerwald break;
47362a1efb9SPeter Meerwald msleep(20); /* measurement takes up to 100 ms */
47462a1efb9SPeter Meerwald }
47562a1efb9SPeter Meerwald
47662a1efb9SPeter Meerwald if (tries < 0) {
47762a1efb9SPeter Meerwald dev_err(&data->client->dev,
47862a1efb9SPeter Meerwald "vcnl4000_measure() failed, data not ready\n");
479ff34ed6dSPeter Meerwald-Stadler ret = -EIO;
480ff34ed6dSPeter Meerwald-Stadler goto fail;
48162a1efb9SPeter Meerwald }
48262a1efb9SPeter Meerwald
483816956c3SMathieu Othacehe ret = vcnl4000_read_data(data, data_reg, val);
48462a1efb9SPeter Meerwald if (ret < 0)
485ff34ed6dSPeter Meerwald-Stadler goto fail;
48662a1efb9SPeter Meerwald
487be38866fSTomas Novotny mutex_unlock(&data->vcnl4000_lock);
48862a1efb9SPeter Meerwald
48962a1efb9SPeter Meerwald return 0;
490ff34ed6dSPeter Meerwald-Stadler
491ff34ed6dSPeter Meerwald-Stadler fail:
492be38866fSTomas Novotny mutex_unlock(&data->vcnl4000_lock);
493ff34ed6dSPeter Meerwald-Stadler return ret;
49462a1efb9SPeter Meerwald }
49562a1efb9SPeter Meerwald
vcnl4200_measure(struct vcnl4000_data * data,struct vcnl4200_channel * chan,int * val)496be38866fSTomas Novotny static int vcnl4200_measure(struct vcnl4000_data *data,
497be38866fSTomas Novotny struct vcnl4200_channel *chan, int *val)
498be38866fSTomas Novotny {
499be38866fSTomas Novotny int ret;
500be38866fSTomas Novotny s64 delta;
501be38866fSTomas Novotny ktime_t next_measurement;
502be38866fSTomas Novotny
503be38866fSTomas Novotny mutex_lock(&chan->lock);
504be38866fSTomas Novotny
505be38866fSTomas Novotny next_measurement = ktime_add(chan->last_measurement,
506be38866fSTomas Novotny chan->sampling_rate);
507be38866fSTomas Novotny delta = ktime_us_delta(next_measurement, ktime_get());
508be38866fSTomas Novotny if (delta > 0)
509be38866fSTomas Novotny usleep_range(delta, delta + 500);
510be38866fSTomas Novotny chan->last_measurement = ktime_get();
511be38866fSTomas Novotny
512be38866fSTomas Novotny mutex_unlock(&chan->lock);
513be38866fSTomas Novotny
514be38866fSTomas Novotny ret = i2c_smbus_read_word_data(data->client, chan->reg);
515be38866fSTomas Novotny if (ret < 0)
516be38866fSTomas Novotny return ret;
517be38866fSTomas Novotny
518be38866fSTomas Novotny *val = ret;
519be38866fSTomas Novotny
520be38866fSTomas Novotny return 0;
521be38866fSTomas Novotny }
522be38866fSTomas Novotny
vcnl4000_measure_light(struct vcnl4000_data * data,int * val)5231ebc787aSTomas Novotny static int vcnl4000_measure_light(struct vcnl4000_data *data, int *val)
5241ebc787aSTomas Novotny {
5251ebc787aSTomas Novotny return vcnl4000_measure(data,
5261ebc787aSTomas Novotny VCNL4000_AL_OD, VCNL4000_AL_RDY,
5271ebc787aSTomas Novotny VCNL4000_AL_RESULT_HI, val);
5281ebc787aSTomas Novotny }
5291ebc787aSTomas Novotny
vcnl4200_measure_light(struct vcnl4000_data * data,int * val)530be38866fSTomas Novotny static int vcnl4200_measure_light(struct vcnl4000_data *data, int *val)
531be38866fSTomas Novotny {
532be38866fSTomas Novotny return vcnl4200_measure(data, &data->vcnl4200_al, val);
533be38866fSTomas Novotny }
534be38866fSTomas Novotny
vcnl4000_measure_proximity(struct vcnl4000_data * data,int * val)5351ebc787aSTomas Novotny static int vcnl4000_measure_proximity(struct vcnl4000_data *data, int *val)
5361ebc787aSTomas Novotny {
5371ebc787aSTomas Novotny return vcnl4000_measure(data,
5381ebc787aSTomas Novotny VCNL4000_PS_OD, VCNL4000_PS_RDY,
5391ebc787aSTomas Novotny VCNL4000_PS_RESULT_HI, val);
5401ebc787aSTomas Novotny }
5411ebc787aSTomas Novotny
vcnl4200_measure_proximity(struct vcnl4000_data * data,int * val)542be38866fSTomas Novotny static int vcnl4200_measure_proximity(struct vcnl4000_data *data, int *val)
543be38866fSTomas Novotny {
544be38866fSTomas Novotny return vcnl4200_measure(data, &data->vcnl4200_ps, val);
545be38866fSTomas Novotny }
546be38866fSTomas Novotny
vcnl4010_read_proxy_samp_freq(struct vcnl4000_data * data,int * val,int * val2)547f6889c1bSMathieu Othacehe static int vcnl4010_read_proxy_samp_freq(struct vcnl4000_data *data, int *val,
548f6889c1bSMathieu Othacehe int *val2)
549f6889c1bSMathieu Othacehe {
550f6889c1bSMathieu Othacehe int ret;
551f6889c1bSMathieu Othacehe
552f6889c1bSMathieu Othacehe ret = i2c_smbus_read_byte_data(data->client, VCNL4010_PROX_RATE);
553f6889c1bSMathieu Othacehe if (ret < 0)
554f6889c1bSMathieu Othacehe return ret;
555f6889c1bSMathieu Othacehe
556f6889c1bSMathieu Othacehe if (ret >= ARRAY_SIZE(vcnl4010_prox_sampling_frequency))
557f6889c1bSMathieu Othacehe return -EINVAL;
558f6889c1bSMathieu Othacehe
559f6889c1bSMathieu Othacehe *val = vcnl4010_prox_sampling_frequency[ret][0];
560f6889c1bSMathieu Othacehe *val2 = vcnl4010_prox_sampling_frequency[ret][1];
561f6889c1bSMathieu Othacehe
562f6889c1bSMathieu Othacehe return 0;
563f6889c1bSMathieu Othacehe }
564f6889c1bSMathieu Othacehe
vcnl4010_is_in_periodic_mode(struct vcnl4000_data * data)565d35567fcSMathieu Othacehe static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data)
566f5a98e1fSGuido Günther {
567d35567fcSMathieu Othacehe int ret;
568f5a98e1fSGuido Günther
569d35567fcSMathieu Othacehe ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
570d35567fcSMathieu Othacehe if (ret < 0)
571d35567fcSMathieu Othacehe return false;
572d35567fcSMathieu Othacehe
573d35567fcSMathieu Othacehe return !!(ret & VCNL4000_SELF_TIMED_EN);
574f5a98e1fSGuido Günther }
575f5a98e1fSGuido Günther
vcnl4000_set_pm_runtime_state(struct vcnl4000_data * data,bool on)5765e00708dSGuido Günther static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
5775e00708dSGuido Günther {
5785e00708dSGuido Günther struct device *dev = &data->client->dev;
5795e00708dSGuido Günther int ret;
5805e00708dSGuido Günther
5815e00708dSGuido Günther if (on) {
582db27fdb3SJonathan Cameron ret = pm_runtime_resume_and_get(dev);
5835e00708dSGuido Günther } else {
5845e00708dSGuido Günther pm_runtime_mark_last_busy(dev);
5855e00708dSGuido Günther ret = pm_runtime_put_autosuspend(dev);
5865e00708dSGuido Günther }
5875e00708dSGuido Günther
5885e00708dSGuido Günther return ret;
5895e00708dSGuido Günther }
5905e00708dSGuido Günther
vcnl4040_read_als_it(struct vcnl4000_data * data,int * val,int * val2)591fea2c97dSAstrid Rost static int vcnl4040_read_als_it(struct vcnl4000_data *data, int *val, int *val2)
592fea2c97dSAstrid Rost {
593fea2c97dSAstrid Rost int ret;
594fea2c97dSAstrid Rost
595fea2c97dSAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
596fea2c97dSAstrid Rost if (ret < 0)
597fea2c97dSAstrid Rost return ret;
598fea2c97dSAstrid Rost
599fea2c97dSAstrid Rost ret = FIELD_GET(VCNL4040_ALS_CONF_IT, ret);
600fea2c97dSAstrid Rost if (ret >= data->chip_spec->num_als_it_times)
601fea2c97dSAstrid Rost return -EINVAL;
602fea2c97dSAstrid Rost
603fea2c97dSAstrid Rost *val = (*data->chip_spec->als_it_times)[ret][0];
604fea2c97dSAstrid Rost *val2 = (*data->chip_spec->als_it_times)[ret][1];
605fea2c97dSAstrid Rost
606fea2c97dSAstrid Rost return 0;
607fea2c97dSAstrid Rost }
608fea2c97dSAstrid Rost
vcnl4040_write_als_it(struct vcnl4000_data * data,int val)609fea2c97dSAstrid Rost static ssize_t vcnl4040_write_als_it(struct vcnl4000_data *data, int val)
610fea2c97dSAstrid Rost {
611fea2c97dSAstrid Rost unsigned int i;
612fea2c97dSAstrid Rost int ret;
613fea2c97dSAstrid Rost u16 regval;
614fea2c97dSAstrid Rost
615fea2c97dSAstrid Rost for (i = 0; i < data->chip_spec->num_als_it_times; i++) {
616fea2c97dSAstrid Rost if (val == (*data->chip_spec->als_it_times)[i][1])
617fea2c97dSAstrid Rost break;
618fea2c97dSAstrid Rost }
619fea2c97dSAstrid Rost
620fea2c97dSAstrid Rost if (i == data->chip_spec->num_als_it_times)
621fea2c97dSAstrid Rost return -EINVAL;
622fea2c97dSAstrid Rost
623fea2c97dSAstrid Rost data->vcnl4200_al.sampling_rate = ktime_set(0, val * 1200);
624fea2c97dSAstrid Rost data->al_scale = div_u64(mul_u32_u32(data->chip_spec->ulux_step,
625fea2c97dSAstrid Rost (*data->chip_spec->als_it_times)[0][1]),
626fea2c97dSAstrid Rost val);
627fea2c97dSAstrid Rost
628fea2c97dSAstrid Rost mutex_lock(&data->vcnl4000_lock);
629fea2c97dSAstrid Rost
630fea2c97dSAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
631fea2c97dSAstrid Rost if (ret < 0)
632fea2c97dSAstrid Rost goto out_unlock;
633fea2c97dSAstrid Rost
634fea2c97dSAstrid Rost regval = FIELD_PREP(VCNL4040_ALS_CONF_IT, i);
635fea2c97dSAstrid Rost regval |= (ret & ~VCNL4040_ALS_CONF_IT);
636fea2c97dSAstrid Rost ret = i2c_smbus_write_word_data(data->client,
637fea2c97dSAstrid Rost VCNL4200_AL_CONF,
638fea2c97dSAstrid Rost regval);
639fea2c97dSAstrid Rost
640fea2c97dSAstrid Rost out_unlock:
641fea2c97dSAstrid Rost mutex_unlock(&data->vcnl4000_lock);
642fea2c97dSAstrid Rost return ret;
643fea2c97dSAstrid Rost }
644fea2c97dSAstrid Rost
vcnl4040_read_ps_it(struct vcnl4000_data * data,int * val,int * val2)64585e2c6a2SMårten Lindahl static int vcnl4040_read_ps_it(struct vcnl4000_data *data, int *val, int *val2)
64685e2c6a2SMårten Lindahl {
64785e2c6a2SMårten Lindahl int ret;
64885e2c6a2SMårten Lindahl
64985e2c6a2SMårten Lindahl ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
65085e2c6a2SMårten Lindahl if (ret < 0)
65185e2c6a2SMårten Lindahl return ret;
65285e2c6a2SMårten Lindahl
65385e2c6a2SMårten Lindahl ret = FIELD_GET(VCNL4040_PS_CONF2_PS_IT, ret);
65485e2c6a2SMårten Lindahl
655e55c96daSAstrid Rost if (ret >= data->chip_spec->num_ps_it_times)
65685e2c6a2SMårten Lindahl return -EINVAL;
65785e2c6a2SMårten Lindahl
658e55c96daSAstrid Rost *val = (*data->chip_spec->ps_it_times)[ret][0];
659e55c96daSAstrid Rost *val2 = (*data->chip_spec->ps_it_times)[ret][1];
66085e2c6a2SMårten Lindahl
66185e2c6a2SMårten Lindahl return 0;
66285e2c6a2SMårten Lindahl }
66385e2c6a2SMårten Lindahl
vcnl4040_write_ps_it(struct vcnl4000_data * data,int val)66485e2c6a2SMårten Lindahl static ssize_t vcnl4040_write_ps_it(struct vcnl4000_data *data, int val)
66585e2c6a2SMårten Lindahl {
66685e2c6a2SMårten Lindahl unsigned int i;
66785e2c6a2SMårten Lindahl int ret, index = -1;
66885e2c6a2SMårten Lindahl u16 regval;
66985e2c6a2SMårten Lindahl
670e55c96daSAstrid Rost for (i = 0; i < data->chip_spec->num_ps_it_times; i++) {
671e55c96daSAstrid Rost if (val == (*data->chip_spec->ps_it_times)[i][1]) {
67285e2c6a2SMårten Lindahl index = i;
67385e2c6a2SMårten Lindahl break;
67485e2c6a2SMårten Lindahl }
67585e2c6a2SMårten Lindahl }
67685e2c6a2SMårten Lindahl
67785e2c6a2SMårten Lindahl if (index < 0)
67885e2c6a2SMårten Lindahl return -EINVAL;
67985e2c6a2SMårten Lindahl
680e55c96daSAstrid Rost data->vcnl4200_ps.sampling_rate = ktime_set(0, val * 60 * NSEC_PER_USEC);
681e55c96daSAstrid Rost
68285e2c6a2SMårten Lindahl mutex_lock(&data->vcnl4000_lock);
68385e2c6a2SMårten Lindahl
68485e2c6a2SMårten Lindahl ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
68585e2c6a2SMårten Lindahl if (ret < 0)
68685e2c6a2SMårten Lindahl goto out;
68785e2c6a2SMårten Lindahl
68885e2c6a2SMårten Lindahl regval = (ret & ~VCNL4040_PS_CONF2_PS_IT) |
68985e2c6a2SMårten Lindahl FIELD_PREP(VCNL4040_PS_CONF2_PS_IT, index);
69085e2c6a2SMårten Lindahl ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
69185e2c6a2SMårten Lindahl regval);
69285e2c6a2SMårten Lindahl
69385e2c6a2SMårten Lindahl out:
69485e2c6a2SMårten Lindahl mutex_unlock(&data->vcnl4000_lock);
69585e2c6a2SMårten Lindahl return ret;
69685e2c6a2SMårten Lindahl }
69785e2c6a2SMårten Lindahl
vcnl4040_read_als_period(struct vcnl4000_data * data,int * val,int * val2)6987f865127SAstrid Rost static ssize_t vcnl4040_read_als_period(struct vcnl4000_data *data, int *val, int *val2)
6997f865127SAstrid Rost {
7007f865127SAstrid Rost int ret, ret_pers, it;
7017f865127SAstrid Rost int64_t val_c;
7027f865127SAstrid Rost
7037f865127SAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
7047f865127SAstrid Rost if (ret < 0)
7057f865127SAstrid Rost return ret;
7067f865127SAstrid Rost
7077f865127SAstrid Rost ret_pers = FIELD_GET(VCNL4040_ALS_CONF_PERS, ret);
7087f865127SAstrid Rost if (ret_pers >= ARRAY_SIZE(vcnl4040_als_persistence))
7097f865127SAstrid Rost return -EINVAL;
7107f865127SAstrid Rost
7117f865127SAstrid Rost it = FIELD_GET(VCNL4040_ALS_CONF_IT, ret);
7127f865127SAstrid Rost if (it >= data->chip_spec->num_als_it_times)
7137f865127SAstrid Rost return -EINVAL;
7147f865127SAstrid Rost
7157f865127SAstrid Rost val_c = mul_u32_u32((*data->chip_spec->als_it_times)[it][1],
7167f865127SAstrid Rost vcnl4040_als_persistence[ret_pers]);
7177f865127SAstrid Rost *val = div_u64_rem(val_c, MICRO, val2);
7187f865127SAstrid Rost
7197f865127SAstrid Rost return IIO_VAL_INT_PLUS_MICRO;
7207f865127SAstrid Rost }
7217f865127SAstrid Rost
vcnl4040_write_als_period(struct vcnl4000_data * data,int val,int val2)7227f865127SAstrid Rost static ssize_t vcnl4040_write_als_period(struct vcnl4000_data *data, int val, int val2)
7237f865127SAstrid Rost {
7247f865127SAstrid Rost unsigned int i;
7257f865127SAstrid Rost int ret, it;
7267f865127SAstrid Rost u16 regval;
7277f865127SAstrid Rost u64 val_n = mul_u32_u32(val, MICRO) + val2;
7287f865127SAstrid Rost
7297f865127SAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
7307f865127SAstrid Rost if (ret < 0)
7317f865127SAstrid Rost return ret;
7327f865127SAstrid Rost
7337f865127SAstrid Rost it = FIELD_GET(VCNL4040_ALS_CONF_IT, ret);
7347f865127SAstrid Rost if (it >= data->chip_spec->num_als_it_times)
7357f865127SAstrid Rost return -EINVAL;
7367f865127SAstrid Rost
7377f865127SAstrid Rost for (i = 0; i < ARRAY_SIZE(vcnl4040_als_persistence) - 1; i++) {
7387f865127SAstrid Rost if (val_n < mul_u32_u32(vcnl4040_als_persistence[i],
7397f865127SAstrid Rost (*data->chip_spec->als_it_times)[it][1]))
7407f865127SAstrid Rost break;
7417f865127SAstrid Rost }
7427f865127SAstrid Rost
7437f865127SAstrid Rost mutex_lock(&data->vcnl4000_lock);
7447f865127SAstrid Rost
7457f865127SAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
7467f865127SAstrid Rost if (ret < 0)
7477f865127SAstrid Rost goto out_unlock;
7487f865127SAstrid Rost
7497f865127SAstrid Rost regval = FIELD_PREP(VCNL4040_ALS_CONF_PERS, i);
7507f865127SAstrid Rost regval |= (ret & ~VCNL4040_ALS_CONF_PERS);
7517f865127SAstrid Rost ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF,
7527f865127SAstrid Rost regval);
7537f865127SAstrid Rost
7547f865127SAstrid Rost out_unlock:
7557f865127SAstrid Rost mutex_unlock(&data->vcnl4000_lock);
7567f865127SAstrid Rost return ret;
7577f865127SAstrid Rost }
7587f865127SAstrid Rost
vcnl4040_read_ps_period(struct vcnl4000_data * data,int * val,int * val2)7597f865127SAstrid Rost static ssize_t vcnl4040_read_ps_period(struct vcnl4000_data *data, int *val, int *val2)
7607f865127SAstrid Rost {
7617f865127SAstrid Rost int ret, ret_pers, it;
7627f865127SAstrid Rost
7637f865127SAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
7647f865127SAstrid Rost if (ret < 0)
7657f865127SAstrid Rost return ret;
7667f865127SAstrid Rost
7677f865127SAstrid Rost ret_pers = FIELD_GET(VCNL4040_CONF1_PS_PERS, ret);
7687f865127SAstrid Rost if (ret_pers >= ARRAY_SIZE(vcnl4040_ps_persistence))
7697f865127SAstrid Rost return -EINVAL;
7707f865127SAstrid Rost
7717f865127SAstrid Rost it = FIELD_GET(VCNL4040_PS_CONF2_PS_IT, ret);
7727f865127SAstrid Rost if (it >= data->chip_spec->num_ps_it_times)
7737f865127SAstrid Rost return -EINVAL;
7747f865127SAstrid Rost
7757f865127SAstrid Rost *val = (*data->chip_spec->ps_it_times)[it][0];
7767f865127SAstrid Rost *val2 = (*data->chip_spec->ps_it_times)[it][1] *
7777f865127SAstrid Rost vcnl4040_ps_persistence[ret_pers];
7787f865127SAstrid Rost
7797f865127SAstrid Rost return IIO_VAL_INT_PLUS_MICRO;
7807f865127SAstrid Rost }
7817f865127SAstrid Rost
vcnl4040_write_ps_period(struct vcnl4000_data * data,int val,int val2)7827f865127SAstrid Rost static ssize_t vcnl4040_write_ps_period(struct vcnl4000_data *data, int val, int val2)
7837f865127SAstrid Rost {
7847f865127SAstrid Rost int ret, it, i;
7857f865127SAstrid Rost u16 regval;
7867f865127SAstrid Rost
7877f865127SAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
7887f865127SAstrid Rost if (ret < 0)
7897f865127SAstrid Rost return ret;
7907f865127SAstrid Rost
7917f865127SAstrid Rost it = FIELD_GET(VCNL4040_PS_CONF2_PS_IT, ret);
7927f865127SAstrid Rost if (it >= data->chip_spec->num_ps_it_times)
7937f865127SAstrid Rost return -EINVAL;
7947f865127SAstrid Rost
7957f865127SAstrid Rost if (val > 0)
7967f865127SAstrid Rost i = ARRAY_SIZE(vcnl4040_ps_persistence) - 1;
7977f865127SAstrid Rost else {
7987f865127SAstrid Rost for (i = 0; i < ARRAY_SIZE(vcnl4040_ps_persistence) - 1; i++) {
7997f865127SAstrid Rost if (val2 <= vcnl4040_ps_persistence[i] *
8007f865127SAstrid Rost (*data->chip_spec->ps_it_times)[it][1])
8017f865127SAstrid Rost break;
8027f865127SAstrid Rost }
8037f865127SAstrid Rost }
8047f865127SAstrid Rost
8057f865127SAstrid Rost mutex_lock(&data->vcnl4000_lock);
8067f865127SAstrid Rost
8077f865127SAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
8087f865127SAstrid Rost if (ret < 0)
8097f865127SAstrid Rost goto out_unlock;
8107f865127SAstrid Rost
8117f865127SAstrid Rost regval = FIELD_PREP(VCNL4040_CONF1_PS_PERS, i);
8127f865127SAstrid Rost regval |= (ret & ~VCNL4040_CONF1_PS_PERS);
8137f865127SAstrid Rost ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
8147f865127SAstrid Rost regval);
8157f865127SAstrid Rost
8167f865127SAstrid Rost out_unlock:
8177f865127SAstrid Rost mutex_unlock(&data->vcnl4000_lock);
8187f865127SAstrid Rost return ret;
8197f865127SAstrid Rost }
8207f865127SAstrid Rost
vcnl4040_read_ps_oversampling_ratio(struct vcnl4000_data * data,int * val)821add98466SAstrid Rost static ssize_t vcnl4040_read_ps_oversampling_ratio(struct vcnl4000_data *data, int *val)
822add98466SAstrid Rost {
823add98466SAstrid Rost int ret;
824add98466SAstrid Rost
825add98466SAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
826add98466SAstrid Rost if (ret < 0)
827add98466SAstrid Rost return ret;
828add98466SAstrid Rost
829add98466SAstrid Rost ret = FIELD_GET(VCNL4040_PS_CONF3_MPS, ret);
830add98466SAstrid Rost if (ret >= ARRAY_SIZE(vcnl4040_ps_oversampling_ratio))
831add98466SAstrid Rost return -EINVAL;
832add98466SAstrid Rost
833add98466SAstrid Rost *val = vcnl4040_ps_oversampling_ratio[ret];
834add98466SAstrid Rost
835add98466SAstrid Rost return ret;
836add98466SAstrid Rost }
837add98466SAstrid Rost
vcnl4040_write_ps_oversampling_ratio(struct vcnl4000_data * data,int val)838add98466SAstrid Rost static ssize_t vcnl4040_write_ps_oversampling_ratio(struct vcnl4000_data *data, int val)
839add98466SAstrid Rost {
840add98466SAstrid Rost unsigned int i;
841add98466SAstrid Rost int ret;
842add98466SAstrid Rost u16 regval;
843add98466SAstrid Rost
844add98466SAstrid Rost for (i = 0; i < ARRAY_SIZE(vcnl4040_ps_oversampling_ratio); i++) {
845add98466SAstrid Rost if (val == vcnl4040_ps_oversampling_ratio[i])
846add98466SAstrid Rost break;
847add98466SAstrid Rost }
848add98466SAstrid Rost
849add98466SAstrid Rost if (i >= ARRAY_SIZE(vcnl4040_ps_oversampling_ratio))
850add98466SAstrid Rost return -EINVAL;
851add98466SAstrid Rost
852add98466SAstrid Rost mutex_lock(&data->vcnl4000_lock);
853add98466SAstrid Rost
854add98466SAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
855add98466SAstrid Rost if (ret < 0)
856add98466SAstrid Rost goto out_unlock;
857add98466SAstrid Rost
858add98466SAstrid Rost regval = FIELD_PREP(VCNL4040_PS_CONF3_MPS, i);
859add98466SAstrid Rost regval |= (ret & ~VCNL4040_PS_CONF3_MPS);
860add98466SAstrid Rost ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,
861add98466SAstrid Rost regval);
862add98466SAstrid Rost
863add98466SAstrid Rost out_unlock:
864add98466SAstrid Rost mutex_unlock(&data->vcnl4000_lock);
865add98466SAstrid Rost return ret;
866add98466SAstrid Rost }
867add98466SAstrid Rost
vcnl4040_read_ps_calibbias(struct vcnl4000_data * data,int * val,int * val2)868bb33e751SAstrid Rost static ssize_t vcnl4040_read_ps_calibbias(struct vcnl4000_data *data, int *val, int *val2)
869bb33e751SAstrid Rost {
870bb33e751SAstrid Rost int ret;
871bb33e751SAstrid Rost
872bb33e751SAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
873bb33e751SAstrid Rost if (ret < 0)
874bb33e751SAstrid Rost return ret;
875bb33e751SAstrid Rost
876bb33e751SAstrid Rost ret = FIELD_GET(VCNL4040_PS_MS_LED_I, ret);
877bb33e751SAstrid Rost if (ret >= ARRAY_SIZE(vcnl4040_ps_calibbias_ua))
878bb33e751SAstrid Rost return -EINVAL;
879bb33e751SAstrid Rost
880bb33e751SAstrid Rost *val = vcnl4040_ps_calibbias_ua[ret][0];
881bb33e751SAstrid Rost *val2 = vcnl4040_ps_calibbias_ua[ret][1];
882bb33e751SAstrid Rost
883bb33e751SAstrid Rost return ret;
884bb33e751SAstrid Rost }
885bb33e751SAstrid Rost
vcnl4040_write_ps_calibbias(struct vcnl4000_data * data,int val)886bb33e751SAstrid Rost static ssize_t vcnl4040_write_ps_calibbias(struct vcnl4000_data *data, int val)
887bb33e751SAstrid Rost {
888bb33e751SAstrid Rost unsigned int i;
889bb33e751SAstrid Rost int ret;
890bb33e751SAstrid Rost u16 regval;
891bb33e751SAstrid Rost
892bb33e751SAstrid Rost for (i = 0; i < ARRAY_SIZE(vcnl4040_ps_calibbias_ua); i++) {
893bb33e751SAstrid Rost if (val == vcnl4040_ps_calibbias_ua[i][1])
894bb33e751SAstrid Rost break;
895bb33e751SAstrid Rost }
896bb33e751SAstrid Rost
897bb33e751SAstrid Rost if (i >= ARRAY_SIZE(vcnl4040_ps_calibbias_ua))
898bb33e751SAstrid Rost return -EINVAL;
899bb33e751SAstrid Rost
900bb33e751SAstrid Rost mutex_lock(&data->vcnl4000_lock);
901bb33e751SAstrid Rost
902bb33e751SAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
903bb33e751SAstrid Rost if (ret < 0)
904bb33e751SAstrid Rost goto out_unlock;
905bb33e751SAstrid Rost
906bb33e751SAstrid Rost regval = (ret & ~VCNL4040_PS_MS_LED_I);
907bb33e751SAstrid Rost regval |= FIELD_PREP(VCNL4040_PS_MS_LED_I, i);
908bb33e751SAstrid Rost ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,
909bb33e751SAstrid Rost regval);
910bb33e751SAstrid Rost
911bb33e751SAstrid Rost out_unlock:
912bb33e751SAstrid Rost mutex_unlock(&data->vcnl4000_lock);
913bb33e751SAstrid Rost return ret;
914bb33e751SAstrid Rost }
915bb33e751SAstrid Rost
vcnl4000_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)91662a1efb9SPeter Meerwald static int vcnl4000_read_raw(struct iio_dev *indio_dev,
91762a1efb9SPeter Meerwald struct iio_chan_spec const *chan,
91862a1efb9SPeter Meerwald int *val, int *val2, long mask)
91962a1efb9SPeter Meerwald {
9205d693139SPeter Meerwald-Stadler int ret;
92162a1efb9SPeter Meerwald struct vcnl4000_data *data = iio_priv(indio_dev);
92262a1efb9SPeter Meerwald
92362a1efb9SPeter Meerwald switch (mask) {
92462a1efb9SPeter Meerwald case IIO_CHAN_INFO_RAW:
9255e00708dSGuido Günther ret = vcnl4000_set_pm_runtime_state(data, true);
9265e00708dSGuido Günther if (ret < 0)
9275e00708dSGuido Günther return ret;
9285e00708dSGuido Günther
92962a1efb9SPeter Meerwald switch (chan->type) {
93062a1efb9SPeter Meerwald case IIO_LIGHT:
9311ebc787aSTomas Novotny ret = data->chip_spec->measure_light(data, val);
9324a818643SGuido Günther if (!ret)
9334a818643SGuido Günther ret = IIO_VAL_INT;
9344a818643SGuido Günther break;
93562a1efb9SPeter Meerwald case IIO_PROXIMITY:
9361ebc787aSTomas Novotny ret = data->chip_spec->measure_proximity(data, val);
937*44b90383SMårten Lindahl *val2 = data->ps_scale;
9384a818643SGuido Günther if (!ret)
939*44b90383SMårten Lindahl ret = IIO_VAL_FRACTIONAL;
9404a818643SGuido Günther break;
94162a1efb9SPeter Meerwald default:
9424a818643SGuido Günther ret = -EINVAL;
94362a1efb9SPeter Meerwald }
9445e00708dSGuido Günther vcnl4000_set_pm_runtime_state(data, false);
9454a818643SGuido Günther return ret;
94662a1efb9SPeter Meerwald case IIO_CHAN_INFO_SCALE:
9475d693139SPeter Meerwald-Stadler if (chan->type != IIO_LIGHT)
9485d693139SPeter Meerwald-Stadler return -EINVAL;
9495d693139SPeter Meerwald-Stadler
95062a1efb9SPeter Meerwald *val = 0;
9511ebc787aSTomas Novotny *val2 = data->al_scale;
9525d693139SPeter Meerwald-Stadler return IIO_VAL_INT_PLUS_MICRO;
95385e2c6a2SMårten Lindahl case IIO_CHAN_INFO_INT_TIME:
9542be17b68SAstrid Rost switch (chan->type) {
955fea2c97dSAstrid Rost case IIO_LIGHT:
956fea2c97dSAstrid Rost ret = vcnl4040_read_als_it(data, val, val2);
957fea2c97dSAstrid Rost break;
9582be17b68SAstrid Rost case IIO_PROXIMITY:
95985e2c6a2SMårten Lindahl ret = vcnl4040_read_ps_it(data, val, val2);
9602be17b68SAstrid Rost break;
9612be17b68SAstrid Rost default:
9622be17b68SAstrid Rost return -EINVAL;
9632be17b68SAstrid Rost }
96485e2c6a2SMårten Lindahl if (ret < 0)
96585e2c6a2SMårten Lindahl return ret;
96685e2c6a2SMårten Lindahl return IIO_VAL_INT_PLUS_MICRO;
967add98466SAstrid Rost case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
968add98466SAstrid Rost switch (chan->type) {
969add98466SAstrid Rost case IIO_PROXIMITY:
970add98466SAstrid Rost ret = vcnl4040_read_ps_oversampling_ratio(data, val);
971add98466SAstrid Rost if (ret < 0)
972add98466SAstrid Rost return ret;
973add98466SAstrid Rost return IIO_VAL_INT;
974add98466SAstrid Rost default:
975add98466SAstrid Rost return -EINVAL;
976add98466SAstrid Rost }
977bb33e751SAstrid Rost case IIO_CHAN_INFO_CALIBBIAS:
978bb33e751SAstrid Rost switch (chan->type) {
979bb33e751SAstrid Rost case IIO_PROXIMITY:
980bb33e751SAstrid Rost ret = vcnl4040_read_ps_calibbias(data, val, val2);
981bb33e751SAstrid Rost if (ret < 0)
982bb33e751SAstrid Rost return ret;
983bb33e751SAstrid Rost return IIO_VAL_INT_PLUS_MICRO;
984bb33e751SAstrid Rost default:
985bb33e751SAstrid Rost return -EINVAL;
986bb33e751SAstrid Rost }
98785e2c6a2SMårten Lindahl default:
98885e2c6a2SMårten Lindahl return -EINVAL;
98985e2c6a2SMårten Lindahl }
99085e2c6a2SMårten Lindahl }
99185e2c6a2SMårten Lindahl
vcnl4040_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)99285e2c6a2SMårten Lindahl static int vcnl4040_write_raw(struct iio_dev *indio_dev,
99385e2c6a2SMårten Lindahl struct iio_chan_spec const *chan,
99485e2c6a2SMårten Lindahl int val, int val2, long mask)
99585e2c6a2SMårten Lindahl {
99685e2c6a2SMårten Lindahl struct vcnl4000_data *data = iio_priv(indio_dev);
99785e2c6a2SMårten Lindahl
99885e2c6a2SMårten Lindahl switch (mask) {
99985e2c6a2SMårten Lindahl case IIO_CHAN_INFO_INT_TIME:
100085e2c6a2SMårten Lindahl if (val != 0)
100185e2c6a2SMårten Lindahl return -EINVAL;
10022be17b68SAstrid Rost switch (chan->type) {
1003fea2c97dSAstrid Rost case IIO_LIGHT:
1004fea2c97dSAstrid Rost return vcnl4040_write_als_it(data, val2);
10052be17b68SAstrid Rost case IIO_PROXIMITY:
100685e2c6a2SMårten Lindahl return vcnl4040_write_ps_it(data, val2);
100785e2c6a2SMårten Lindahl default:
100885e2c6a2SMårten Lindahl return -EINVAL;
100985e2c6a2SMårten Lindahl }
1010add98466SAstrid Rost case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
1011add98466SAstrid Rost switch (chan->type) {
1012add98466SAstrid Rost case IIO_PROXIMITY:
1013add98466SAstrid Rost return vcnl4040_write_ps_oversampling_ratio(data, val);
1014add98466SAstrid Rost default:
1015add98466SAstrid Rost return -EINVAL;
1016add98466SAstrid Rost }
1017bb33e751SAstrid Rost case IIO_CHAN_INFO_CALIBBIAS:
1018bb33e751SAstrid Rost switch (chan->type) {
1019bb33e751SAstrid Rost case IIO_PROXIMITY:
1020bb33e751SAstrid Rost return vcnl4040_write_ps_calibbias(data, val2);
1021bb33e751SAstrid Rost default:
1022bb33e751SAstrid Rost return -EINVAL;
1023bb33e751SAstrid Rost }
10242be17b68SAstrid Rost default:
10252be17b68SAstrid Rost return -EINVAL;
10262be17b68SAstrid Rost }
102785e2c6a2SMårten Lindahl }
102885e2c6a2SMårten Lindahl
vcnl4040_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)102985e2c6a2SMårten Lindahl static int vcnl4040_read_avail(struct iio_dev *indio_dev,
103085e2c6a2SMårten Lindahl struct iio_chan_spec const *chan,
103185e2c6a2SMårten Lindahl const int **vals, int *type, int *length,
103285e2c6a2SMårten Lindahl long mask)
103385e2c6a2SMårten Lindahl {
1034e55c96daSAstrid Rost struct vcnl4000_data *data = iio_priv(indio_dev);
1035e55c96daSAstrid Rost
103685e2c6a2SMårten Lindahl switch (mask) {
103785e2c6a2SMårten Lindahl case IIO_CHAN_INFO_INT_TIME:
10382be17b68SAstrid Rost switch (chan->type) {
1039fea2c97dSAstrid Rost case IIO_LIGHT:
1040fea2c97dSAstrid Rost *vals = (int *)(*data->chip_spec->als_it_times);
1041fea2c97dSAstrid Rost *length = 2 * data->chip_spec->num_als_it_times;
1042fea2c97dSAstrid Rost break;
10432be17b68SAstrid Rost case IIO_PROXIMITY:
1044e55c96daSAstrid Rost *vals = (int *)(*data->chip_spec->ps_it_times);
1045e55c96daSAstrid Rost *length = 2 * data->chip_spec->num_ps_it_times;
10462be17b68SAstrid Rost break;
10472be17b68SAstrid Rost default:
10482be17b68SAstrid Rost return -EINVAL;
10492be17b68SAstrid Rost }
10502be17b68SAstrid Rost *type = IIO_VAL_INT_PLUS_MICRO;
105185e2c6a2SMårten Lindahl return IIO_AVAIL_LIST;
1052add98466SAstrid Rost case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
1053add98466SAstrid Rost switch (chan->type) {
1054add98466SAstrid Rost case IIO_PROXIMITY:
1055add98466SAstrid Rost *vals = (int *)vcnl4040_ps_oversampling_ratio;
1056add98466SAstrid Rost *length = ARRAY_SIZE(vcnl4040_ps_oversampling_ratio);
1057add98466SAstrid Rost *type = IIO_VAL_INT;
1058add98466SAstrid Rost return IIO_AVAIL_LIST;
1059add98466SAstrid Rost default:
1060add98466SAstrid Rost return -EINVAL;
1061add98466SAstrid Rost }
1062bb33e751SAstrid Rost case IIO_CHAN_INFO_CALIBBIAS:
1063bb33e751SAstrid Rost switch (chan->type) {
1064bb33e751SAstrid Rost case IIO_PROXIMITY:
1065bb33e751SAstrid Rost *vals = (int *)vcnl4040_ps_calibbias_ua;
1066bb33e751SAstrid Rost *length = 2 * ARRAY_SIZE(vcnl4040_ps_calibbias_ua);
1067bb33e751SAstrid Rost *type = IIO_VAL_INT_PLUS_MICRO;
1068bb33e751SAstrid Rost return IIO_AVAIL_LIST;
1069bb33e751SAstrid Rost default:
1070bb33e751SAstrid Rost return -EINVAL;
1071bb33e751SAstrid Rost }
107262a1efb9SPeter Meerwald default:
10735d693139SPeter Meerwald-Stadler return -EINVAL;
107462a1efb9SPeter Meerwald }
107562a1efb9SPeter Meerwald }
107662a1efb9SPeter Meerwald
vcnl4010_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)1077d35567fcSMathieu Othacehe static int vcnl4010_read_raw(struct iio_dev *indio_dev,
1078d35567fcSMathieu Othacehe struct iio_chan_spec const *chan,
1079d35567fcSMathieu Othacehe int *val, int *val2, long mask)
1080d35567fcSMathieu Othacehe {
1081d35567fcSMathieu Othacehe int ret;
1082d35567fcSMathieu Othacehe struct vcnl4000_data *data = iio_priv(indio_dev);
1083d35567fcSMathieu Othacehe
1084d35567fcSMathieu Othacehe switch (mask) {
1085d35567fcSMathieu Othacehe case IIO_CHAN_INFO_RAW:
1086d35567fcSMathieu Othacehe case IIO_CHAN_INFO_SCALE:
1087d35567fcSMathieu Othacehe ret = iio_device_claim_direct_mode(indio_dev);
1088d35567fcSMathieu Othacehe if (ret)
1089d35567fcSMathieu Othacehe return ret;
1090d35567fcSMathieu Othacehe
1091d35567fcSMathieu Othacehe /* Protect against event capture. */
1092d35567fcSMathieu Othacehe if (vcnl4010_is_in_periodic_mode(data)) {
1093d35567fcSMathieu Othacehe ret = -EBUSY;
1094d35567fcSMathieu Othacehe } else {
1095d35567fcSMathieu Othacehe ret = vcnl4000_read_raw(indio_dev, chan, val, val2,
1096d35567fcSMathieu Othacehe mask);
1097d35567fcSMathieu Othacehe }
1098d35567fcSMathieu Othacehe
1099d35567fcSMathieu Othacehe iio_device_release_direct_mode(indio_dev);
1100d35567fcSMathieu Othacehe return ret;
1101f6889c1bSMathieu Othacehe case IIO_CHAN_INFO_SAMP_FREQ:
1102f6889c1bSMathieu Othacehe switch (chan->type) {
1103f6889c1bSMathieu Othacehe case IIO_PROXIMITY:
1104f6889c1bSMathieu Othacehe ret = vcnl4010_read_proxy_samp_freq(data, val, val2);
1105f6889c1bSMathieu Othacehe if (ret < 0)
1106f6889c1bSMathieu Othacehe return ret;
1107f6889c1bSMathieu Othacehe return IIO_VAL_INT_PLUS_MICRO;
1108d35567fcSMathieu Othacehe default:
1109d35567fcSMathieu Othacehe return -EINVAL;
1110d35567fcSMathieu Othacehe }
1111f6889c1bSMathieu Othacehe default:
1112f6889c1bSMathieu Othacehe return -EINVAL;
1113f6889c1bSMathieu Othacehe }
1114f6889c1bSMathieu Othacehe }
1115f6889c1bSMathieu Othacehe
vcnl4010_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)1116f6889c1bSMathieu Othacehe static int vcnl4010_read_avail(struct iio_dev *indio_dev,
1117f6889c1bSMathieu Othacehe struct iio_chan_spec const *chan,
1118f6889c1bSMathieu Othacehe const int **vals, int *type, int *length,
1119f6889c1bSMathieu Othacehe long mask)
1120f6889c1bSMathieu Othacehe {
1121f6889c1bSMathieu Othacehe switch (mask) {
1122f6889c1bSMathieu Othacehe case IIO_CHAN_INFO_SAMP_FREQ:
1123f6889c1bSMathieu Othacehe *vals = (int *)vcnl4010_prox_sampling_frequency;
1124f6889c1bSMathieu Othacehe *type = IIO_VAL_INT_PLUS_MICRO;
1125f6889c1bSMathieu Othacehe *length = 2 * ARRAY_SIZE(vcnl4010_prox_sampling_frequency);
1126f6889c1bSMathieu Othacehe return IIO_AVAIL_LIST;
1127f6889c1bSMathieu Othacehe default:
1128f6889c1bSMathieu Othacehe return -EINVAL;
1129f6889c1bSMathieu Othacehe }
1130f6889c1bSMathieu Othacehe }
1131f6889c1bSMathieu Othacehe
vcnl4010_write_proxy_samp_freq(struct vcnl4000_data * data,int val,int val2)1132f6889c1bSMathieu Othacehe static int vcnl4010_write_proxy_samp_freq(struct vcnl4000_data *data, int val,
1133f6889c1bSMathieu Othacehe int val2)
1134f6889c1bSMathieu Othacehe {
1135f6889c1bSMathieu Othacehe unsigned int i;
1136f6889c1bSMathieu Othacehe int index = -1;
1137f6889c1bSMathieu Othacehe
1138f6889c1bSMathieu Othacehe for (i = 0; i < ARRAY_SIZE(vcnl4010_prox_sampling_frequency); i++) {
1139f6889c1bSMathieu Othacehe if (val == vcnl4010_prox_sampling_frequency[i][0] &&
1140f6889c1bSMathieu Othacehe val2 == vcnl4010_prox_sampling_frequency[i][1]) {
1141f6889c1bSMathieu Othacehe index = i;
1142f6889c1bSMathieu Othacehe break;
1143f6889c1bSMathieu Othacehe }
1144f6889c1bSMathieu Othacehe }
1145f6889c1bSMathieu Othacehe
1146f6889c1bSMathieu Othacehe if (index < 0)
1147f6889c1bSMathieu Othacehe return -EINVAL;
1148f6889c1bSMathieu Othacehe
1149f6889c1bSMathieu Othacehe return i2c_smbus_write_byte_data(data->client, VCNL4010_PROX_RATE,
1150f6889c1bSMathieu Othacehe index);
1151f6889c1bSMathieu Othacehe }
1152f6889c1bSMathieu Othacehe
vcnl4010_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)1153f6889c1bSMathieu Othacehe static int vcnl4010_write_raw(struct iio_dev *indio_dev,
1154f6889c1bSMathieu Othacehe struct iio_chan_spec const *chan,
1155f6889c1bSMathieu Othacehe int val, int val2, long mask)
1156f6889c1bSMathieu Othacehe {
1157f6889c1bSMathieu Othacehe int ret;
1158f6889c1bSMathieu Othacehe struct vcnl4000_data *data = iio_priv(indio_dev);
1159f6889c1bSMathieu Othacehe
1160f6889c1bSMathieu Othacehe ret = iio_device_claim_direct_mode(indio_dev);
1161f6889c1bSMathieu Othacehe if (ret)
1162f6889c1bSMathieu Othacehe return ret;
1163f6889c1bSMathieu Othacehe
1164f6889c1bSMathieu Othacehe /* Protect against event capture. */
1165f6889c1bSMathieu Othacehe if (vcnl4010_is_in_periodic_mode(data)) {
1166f6889c1bSMathieu Othacehe ret = -EBUSY;
1167f6889c1bSMathieu Othacehe goto end;
1168f6889c1bSMathieu Othacehe }
1169f6889c1bSMathieu Othacehe
1170f6889c1bSMathieu Othacehe switch (mask) {
1171f6889c1bSMathieu Othacehe case IIO_CHAN_INFO_SAMP_FREQ:
1172f6889c1bSMathieu Othacehe switch (chan->type) {
1173f6889c1bSMathieu Othacehe case IIO_PROXIMITY:
1174f6889c1bSMathieu Othacehe ret = vcnl4010_write_proxy_samp_freq(data, val, val2);
1175f6889c1bSMathieu Othacehe goto end;
1176f6889c1bSMathieu Othacehe default:
1177f6889c1bSMathieu Othacehe ret = -EINVAL;
1178f6889c1bSMathieu Othacehe goto end;
1179f6889c1bSMathieu Othacehe }
1180f6889c1bSMathieu Othacehe default:
1181f6889c1bSMathieu Othacehe ret = -EINVAL;
1182f6889c1bSMathieu Othacehe goto end;
1183f6889c1bSMathieu Othacehe }
1184f6889c1bSMathieu Othacehe
1185f6889c1bSMathieu Othacehe end:
1186f6889c1bSMathieu Othacehe iio_device_release_direct_mode(indio_dev);
1187f6889c1bSMathieu Othacehe return ret;
1188d35567fcSMathieu Othacehe }
1189d35567fcSMathieu Othacehe
vcnl4010_read_event(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,enum iio_event_info info,int * val,int * val2)1190d35567fcSMathieu Othacehe static int vcnl4010_read_event(struct iio_dev *indio_dev,
1191d35567fcSMathieu Othacehe const struct iio_chan_spec *chan,
1192d35567fcSMathieu Othacehe enum iio_event_type type,
1193d35567fcSMathieu Othacehe enum iio_event_direction dir,
1194d35567fcSMathieu Othacehe enum iio_event_info info,
1195d35567fcSMathieu Othacehe int *val, int *val2)
1196d35567fcSMathieu Othacehe {
1197d35567fcSMathieu Othacehe int ret;
1198d35567fcSMathieu Othacehe struct vcnl4000_data *data = iio_priv(indio_dev);
1199d35567fcSMathieu Othacehe
1200d35567fcSMathieu Othacehe switch (info) {
1201d35567fcSMathieu Othacehe case IIO_EV_INFO_VALUE:
1202d35567fcSMathieu Othacehe switch (dir) {
1203d35567fcSMathieu Othacehe case IIO_EV_DIR_RISING:
1204d35567fcSMathieu Othacehe ret = vcnl4000_read_data(data, VCNL4010_HIGH_THR_HI,
1205d35567fcSMathieu Othacehe val);
1206d35567fcSMathieu Othacehe if (ret < 0)
1207d35567fcSMathieu Othacehe return ret;
1208d35567fcSMathieu Othacehe return IIO_VAL_INT;
1209d35567fcSMathieu Othacehe case IIO_EV_DIR_FALLING:
1210d35567fcSMathieu Othacehe ret = vcnl4000_read_data(data, VCNL4010_LOW_THR_HI,
1211d35567fcSMathieu Othacehe val);
1212d35567fcSMathieu Othacehe if (ret < 0)
1213d35567fcSMathieu Othacehe return ret;
1214d35567fcSMathieu Othacehe return IIO_VAL_INT;
1215d35567fcSMathieu Othacehe default:
1216d35567fcSMathieu Othacehe return -EINVAL;
1217d35567fcSMathieu Othacehe }
1218d35567fcSMathieu Othacehe default:
1219d35567fcSMathieu Othacehe return -EINVAL;
1220d35567fcSMathieu Othacehe }
1221d35567fcSMathieu Othacehe }
1222d35567fcSMathieu Othacehe
vcnl4010_write_event(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,enum iio_event_info info,int val,int val2)1223d35567fcSMathieu Othacehe static int vcnl4010_write_event(struct iio_dev *indio_dev,
1224d35567fcSMathieu Othacehe const struct iio_chan_spec *chan,
1225d35567fcSMathieu Othacehe enum iio_event_type type,
1226d35567fcSMathieu Othacehe enum iio_event_direction dir,
1227d35567fcSMathieu Othacehe enum iio_event_info info,
1228d35567fcSMathieu Othacehe int val, int val2)
1229d35567fcSMathieu Othacehe {
1230d35567fcSMathieu Othacehe int ret;
1231d35567fcSMathieu Othacehe struct vcnl4000_data *data = iio_priv(indio_dev);
1232d35567fcSMathieu Othacehe
1233d35567fcSMathieu Othacehe switch (info) {
1234d35567fcSMathieu Othacehe case IIO_EV_INFO_VALUE:
1235d35567fcSMathieu Othacehe switch (dir) {
1236d35567fcSMathieu Othacehe case IIO_EV_DIR_RISING:
1237d35567fcSMathieu Othacehe ret = vcnl4000_write_data(data, VCNL4010_HIGH_THR_HI,
1238d35567fcSMathieu Othacehe val);
1239d35567fcSMathieu Othacehe if (ret < 0)
1240d35567fcSMathieu Othacehe return ret;
1241d35567fcSMathieu Othacehe return IIO_VAL_INT;
1242d35567fcSMathieu Othacehe case IIO_EV_DIR_FALLING:
1243d35567fcSMathieu Othacehe ret = vcnl4000_write_data(data, VCNL4010_LOW_THR_HI,
1244d35567fcSMathieu Othacehe val);
1245d35567fcSMathieu Othacehe if (ret < 0)
1246d35567fcSMathieu Othacehe return ret;
1247d35567fcSMathieu Othacehe return IIO_VAL_INT;
1248d35567fcSMathieu Othacehe default:
1249d35567fcSMathieu Othacehe return -EINVAL;
1250d35567fcSMathieu Othacehe }
1251d35567fcSMathieu Othacehe default:
1252d35567fcSMathieu Othacehe return -EINVAL;
1253d35567fcSMathieu Othacehe }
1254d35567fcSMathieu Othacehe }
1255d35567fcSMathieu Othacehe
vcnl4040_read_event(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,enum iio_event_info info,int * val,int * val2)125654667612SMårten Lindahl static int vcnl4040_read_event(struct iio_dev *indio_dev,
125754667612SMårten Lindahl const struct iio_chan_spec *chan,
125854667612SMårten Lindahl enum iio_event_type type,
125954667612SMårten Lindahl enum iio_event_direction dir,
126054667612SMårten Lindahl enum iio_event_info info,
126154667612SMårten Lindahl int *val, int *val2)
126254667612SMårten Lindahl {
126354667612SMårten Lindahl int ret;
126454667612SMårten Lindahl struct vcnl4000_data *data = iio_priv(indio_dev);
126554667612SMårten Lindahl
12662be17b68SAstrid Rost switch (chan->type) {
1267bc292aafSAstrid Rost case IIO_LIGHT:
1268bc292aafSAstrid Rost switch (info) {
12697f865127SAstrid Rost case IIO_EV_INFO_PERIOD:
12707f865127SAstrid Rost return vcnl4040_read_als_period(data, val, val2);
1271bc292aafSAstrid Rost case IIO_EV_INFO_VALUE:
1272bc292aafSAstrid Rost switch (dir) {
1273bc292aafSAstrid Rost case IIO_EV_DIR_RISING:
1274bc292aafSAstrid Rost ret = i2c_smbus_read_word_data(data->client,
1275bc292aafSAstrid Rost VCNL4040_ALS_THDH_LM);
1276bc292aafSAstrid Rost break;
1277bc292aafSAstrid Rost case IIO_EV_DIR_FALLING:
1278bc292aafSAstrid Rost ret = i2c_smbus_read_word_data(data->client,
1279bc292aafSAstrid Rost VCNL4040_ALS_THDL_LM);
1280bc292aafSAstrid Rost break;
1281bc292aafSAstrid Rost default:
1282bc292aafSAstrid Rost return -EINVAL;
1283bc292aafSAstrid Rost }
1284bc292aafSAstrid Rost break;
1285bc292aafSAstrid Rost default:
1286bc292aafSAstrid Rost return -EINVAL;
1287bc292aafSAstrid Rost }
1288bc292aafSAstrid Rost break;
12892be17b68SAstrid Rost case IIO_PROXIMITY:
12902be17b68SAstrid Rost switch (info) {
12917f865127SAstrid Rost case IIO_EV_INFO_PERIOD:
12927f865127SAstrid Rost return vcnl4040_read_ps_period(data, val, val2);
12932be17b68SAstrid Rost case IIO_EV_INFO_VALUE:
129454667612SMårten Lindahl switch (dir) {
129554667612SMårten Lindahl case IIO_EV_DIR_RISING:
129654667612SMårten Lindahl ret = i2c_smbus_read_word_data(data->client,
129754667612SMårten Lindahl VCNL4040_PS_THDH_LM);
12982be17b68SAstrid Rost break;
129954667612SMårten Lindahl case IIO_EV_DIR_FALLING:
130054667612SMårten Lindahl ret = i2c_smbus_read_word_data(data->client,
130154667612SMårten Lindahl VCNL4040_PS_THDL_LM);
13022be17b68SAstrid Rost break;
13032be17b68SAstrid Rost default:
13042be17b68SAstrid Rost return -EINVAL;
13052be17b68SAstrid Rost }
13062be17b68SAstrid Rost break;
13072be17b68SAstrid Rost default:
13082be17b68SAstrid Rost return -EINVAL;
13092be17b68SAstrid Rost }
13102be17b68SAstrid Rost break;
13112be17b68SAstrid Rost default:
13122be17b68SAstrid Rost return -EINVAL;
13132be17b68SAstrid Rost }
131454667612SMårten Lindahl if (ret < 0)
131554667612SMårten Lindahl return ret;
131654667612SMårten Lindahl *val = ret;
131754667612SMårten Lindahl return IIO_VAL_INT;
131854667612SMårten Lindahl }
131954667612SMårten Lindahl
vcnl4040_write_event(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,enum iio_event_info info,int val,int val2)132054667612SMårten Lindahl static int vcnl4040_write_event(struct iio_dev *indio_dev,
132154667612SMårten Lindahl const struct iio_chan_spec *chan,
132254667612SMårten Lindahl enum iio_event_type type,
132354667612SMårten Lindahl enum iio_event_direction dir,
132454667612SMårten Lindahl enum iio_event_info info,
132554667612SMårten Lindahl int val, int val2)
132654667612SMårten Lindahl {
132754667612SMårten Lindahl int ret;
132854667612SMårten Lindahl struct vcnl4000_data *data = iio_priv(indio_dev);
132954667612SMårten Lindahl
13302be17b68SAstrid Rost switch (chan->type) {
1331bc292aafSAstrid Rost case IIO_LIGHT:
1332bc292aafSAstrid Rost switch (info) {
13337f865127SAstrid Rost case IIO_EV_INFO_PERIOD:
13347f865127SAstrid Rost return vcnl4040_write_als_period(data, val, val2);
1335bc292aafSAstrid Rost case IIO_EV_INFO_VALUE:
1336bc292aafSAstrid Rost switch (dir) {
1337bc292aafSAstrid Rost case IIO_EV_DIR_RISING:
1338bc292aafSAstrid Rost ret = i2c_smbus_write_word_data(data->client,
1339bc292aafSAstrid Rost VCNL4040_ALS_THDH_LM,
1340bc292aafSAstrid Rost val);
1341bc292aafSAstrid Rost break;
1342bc292aafSAstrid Rost case IIO_EV_DIR_FALLING:
1343bc292aafSAstrid Rost ret = i2c_smbus_write_word_data(data->client,
1344bc292aafSAstrid Rost VCNL4040_ALS_THDL_LM,
1345bc292aafSAstrid Rost val);
1346bc292aafSAstrid Rost break;
1347bc292aafSAstrid Rost default:
1348bc292aafSAstrid Rost return -EINVAL;
1349bc292aafSAstrid Rost }
1350bc292aafSAstrid Rost break;
1351bc292aafSAstrid Rost default:
1352bc292aafSAstrid Rost return -EINVAL;
1353bc292aafSAstrid Rost }
1354bc292aafSAstrid Rost break;
13552be17b68SAstrid Rost case IIO_PROXIMITY:
13562be17b68SAstrid Rost switch (info) {
13577f865127SAstrid Rost case IIO_EV_INFO_PERIOD:
13587f865127SAstrid Rost return vcnl4040_write_ps_period(data, val, val2);
13592be17b68SAstrid Rost case IIO_EV_INFO_VALUE:
136054667612SMårten Lindahl switch (dir) {
136154667612SMårten Lindahl case IIO_EV_DIR_RISING:
136254667612SMårten Lindahl ret = i2c_smbus_write_word_data(data->client,
13632be17b68SAstrid Rost VCNL4040_PS_THDH_LM,
13642be17b68SAstrid Rost val);
13652be17b68SAstrid Rost break;
136654667612SMårten Lindahl case IIO_EV_DIR_FALLING:
136754667612SMårten Lindahl ret = i2c_smbus_write_word_data(data->client,
13682be17b68SAstrid Rost VCNL4040_PS_THDL_LM,
13692be17b68SAstrid Rost val);
13702be17b68SAstrid Rost break;
137154667612SMårten Lindahl default:
137254667612SMårten Lindahl return -EINVAL;
137354667612SMårten Lindahl }
13742be17b68SAstrid Rost break;
13752be17b68SAstrid Rost default:
13762be17b68SAstrid Rost return -EINVAL;
13772be17b68SAstrid Rost }
13782be17b68SAstrid Rost break;
13792be17b68SAstrid Rost default:
13802be17b68SAstrid Rost return -EINVAL;
13812be17b68SAstrid Rost }
13822be17b68SAstrid Rost if (ret < 0)
13832be17b68SAstrid Rost return ret;
13842be17b68SAstrid Rost return IIO_VAL_INT;
138554667612SMårten Lindahl }
138654667612SMårten Lindahl
vcnl4010_is_thr_enabled(struct vcnl4000_data * data)1387d35567fcSMathieu Othacehe static bool vcnl4010_is_thr_enabled(struct vcnl4000_data *data)
1388d35567fcSMathieu Othacehe {
1389d35567fcSMathieu Othacehe int ret;
1390d35567fcSMathieu Othacehe
1391d35567fcSMathieu Othacehe ret = i2c_smbus_read_byte_data(data->client, VCNL4010_INT_CTRL);
1392d35567fcSMathieu Othacehe if (ret < 0)
1393d35567fcSMathieu Othacehe return false;
1394d35567fcSMathieu Othacehe
1395d35567fcSMathieu Othacehe return !!(ret & VCNL4010_INT_THR_EN);
1396d35567fcSMathieu Othacehe }
1397d35567fcSMathieu Othacehe
vcnl4010_read_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir)1398d35567fcSMathieu Othacehe static int vcnl4010_read_event_config(struct iio_dev *indio_dev,
1399d35567fcSMathieu Othacehe const struct iio_chan_spec *chan,
1400d35567fcSMathieu Othacehe enum iio_event_type type,
1401d35567fcSMathieu Othacehe enum iio_event_direction dir)
1402d35567fcSMathieu Othacehe {
1403d35567fcSMathieu Othacehe struct vcnl4000_data *data = iio_priv(indio_dev);
1404d35567fcSMathieu Othacehe
1405d35567fcSMathieu Othacehe switch (chan->type) {
1406d35567fcSMathieu Othacehe case IIO_PROXIMITY:
1407d35567fcSMathieu Othacehe return vcnl4010_is_thr_enabled(data);
1408d35567fcSMathieu Othacehe default:
1409d35567fcSMathieu Othacehe return -EINVAL;
1410d35567fcSMathieu Othacehe }
1411d35567fcSMathieu Othacehe }
1412d35567fcSMathieu Othacehe
vcnl4010_config_threshold(struct iio_dev * indio_dev,bool state)1413d35567fcSMathieu Othacehe static int vcnl4010_config_threshold(struct iio_dev *indio_dev, bool state)
1414d35567fcSMathieu Othacehe {
1415d35567fcSMathieu Othacehe struct vcnl4000_data *data = iio_priv(indio_dev);
1416d35567fcSMathieu Othacehe int ret;
1417d35567fcSMathieu Othacehe int icr;
1418d35567fcSMathieu Othacehe int command;
1419d35567fcSMathieu Othacehe
1420d35567fcSMathieu Othacehe if (state) {
1421d35567fcSMathieu Othacehe ret = iio_device_claim_direct_mode(indio_dev);
1422d35567fcSMathieu Othacehe if (ret)
1423d35567fcSMathieu Othacehe return ret;
1424d35567fcSMathieu Othacehe
1425d35567fcSMathieu Othacehe /* Enable periodic measurement of proximity data. */
1426d35567fcSMathieu Othacehe command = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
1427d35567fcSMathieu Othacehe
1428d35567fcSMathieu Othacehe /*
1429d35567fcSMathieu Othacehe * Enable interrupts on threshold, for proximity data by
1430d35567fcSMathieu Othacehe * default.
1431d35567fcSMathieu Othacehe */
1432d35567fcSMathieu Othacehe icr = VCNL4010_INT_THR_EN;
1433d35567fcSMathieu Othacehe } else {
1434d35567fcSMathieu Othacehe if (!vcnl4010_is_thr_enabled(data))
1435d35567fcSMathieu Othacehe return 0;
1436d35567fcSMathieu Othacehe
1437d35567fcSMathieu Othacehe command = 0;
1438d35567fcSMathieu Othacehe icr = 0;
1439d35567fcSMathieu Othacehe }
1440d35567fcSMathieu Othacehe
1441d35567fcSMathieu Othacehe ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
1442d35567fcSMathieu Othacehe command);
1443d35567fcSMathieu Othacehe if (ret < 0)
1444d35567fcSMathieu Othacehe goto end;
1445d35567fcSMathieu Othacehe
1446d35567fcSMathieu Othacehe ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, icr);
1447d35567fcSMathieu Othacehe
1448d35567fcSMathieu Othacehe end:
1449d35567fcSMathieu Othacehe if (state)
1450d35567fcSMathieu Othacehe iio_device_release_direct_mode(indio_dev);
1451d35567fcSMathieu Othacehe
1452d35567fcSMathieu Othacehe return ret;
1453d35567fcSMathieu Othacehe }
1454d35567fcSMathieu Othacehe
vcnl4010_write_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,int state)1455d35567fcSMathieu Othacehe static int vcnl4010_write_event_config(struct iio_dev *indio_dev,
1456d35567fcSMathieu Othacehe const struct iio_chan_spec *chan,
1457d35567fcSMathieu Othacehe enum iio_event_type type,
1458d35567fcSMathieu Othacehe enum iio_event_direction dir,
1459d35567fcSMathieu Othacehe int state)
1460d35567fcSMathieu Othacehe {
1461d35567fcSMathieu Othacehe switch (chan->type) {
1462d35567fcSMathieu Othacehe case IIO_PROXIMITY:
1463d35567fcSMathieu Othacehe return vcnl4010_config_threshold(indio_dev, state);
1464d35567fcSMathieu Othacehe default:
1465d35567fcSMathieu Othacehe return -EINVAL;
1466d35567fcSMathieu Othacehe }
1467d35567fcSMathieu Othacehe }
1468d35567fcSMathieu Othacehe
vcnl4040_read_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir)146954667612SMårten Lindahl static int vcnl4040_read_event_config(struct iio_dev *indio_dev,
147054667612SMårten Lindahl const struct iio_chan_spec *chan,
147154667612SMårten Lindahl enum iio_event_type type,
147254667612SMårten Lindahl enum iio_event_direction dir)
147354667612SMårten Lindahl {
147454667612SMårten Lindahl int ret;
147554667612SMårten Lindahl struct vcnl4000_data *data = iio_priv(indio_dev);
147654667612SMårten Lindahl
14772be17b68SAstrid Rost switch (chan->type) {
1478bc292aafSAstrid Rost case IIO_LIGHT:
1479bc292aafSAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
1480bc292aafSAstrid Rost if (ret < 0)
1481bc292aafSAstrid Rost return ret;
1482bc292aafSAstrid Rost
1483bc292aafSAstrid Rost data->als_int = FIELD_GET(VCNL4040_ALS_CONF_INT_EN, ret);
1484bc292aafSAstrid Rost
1485bc292aafSAstrid Rost return data->als_int;
14862be17b68SAstrid Rost case IIO_PROXIMITY:
148754667612SMårten Lindahl ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
148854667612SMårten Lindahl if (ret < 0)
148954667612SMårten Lindahl return ret;
149054667612SMårten Lindahl
149154667612SMårten Lindahl data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, ret);
149254667612SMårten Lindahl
149354667612SMårten Lindahl return (dir == IIO_EV_DIR_RISING) ?
149454667612SMårten Lindahl FIELD_GET(VCNL4040_PS_IF_AWAY, ret) :
149554667612SMårten Lindahl FIELD_GET(VCNL4040_PS_IF_CLOSE, ret);
14962be17b68SAstrid Rost default:
14972be17b68SAstrid Rost return -EINVAL;
14982be17b68SAstrid Rost }
149954667612SMårten Lindahl }
150054667612SMårten Lindahl
vcnl4040_write_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,int state)150154667612SMårten Lindahl static int vcnl4040_write_event_config(struct iio_dev *indio_dev,
150254667612SMårten Lindahl const struct iio_chan_spec *chan,
150354667612SMårten Lindahl enum iio_event_type type,
150454667612SMårten Lindahl enum iio_event_direction dir, int state)
150554667612SMårten Lindahl {
15062be17b68SAstrid Rost int ret = -EINVAL;
150754667612SMårten Lindahl u16 val, mask;
150854667612SMårten Lindahl struct vcnl4000_data *data = iio_priv(indio_dev);
150954667612SMårten Lindahl
151054667612SMårten Lindahl mutex_lock(&data->vcnl4000_lock);
151154667612SMårten Lindahl
15122be17b68SAstrid Rost switch (chan->type) {
1513bc292aafSAstrid Rost case IIO_LIGHT:
1514bc292aafSAstrid Rost ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
1515bc292aafSAstrid Rost if (ret < 0)
1516bc292aafSAstrid Rost goto out;
1517bc292aafSAstrid Rost
1518bc292aafSAstrid Rost mask = VCNL4040_ALS_CONF_INT_EN;
1519bc292aafSAstrid Rost if (state)
1520bc292aafSAstrid Rost val = (ret | mask);
1521bc292aafSAstrid Rost else
1522bc292aafSAstrid Rost val = (ret & ~mask);
1523bc292aafSAstrid Rost
1524bc292aafSAstrid Rost data->als_int = FIELD_GET(VCNL4040_ALS_CONF_INT_EN, val);
1525bc292aafSAstrid Rost ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF,
1526bc292aafSAstrid Rost val);
1527bc292aafSAstrid Rost break;
15282be17b68SAstrid Rost case IIO_PROXIMITY:
152954667612SMårten Lindahl ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
153054667612SMårten Lindahl if (ret < 0)
153154667612SMårten Lindahl goto out;
153254667612SMårten Lindahl
153354667612SMårten Lindahl if (dir == IIO_EV_DIR_RISING)
153454667612SMårten Lindahl mask = VCNL4040_PS_IF_AWAY;
153554667612SMårten Lindahl else
153654667612SMårten Lindahl mask = VCNL4040_PS_IF_CLOSE;
153754667612SMårten Lindahl
153854667612SMårten Lindahl val = state ? (ret | mask) : (ret & ~mask);
153954667612SMårten Lindahl
154054667612SMårten Lindahl data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, val);
15412be17b68SAstrid Rost ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
15422be17b68SAstrid Rost val);
15432be17b68SAstrid Rost break;
15442be17b68SAstrid Rost default:
15452be17b68SAstrid Rost break;
15462be17b68SAstrid Rost }
154754667612SMårten Lindahl
154854667612SMårten Lindahl out:
154954667612SMårten Lindahl mutex_unlock(&data->vcnl4000_lock);
155054667612SMårten Lindahl
155154667612SMårten Lindahl return ret;
155254667612SMårten Lindahl }
155354667612SMårten Lindahl
vcnl4040_irq_thread(int irq,void * p)155454667612SMårten Lindahl static irqreturn_t vcnl4040_irq_thread(int irq, void *p)
155554667612SMårten Lindahl {
155654667612SMårten Lindahl struct iio_dev *indio_dev = p;
155754667612SMårten Lindahl struct vcnl4000_data *data = iio_priv(indio_dev);
155854667612SMårten Lindahl int ret;
155954667612SMårten Lindahl
1560854965b7SAstrid Rost ret = i2c_smbus_read_word_data(data->client, data->chip_spec->int_reg);
156154667612SMårten Lindahl if (ret < 0)
156254667612SMårten Lindahl return IRQ_HANDLED;
156354667612SMårten Lindahl
156454667612SMårten Lindahl if (ret & VCNL4040_PS_IF_CLOSE) {
156554667612SMårten Lindahl iio_push_event(indio_dev,
156654667612SMårten Lindahl IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
156754667612SMårten Lindahl IIO_EV_TYPE_THRESH,
156854667612SMårten Lindahl IIO_EV_DIR_RISING),
156954667612SMårten Lindahl iio_get_time_ns(indio_dev));
157054667612SMårten Lindahl }
157154667612SMårten Lindahl
157254667612SMårten Lindahl if (ret & VCNL4040_PS_IF_AWAY) {
157354667612SMårten Lindahl iio_push_event(indio_dev,
157454667612SMårten Lindahl IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
157554667612SMårten Lindahl IIO_EV_TYPE_THRESH,
157654667612SMårten Lindahl IIO_EV_DIR_FALLING),
157754667612SMårten Lindahl iio_get_time_ns(indio_dev));
157854667612SMårten Lindahl }
157954667612SMårten Lindahl
1580bc292aafSAstrid Rost if (ret & VCNL4040_ALS_FALLING) {
1581bc292aafSAstrid Rost iio_push_event(indio_dev,
1582bc292aafSAstrid Rost IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
1583bc292aafSAstrid Rost IIO_EV_TYPE_THRESH,
1584bc292aafSAstrid Rost IIO_EV_DIR_FALLING),
1585bc292aafSAstrid Rost iio_get_time_ns(indio_dev));
1586bc292aafSAstrid Rost }
1587bc292aafSAstrid Rost
1588bc292aafSAstrid Rost if (ret & VCNL4040_ALS_RISING) {
1589bc292aafSAstrid Rost iio_push_event(indio_dev,
1590bc292aafSAstrid Rost IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
1591bc292aafSAstrid Rost IIO_EV_TYPE_THRESH,
1592bc292aafSAstrid Rost IIO_EV_DIR_RISING),
1593bc292aafSAstrid Rost iio_get_time_ns(indio_dev));
1594bc292aafSAstrid Rost }
1595bc292aafSAstrid Rost
159654667612SMårten Lindahl return IRQ_HANDLED;
159754667612SMårten Lindahl }
159854667612SMårten Lindahl
vcnl4000_read_near_level(struct iio_dev * indio_dev,uintptr_t priv,const struct iio_chan_spec * chan,char * buf)1599d35567fcSMathieu Othacehe static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,
1600d35567fcSMathieu Othacehe uintptr_t priv,
1601d35567fcSMathieu Othacehe const struct iio_chan_spec *chan,
1602d35567fcSMathieu Othacehe char *buf)
1603d35567fcSMathieu Othacehe {
1604d35567fcSMathieu Othacehe struct vcnl4000_data *data = iio_priv(indio_dev);
1605d35567fcSMathieu Othacehe
1606d35567fcSMathieu Othacehe return sprintf(buf, "%u\n", data->near_level);
1607d35567fcSMathieu Othacehe }
1608d35567fcSMathieu Othacehe
vcnl4010_irq_thread(int irq,void * p)16093a52d32aSMårten Lindahl static irqreturn_t vcnl4010_irq_thread(int irq, void *p)
16103a52d32aSMårten Lindahl {
16113a52d32aSMårten Lindahl struct iio_dev *indio_dev = p;
16123a52d32aSMårten Lindahl struct vcnl4000_data *data = iio_priv(indio_dev);
16133a52d32aSMårten Lindahl unsigned long isr;
16143a52d32aSMårten Lindahl int ret;
16153a52d32aSMårten Lindahl
16163a52d32aSMårten Lindahl ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
16173a52d32aSMårten Lindahl if (ret < 0)
16183a52d32aSMårten Lindahl goto end;
16193a52d32aSMårten Lindahl
16203a52d32aSMårten Lindahl isr = ret;
16213a52d32aSMårten Lindahl
16223a52d32aSMårten Lindahl if (isr & VCNL4010_INT_THR) {
16233a52d32aSMårten Lindahl if (test_bit(VCNL4010_INT_THR_LOW, &isr)) {
16243a52d32aSMårten Lindahl iio_push_event(indio_dev,
16253a52d32aSMårten Lindahl IIO_UNMOD_EVENT_CODE(
16263a52d32aSMårten Lindahl IIO_PROXIMITY,
16273a52d32aSMårten Lindahl 1,
16283a52d32aSMårten Lindahl IIO_EV_TYPE_THRESH,
16293a52d32aSMårten Lindahl IIO_EV_DIR_FALLING),
16303a52d32aSMårten Lindahl iio_get_time_ns(indio_dev));
16313a52d32aSMårten Lindahl }
16323a52d32aSMårten Lindahl
16333a52d32aSMårten Lindahl if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) {
16343a52d32aSMårten Lindahl iio_push_event(indio_dev,
16353a52d32aSMårten Lindahl IIO_UNMOD_EVENT_CODE(
16363a52d32aSMårten Lindahl IIO_PROXIMITY,
16373a52d32aSMårten Lindahl 1,
16383a52d32aSMårten Lindahl IIO_EV_TYPE_THRESH,
16393a52d32aSMårten Lindahl IIO_EV_DIR_RISING),
16403a52d32aSMårten Lindahl iio_get_time_ns(indio_dev));
16413a52d32aSMårten Lindahl }
16423a52d32aSMårten Lindahl
16433a52d32aSMårten Lindahl i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
16443a52d32aSMårten Lindahl isr & VCNL4010_INT_THR);
16453a52d32aSMårten Lindahl }
16463a52d32aSMårten Lindahl
16473a52d32aSMårten Lindahl if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev))
1648f700e55eSMehdi Djait iio_trigger_poll_nested(indio_dev->trig);
16493a52d32aSMårten Lindahl
16503a52d32aSMårten Lindahl end:
16513a52d32aSMårten Lindahl return IRQ_HANDLED;
16523a52d32aSMårten Lindahl }
16533a52d32aSMårten Lindahl
vcnl4010_trigger_handler(int irq,void * p)16543a52d32aSMårten Lindahl static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)
16553a52d32aSMårten Lindahl {
16563a52d32aSMårten Lindahl struct iio_poll_func *pf = p;
16573a52d32aSMårten Lindahl struct iio_dev *indio_dev = pf->indio_dev;
16583a52d32aSMårten Lindahl struct vcnl4000_data *data = iio_priv(indio_dev);
16593a52d32aSMårten Lindahl const unsigned long *active_scan_mask = indio_dev->active_scan_mask;
16603a52d32aSMårten Lindahl u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */
16613a52d32aSMårten Lindahl bool data_read = false;
16623a52d32aSMårten Lindahl unsigned long isr;
16633a52d32aSMårten Lindahl int val = 0;
16643a52d32aSMårten Lindahl int ret;
16653a52d32aSMårten Lindahl
16663a52d32aSMårten Lindahl ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
16673a52d32aSMårten Lindahl if (ret < 0)
16683a52d32aSMårten Lindahl goto end;
16693a52d32aSMårten Lindahl
16703a52d32aSMårten Lindahl isr = ret;
16713a52d32aSMårten Lindahl
16723a52d32aSMårten Lindahl if (test_bit(0, active_scan_mask)) {
16733a52d32aSMårten Lindahl if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) {
16743a52d32aSMårten Lindahl ret = vcnl4000_read_data(data,
16753a52d32aSMårten Lindahl VCNL4000_PS_RESULT_HI,
16763a52d32aSMårten Lindahl &val);
16773a52d32aSMårten Lindahl if (ret < 0)
16783a52d32aSMårten Lindahl goto end;
16793a52d32aSMårten Lindahl
16803a52d32aSMårten Lindahl buffer[0] = val;
16813a52d32aSMårten Lindahl data_read = true;
16823a52d32aSMårten Lindahl }
16833a52d32aSMårten Lindahl }
16843a52d32aSMårten Lindahl
16853a52d32aSMårten Lindahl ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
16863a52d32aSMårten Lindahl isr & VCNL4010_INT_DRDY);
16873a52d32aSMårten Lindahl if (ret < 0)
16883a52d32aSMårten Lindahl goto end;
16893a52d32aSMårten Lindahl
16903a52d32aSMårten Lindahl if (!data_read)
16913a52d32aSMårten Lindahl goto end;
16923a52d32aSMårten Lindahl
16933a52d32aSMårten Lindahl iio_push_to_buffers_with_timestamp(indio_dev, buffer,
16943a52d32aSMårten Lindahl iio_get_time_ns(indio_dev));
16953a52d32aSMårten Lindahl
16963a52d32aSMårten Lindahl end:
16973a52d32aSMårten Lindahl iio_trigger_notify_done(indio_dev->trig);
16983a52d32aSMårten Lindahl return IRQ_HANDLED;
16993a52d32aSMårten Lindahl }
17003a52d32aSMårten Lindahl
vcnl4010_buffer_postenable(struct iio_dev * indio_dev)17013a52d32aSMårten Lindahl static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev)
17023a52d32aSMårten Lindahl {
17033a52d32aSMårten Lindahl struct vcnl4000_data *data = iio_priv(indio_dev);
17043a52d32aSMårten Lindahl int ret;
17053a52d32aSMårten Lindahl int cmd;
17063a52d32aSMårten Lindahl
17073a52d32aSMårten Lindahl /* Do not enable the buffer if we are already capturing events. */
17083a52d32aSMårten Lindahl if (vcnl4010_is_in_periodic_mode(data))
17093a52d32aSMårten Lindahl return -EBUSY;
17103a52d32aSMårten Lindahl
17113a52d32aSMårten Lindahl ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL,
17123a52d32aSMårten Lindahl VCNL4010_INT_PROX_EN);
17133a52d32aSMårten Lindahl if (ret < 0)
17143a52d32aSMårten Lindahl return ret;
17153a52d32aSMårten Lindahl
17163a52d32aSMårten Lindahl cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
17173a52d32aSMårten Lindahl return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd);
17183a52d32aSMårten Lindahl }
17193a52d32aSMårten Lindahl
vcnl4010_buffer_predisable(struct iio_dev * indio_dev)17203a52d32aSMårten Lindahl static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev)
17213a52d32aSMårten Lindahl {
17223a52d32aSMårten Lindahl struct vcnl4000_data *data = iio_priv(indio_dev);
17233a52d32aSMårten Lindahl int ret;
17243a52d32aSMårten Lindahl
17253a52d32aSMårten Lindahl ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0);
17263a52d32aSMårten Lindahl if (ret < 0)
17273a52d32aSMårten Lindahl return ret;
17283a52d32aSMårten Lindahl
17293a52d32aSMårten Lindahl return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0);
17303a52d32aSMårten Lindahl }
17313a52d32aSMårten Lindahl
17323a52d32aSMårten Lindahl static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = {
17333a52d32aSMårten Lindahl .postenable = &vcnl4010_buffer_postenable,
17343a52d32aSMårten Lindahl .predisable = &vcnl4010_buffer_predisable,
17353a52d32aSMårten Lindahl };
17363a52d32aSMårten Lindahl
1737d35567fcSMathieu Othacehe static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = {
1738d35567fcSMathieu Othacehe {
1739d35567fcSMathieu Othacehe .name = "nearlevel",
1740d35567fcSMathieu Othacehe .shared = IIO_SEPARATE,
1741d35567fcSMathieu Othacehe .read = vcnl4000_read_near_level,
1742d35567fcSMathieu Othacehe },
1743d35567fcSMathieu Othacehe { /* sentinel */ }
1744d35567fcSMathieu Othacehe };
1745d35567fcSMathieu Othacehe
1746d35567fcSMathieu Othacehe static const struct iio_event_spec vcnl4000_event_spec[] = {
1747d35567fcSMathieu Othacehe {
1748d35567fcSMathieu Othacehe .type = IIO_EV_TYPE_THRESH,
1749d35567fcSMathieu Othacehe .dir = IIO_EV_DIR_RISING,
1750d35567fcSMathieu Othacehe .mask_separate = BIT(IIO_EV_INFO_VALUE),
1751d35567fcSMathieu Othacehe }, {
1752d35567fcSMathieu Othacehe .type = IIO_EV_TYPE_THRESH,
1753d35567fcSMathieu Othacehe .dir = IIO_EV_DIR_FALLING,
1754d35567fcSMathieu Othacehe .mask_separate = BIT(IIO_EV_INFO_VALUE),
1755d35567fcSMathieu Othacehe }, {
1756d35567fcSMathieu Othacehe .type = IIO_EV_TYPE_THRESH,
1757d35567fcSMathieu Othacehe .dir = IIO_EV_DIR_EITHER,
1758d35567fcSMathieu Othacehe .mask_separate = BIT(IIO_EV_INFO_ENABLE),
1759d35567fcSMathieu Othacehe }
1760d35567fcSMathieu Othacehe };
1761d35567fcSMathieu Othacehe
17627f865127SAstrid Rost static const struct iio_event_spec vcnl4040_als_event_spec[] = {
17637f865127SAstrid Rost {
17647f865127SAstrid Rost .type = IIO_EV_TYPE_THRESH,
17657f865127SAstrid Rost .dir = IIO_EV_DIR_RISING,
17667f865127SAstrid Rost .mask_separate = BIT(IIO_EV_INFO_VALUE),
17677f865127SAstrid Rost }, {
17687f865127SAstrid Rost .type = IIO_EV_TYPE_THRESH,
17697f865127SAstrid Rost .dir = IIO_EV_DIR_FALLING,
17707f865127SAstrid Rost .mask_separate = BIT(IIO_EV_INFO_VALUE),
17717f865127SAstrid Rost }, {
17727f865127SAstrid Rost .type = IIO_EV_TYPE_THRESH,
17737f865127SAstrid Rost .dir = IIO_EV_DIR_EITHER,
17747f865127SAstrid Rost .mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_PERIOD),
17757f865127SAstrid Rost },
17767f865127SAstrid Rost };
17777f865127SAstrid Rost
177854667612SMårten Lindahl static const struct iio_event_spec vcnl4040_event_spec[] = {
177954667612SMårten Lindahl {
178054667612SMårten Lindahl .type = IIO_EV_TYPE_THRESH,
178154667612SMårten Lindahl .dir = IIO_EV_DIR_RISING,
178254667612SMårten Lindahl .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
178354667612SMårten Lindahl }, {
178454667612SMårten Lindahl .type = IIO_EV_TYPE_THRESH,
178554667612SMårten Lindahl .dir = IIO_EV_DIR_FALLING,
178654667612SMårten Lindahl .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
17877f865127SAstrid Rost }, {
17887f865127SAstrid Rost .type = IIO_EV_TYPE_THRESH,
17897f865127SAstrid Rost .dir = IIO_EV_DIR_EITHER,
17907f865127SAstrid Rost .mask_separate = BIT(IIO_EV_INFO_PERIOD),
179154667612SMårten Lindahl },
179254667612SMårten Lindahl };
179354667612SMårten Lindahl
1794d35567fcSMathieu Othacehe static const struct iio_chan_spec vcnl4000_channels[] = {
1795d35567fcSMathieu Othacehe {
1796d35567fcSMathieu Othacehe .type = IIO_LIGHT,
1797d35567fcSMathieu Othacehe .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
1798d35567fcSMathieu Othacehe BIT(IIO_CHAN_INFO_SCALE),
1799d35567fcSMathieu Othacehe }, {
1800d35567fcSMathieu Othacehe .type = IIO_PROXIMITY,
1801d35567fcSMathieu Othacehe .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
1802d35567fcSMathieu Othacehe .ext_info = vcnl4000_ext_info,
1803d35567fcSMathieu Othacehe }
1804d35567fcSMathieu Othacehe };
1805d35567fcSMathieu Othacehe
1806d35567fcSMathieu Othacehe static const struct iio_chan_spec vcnl4010_channels[] = {
1807d35567fcSMathieu Othacehe {
1808d35567fcSMathieu Othacehe .type = IIO_LIGHT,
18098fe78d52SMathieu Othacehe .scan_index = -1,
1810d35567fcSMathieu Othacehe .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
1811d35567fcSMathieu Othacehe BIT(IIO_CHAN_INFO_SCALE),
1812d35567fcSMathieu Othacehe }, {
1813d35567fcSMathieu Othacehe .type = IIO_PROXIMITY,
18148fe78d52SMathieu Othacehe .scan_index = 0,
1815f6889c1bSMathieu Othacehe .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
1816f6889c1bSMathieu Othacehe BIT(IIO_CHAN_INFO_SAMP_FREQ),
1817f6889c1bSMathieu Othacehe .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
1818d35567fcSMathieu Othacehe .event_spec = vcnl4000_event_spec,
1819d35567fcSMathieu Othacehe .num_event_specs = ARRAY_SIZE(vcnl4000_event_spec),
1820d35567fcSMathieu Othacehe .ext_info = vcnl4000_ext_info,
18218fe78d52SMathieu Othacehe .scan_type = {
18228fe78d52SMathieu Othacehe .sign = 'u',
18238fe78d52SMathieu Othacehe .realbits = 16,
18248fe78d52SMathieu Othacehe .storagebits = 16,
18258fe78d52SMathieu Othacehe .endianness = IIO_CPU,
1826d35567fcSMathieu Othacehe },
18278fe78d52SMathieu Othacehe },
18288fe78d52SMathieu Othacehe IIO_CHAN_SOFT_TIMESTAMP(1),
1829d35567fcSMathieu Othacehe };
1830d35567fcSMathieu Othacehe
183185e2c6a2SMårten Lindahl static const struct iio_chan_spec vcnl4040_channels[] = {
183285e2c6a2SMårten Lindahl {
183385e2c6a2SMårten Lindahl .type = IIO_LIGHT,
183485e2c6a2SMårten Lindahl .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
1835fea2c97dSAstrid Rost BIT(IIO_CHAN_INFO_SCALE) |
1836fea2c97dSAstrid Rost BIT(IIO_CHAN_INFO_INT_TIME),
1837fea2c97dSAstrid Rost .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME),
18387f865127SAstrid Rost .event_spec = vcnl4040_als_event_spec,
18397f865127SAstrid Rost .num_event_specs = ARRAY_SIZE(vcnl4040_als_event_spec),
184085e2c6a2SMårten Lindahl }, {
184185e2c6a2SMårten Lindahl .type = IIO_PROXIMITY,
184285e2c6a2SMårten Lindahl .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
1843add98466SAstrid Rost BIT(IIO_CHAN_INFO_INT_TIME) |
1844bb33e751SAstrid Rost BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
1845bb33e751SAstrid Rost BIT(IIO_CHAN_INFO_CALIBBIAS),
1846add98466SAstrid Rost .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) |
1847bb33e751SAstrid Rost BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
1848bb33e751SAstrid Rost BIT(IIO_CHAN_INFO_CALIBBIAS),
184985e2c6a2SMårten Lindahl .ext_info = vcnl4000_ext_info,
185054667612SMårten Lindahl .event_spec = vcnl4040_event_spec,
185154667612SMårten Lindahl .num_event_specs = ARRAY_SIZE(vcnl4040_event_spec),
185285e2c6a2SMårten Lindahl }
185385e2c6a2SMårten Lindahl };
185485e2c6a2SMårten Lindahl
185562a1efb9SPeter Meerwald static const struct iio_info vcnl4000_info = {
185662a1efb9SPeter Meerwald .read_raw = vcnl4000_read_raw,
185762a1efb9SPeter Meerwald };
185862a1efb9SPeter Meerwald
1859d35567fcSMathieu Othacehe static const struct iio_info vcnl4010_info = {
1860d35567fcSMathieu Othacehe .read_raw = vcnl4010_read_raw,
1861f6889c1bSMathieu Othacehe .read_avail = vcnl4010_read_avail,
1862f6889c1bSMathieu Othacehe .write_raw = vcnl4010_write_raw,
1863d35567fcSMathieu Othacehe .read_event_value = vcnl4010_read_event,
1864d35567fcSMathieu Othacehe .write_event_value = vcnl4010_write_event,
1865d35567fcSMathieu Othacehe .read_event_config = vcnl4010_read_event_config,
1866d35567fcSMathieu Othacehe .write_event_config = vcnl4010_write_event_config,
1867d35567fcSMathieu Othacehe };
1868d35567fcSMathieu Othacehe
186985e2c6a2SMårten Lindahl static const struct iio_info vcnl4040_info = {
187085e2c6a2SMårten Lindahl .read_raw = vcnl4000_read_raw,
187185e2c6a2SMårten Lindahl .write_raw = vcnl4040_write_raw,
187254667612SMårten Lindahl .read_event_value = vcnl4040_read_event,
187354667612SMårten Lindahl .write_event_value = vcnl4040_write_event,
187454667612SMårten Lindahl .read_event_config = vcnl4040_read_event_config,
187554667612SMårten Lindahl .write_event_config = vcnl4040_write_event_config,
187685e2c6a2SMårten Lindahl .read_avail = vcnl4040_read_avail,
187785e2c6a2SMårten Lindahl };
187885e2c6a2SMårten Lindahl
1879d35567fcSMathieu Othacehe static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
1880d35567fcSMathieu Othacehe [VCNL4000] = {
1881d35567fcSMathieu Othacehe .prod = "VCNL4000",
1882d35567fcSMathieu Othacehe .init = vcnl4000_init,
1883d35567fcSMathieu Othacehe .measure_light = vcnl4000_measure_light,
1884d35567fcSMathieu Othacehe .measure_proximity = vcnl4000_measure_proximity,
1885d35567fcSMathieu Othacehe .set_power_state = vcnl4000_set_power_state,
1886d35567fcSMathieu Othacehe .channels = vcnl4000_channels,
1887d35567fcSMathieu Othacehe .num_channels = ARRAY_SIZE(vcnl4000_channels),
1888d35567fcSMathieu Othacehe .info = &vcnl4000_info,
1889d35567fcSMathieu Othacehe },
1890d35567fcSMathieu Othacehe [VCNL4010] = {
1891d35567fcSMathieu Othacehe .prod = "VCNL4010/4020",
1892d35567fcSMathieu Othacehe .init = vcnl4000_init,
1893d35567fcSMathieu Othacehe .measure_light = vcnl4000_measure_light,
1894d35567fcSMathieu Othacehe .measure_proximity = vcnl4000_measure_proximity,
1895d35567fcSMathieu Othacehe .set_power_state = vcnl4000_set_power_state,
1896d35567fcSMathieu Othacehe .channels = vcnl4010_channels,
1897d35567fcSMathieu Othacehe .num_channels = ARRAY_SIZE(vcnl4010_channels),
1898d35567fcSMathieu Othacehe .info = &vcnl4010_info,
1899bfb6cfeeSMårten Lindahl .irq_thread = vcnl4010_irq_thread,
1900bfb6cfeeSMårten Lindahl .trig_buffer_func = vcnl4010_trigger_handler,
1901bfb6cfeeSMårten Lindahl .buffer_setup_ops = &vcnl4010_buffer_ops,
1902d35567fcSMathieu Othacehe },
1903d35567fcSMathieu Othacehe [VCNL4040] = {
1904d35567fcSMathieu Othacehe .prod = "VCNL4040",
1905d35567fcSMathieu Othacehe .init = vcnl4200_init,
1906d35567fcSMathieu Othacehe .measure_light = vcnl4200_measure_light,
1907d35567fcSMathieu Othacehe .measure_proximity = vcnl4200_measure_proximity,
1908d35567fcSMathieu Othacehe .set_power_state = vcnl4200_set_power_state,
190985e2c6a2SMårten Lindahl .channels = vcnl4040_channels,
191085e2c6a2SMårten Lindahl .num_channels = ARRAY_SIZE(vcnl4040_channels),
191185e2c6a2SMårten Lindahl .info = &vcnl4040_info,
191254667612SMårten Lindahl .irq_thread = vcnl4040_irq_thread,
1913854965b7SAstrid Rost .int_reg = VCNL4040_INT_FLAGS,
1914e55c96daSAstrid Rost .ps_it_times = &vcnl4040_ps_it_times,
1915e55c96daSAstrid Rost .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times),
1916fea2c97dSAstrid Rost .als_it_times = &vcnl4040_als_it_times,
1917fea2c97dSAstrid Rost .num_als_it_times = ARRAY_SIZE(vcnl4040_als_it_times),
1918fea2c97dSAstrid Rost .ulux_step = 100000,
1919d35567fcSMathieu Othacehe },
1920d35567fcSMathieu Othacehe [VCNL4200] = {
1921d35567fcSMathieu Othacehe .prod = "VCNL4200",
1922d35567fcSMathieu Othacehe .init = vcnl4200_init,
1923d35567fcSMathieu Othacehe .measure_light = vcnl4200_measure_light,
1924d35567fcSMathieu Othacehe .measure_proximity = vcnl4200_measure_proximity,
1925d35567fcSMathieu Othacehe .set_power_state = vcnl4200_set_power_state,
1926854965b7SAstrid Rost .channels = vcnl4040_channels,
1927d35567fcSMathieu Othacehe .num_channels = ARRAY_SIZE(vcnl4000_channels),
1928854965b7SAstrid Rost .info = &vcnl4040_info,
1929854965b7SAstrid Rost .irq_thread = vcnl4040_irq_thread,
1930854965b7SAstrid Rost .int_reg = VCNL4200_INT_FLAGS,
1931e55c96daSAstrid Rost .ps_it_times = &vcnl4200_ps_it_times,
1932e55c96daSAstrid Rost .num_ps_it_times = ARRAY_SIZE(vcnl4200_ps_it_times),
1933fea2c97dSAstrid Rost .als_it_times = &vcnl4200_als_it_times,
1934fea2c97dSAstrid Rost .num_als_it_times = ARRAY_SIZE(vcnl4200_als_it_times),
1935fea2c97dSAstrid Rost .ulux_step = 24000,
1936d35567fcSMathieu Othacehe },
1937d35567fcSMathieu Othacehe };
1938d35567fcSMathieu Othacehe
19398fe78d52SMathieu Othacehe static const struct iio_trigger_ops vcnl4010_trigger_ops = {
19408fe78d52SMathieu Othacehe .validate_device = iio_trigger_validate_own_device,
19418fe78d52SMathieu Othacehe };
19428fe78d52SMathieu Othacehe
vcnl4010_probe_trigger(struct iio_dev * indio_dev)19438fe78d52SMathieu Othacehe static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)
19448fe78d52SMathieu Othacehe {
19458fe78d52SMathieu Othacehe struct vcnl4000_data *data = iio_priv(indio_dev);
19468fe78d52SMathieu Othacehe struct i2c_client *client = data->client;
19478fe78d52SMathieu Othacehe struct iio_trigger *trigger;
19488fe78d52SMathieu Othacehe
19498fe78d52SMathieu Othacehe trigger = devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
195015ea2878SJonathan Cameron indio_dev->name,
195115ea2878SJonathan Cameron iio_device_id(indio_dev));
19528fe78d52SMathieu Othacehe if (!trigger)
19538fe78d52SMathieu Othacehe return -ENOMEM;
19548fe78d52SMathieu Othacehe
19558fe78d52SMathieu Othacehe trigger->ops = &vcnl4010_trigger_ops;
19568fe78d52SMathieu Othacehe iio_trigger_set_drvdata(trigger, indio_dev);
19578fe78d52SMathieu Othacehe
19588fe78d52SMathieu Othacehe return devm_iio_trigger_register(&client->dev, trigger);
19598fe78d52SMathieu Othacehe }
19608fe78d52SMathieu Othacehe
vcnl4000_probe(struct i2c_client * client)1961e61295e0SUwe Kleine-König static int vcnl4000_probe(struct i2c_client *client)
196262a1efb9SPeter Meerwald {
1963e61295e0SUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(client);
196462a1efb9SPeter Meerwald struct vcnl4000_data *data;
196562a1efb9SPeter Meerwald struct iio_dev *indio_dev;
19661ebc787aSTomas Novotny int ret;
196762a1efb9SPeter Meerwald
19682669d723SPeter Meerwald indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
196962a1efb9SPeter Meerwald if (!indio_dev)
197062a1efb9SPeter Meerwald return -ENOMEM;
197162a1efb9SPeter Meerwald
197262a1efb9SPeter Meerwald data = iio_priv(indio_dev);
197362a1efb9SPeter Meerwald i2c_set_clientdata(client, indio_dev);
197462a1efb9SPeter Meerwald data->client = client;
19751ebc787aSTomas Novotny data->id = id->driver_data;
19761ebc787aSTomas Novotny data->chip_spec = &vcnl4000_chip_spec_cfg[data->id];
197762a1efb9SPeter Meerwald
197842ec40b0SMårten Lindahl mutex_init(&data->vcnl4000_lock);
197942ec40b0SMårten Lindahl
19801ebc787aSTomas Novotny ret = data->chip_spec->init(data);
198162a1efb9SPeter Meerwald if (ret < 0)
19822669d723SPeter Meerwald return ret;
198362a1efb9SPeter Meerwald
1984d978bfddSPeter Meerwald-Stadler dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n",
19851ebc787aSTomas Novotny data->chip_spec->prod, data->rev);
198662a1efb9SPeter Meerwald
1987f5a98e1fSGuido Günther if (device_property_read_u32(&client->dev, "proximity-near-level",
1988f5a98e1fSGuido Günther &data->near_level))
1989f5a98e1fSGuido Günther data->near_level = 0;
1990f5a98e1fSGuido Günther
1991d35567fcSMathieu Othacehe indio_dev->info = data->chip_spec->info;
1992d35567fcSMathieu Othacehe indio_dev->channels = data->chip_spec->channels;
1993d35567fcSMathieu Othacehe indio_dev->num_channels = data->chip_spec->num_channels;
199462a1efb9SPeter Meerwald indio_dev->name = VCNL4000_DRV_NAME;
199562a1efb9SPeter Meerwald indio_dev->modes = INDIO_DIRECT_MODE;
199662a1efb9SPeter Meerwald
1997bfb6cfeeSMårten Lindahl if (data->chip_spec->trig_buffer_func &&
1998bfb6cfeeSMårten Lindahl data->chip_spec->buffer_setup_ops) {
19998fe78d52SMathieu Othacehe ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
20008fe78d52SMathieu Othacehe NULL,
2001bfb6cfeeSMårten Lindahl data->chip_spec->trig_buffer_func,
2002bfb6cfeeSMårten Lindahl data->chip_spec->buffer_setup_ops);
20038fe78d52SMathieu Othacehe if (ret < 0) {
20048fe78d52SMathieu Othacehe dev_err(&client->dev,
20058fe78d52SMathieu Othacehe "unable to setup iio triggered buffer\n");
20068fe78d52SMathieu Othacehe return ret;
20078fe78d52SMathieu Othacehe }
2008bfb6cfeeSMårten Lindahl }
20098fe78d52SMathieu Othacehe
2010bfb6cfeeSMårten Lindahl if (client->irq && data->chip_spec->irq_thread) {
2011d35567fcSMathieu Othacehe ret = devm_request_threaded_irq(&client->dev, client->irq,
2012bfb6cfeeSMårten Lindahl NULL, data->chip_spec->irq_thread,
2013d35567fcSMathieu Othacehe IRQF_TRIGGER_FALLING |
2014d35567fcSMathieu Othacehe IRQF_ONESHOT,
2015bfb6cfeeSMårten Lindahl "vcnl4000_irq",
2016d35567fcSMathieu Othacehe indio_dev);
2017d35567fcSMathieu Othacehe if (ret < 0) {
2018d35567fcSMathieu Othacehe dev_err(&client->dev, "irq request failed\n");
2019d35567fcSMathieu Othacehe return ret;
2020d35567fcSMathieu Othacehe }
20218fe78d52SMathieu Othacehe
20228fe78d52SMathieu Othacehe ret = vcnl4010_probe_trigger(indio_dev);
20238fe78d52SMathieu Othacehe if (ret < 0)
20248fe78d52SMathieu Othacehe return ret;
2025d35567fcSMathieu Othacehe }
2026d35567fcSMathieu Othacehe
20275e00708dSGuido Günther ret = pm_runtime_set_active(&client->dev);
20285e00708dSGuido Günther if (ret < 0)
20295e00708dSGuido Günther goto fail_poweroff;
20305e00708dSGuido Günther
20315e00708dSGuido Günther ret = iio_device_register(indio_dev);
20325e00708dSGuido Günther if (ret < 0)
20335e00708dSGuido Günther goto fail_poweroff;
20345e00708dSGuido Günther
20355e00708dSGuido Günther pm_runtime_enable(&client->dev);
20365e00708dSGuido Günther pm_runtime_set_autosuspend_delay(&client->dev, VCNL4000_SLEEP_DELAY_MS);
20375e00708dSGuido Günther pm_runtime_use_autosuspend(&client->dev);
20385e00708dSGuido Günther
20395e00708dSGuido Günther return 0;
20405e00708dSGuido Günther fail_poweroff:
20415e00708dSGuido Günther data->chip_spec->set_power_state(data, false);
20425e00708dSGuido Günther return ret;
204362a1efb9SPeter Meerwald }
204462a1efb9SPeter Meerwald
2045ebd457d5SAngus Ainslie (Purism) static const struct of_device_id vcnl_4000_of_match[] = {
2046ebd457d5SAngus Ainslie (Purism) {
2047ebd457d5SAngus Ainslie (Purism) .compatible = "vishay,vcnl4000",
20481436a78cSMarco Felsch .data = (void *)VCNL4000,
2049ebd457d5SAngus Ainslie (Purism) },
2050ebd457d5SAngus Ainslie (Purism) {
2051ebd457d5SAngus Ainslie (Purism) .compatible = "vishay,vcnl4010",
20521436a78cSMarco Felsch .data = (void *)VCNL4010,
2053ebd457d5SAngus Ainslie (Purism) },
2054ebd457d5SAngus Ainslie (Purism) {
20551436a78cSMarco Felsch .compatible = "vishay,vcnl4020",
20561436a78cSMarco Felsch .data = (void *)VCNL4010,
2057ebd457d5SAngus Ainslie (Purism) },
2058ebd457d5SAngus Ainslie (Purism) {
20597fd1c260SMarco Felsch .compatible = "vishay,vcnl4040",
20607fd1c260SMarco Felsch .data = (void *)VCNL4040,
20617fd1c260SMarco Felsch },
20627fd1c260SMarco Felsch {
2063ebd457d5SAngus Ainslie (Purism) .compatible = "vishay,vcnl4200",
20641436a78cSMarco Felsch .data = (void *)VCNL4200,
2065ebd457d5SAngus Ainslie (Purism) },
2066ebd457d5SAngus Ainslie (Purism) {},
2067ebd457d5SAngus Ainslie (Purism) };
2068ebd457d5SAngus Ainslie (Purism) MODULE_DEVICE_TABLE(of, vcnl_4000_of_match);
2069ebd457d5SAngus Ainslie (Purism)
vcnl4000_remove(struct i2c_client * client)2070ed5c2f5fSUwe Kleine-König static void vcnl4000_remove(struct i2c_client *client)
20715e00708dSGuido Günther {
20725e00708dSGuido Günther struct iio_dev *indio_dev = i2c_get_clientdata(client);
20735e00708dSGuido Günther struct vcnl4000_data *data = iio_priv(indio_dev);
2074ab91da2fSUwe Kleine-König int ret;
20755e00708dSGuido Günther
20765e00708dSGuido Günther pm_runtime_dont_use_autosuspend(&client->dev);
20775e00708dSGuido Günther pm_runtime_disable(&client->dev);
20785e00708dSGuido Günther iio_device_unregister(indio_dev);
20795e00708dSGuido Günther pm_runtime_set_suspended(&client->dev);
20805e00708dSGuido Günther
2081ab91da2fSUwe Kleine-König ret = data->chip_spec->set_power_state(data, false);
2082ab91da2fSUwe Kleine-König if (ret)
2083ab91da2fSUwe Kleine-König dev_warn(&client->dev, "Failed to power down (%pe)\n",
2084ab91da2fSUwe Kleine-König ERR_PTR(ret));
20855e00708dSGuido Günther }
20865e00708dSGuido Günther
vcnl4000_runtime_suspend(struct device * dev)2087cd4d10b1SJonathan Cameron static int vcnl4000_runtime_suspend(struct device *dev)
20885e00708dSGuido Günther {
20895e00708dSGuido Günther struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
20905e00708dSGuido Günther struct vcnl4000_data *data = iio_priv(indio_dev);
20915e00708dSGuido Günther
20925e00708dSGuido Günther return data->chip_spec->set_power_state(data, false);
20935e00708dSGuido Günther }
20945e00708dSGuido Günther
vcnl4000_runtime_resume(struct device * dev)2095cd4d10b1SJonathan Cameron static int vcnl4000_runtime_resume(struct device *dev)
20965e00708dSGuido Günther {
20975e00708dSGuido Günther struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
20985e00708dSGuido Günther struct vcnl4000_data *data = iio_priv(indio_dev);
20995e00708dSGuido Günther
21005e00708dSGuido Günther return data->chip_spec->set_power_state(data, true);
21015e00708dSGuido Günther }
21025e00708dSGuido Günther
2103cd4d10b1SJonathan Cameron static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4000_pm_ops, vcnl4000_runtime_suspend,
2104cd4d10b1SJonathan Cameron vcnl4000_runtime_resume, NULL);
21055e00708dSGuido Günther
210662a1efb9SPeter Meerwald static struct i2c_driver vcnl4000_driver = {
210762a1efb9SPeter Meerwald .driver = {
210862a1efb9SPeter Meerwald .name = VCNL4000_DRV_NAME,
2109cd4d10b1SJonathan Cameron .pm = pm_ptr(&vcnl4000_pm_ops),
2110ebd457d5SAngus Ainslie (Purism) .of_match_table = vcnl_4000_of_match,
211162a1efb9SPeter Meerwald },
21127cf15f42SUwe Kleine-König .probe = vcnl4000_probe,
211362a1efb9SPeter Meerwald .id_table = vcnl4000_id,
21145e00708dSGuido Günther .remove = vcnl4000_remove,
211562a1efb9SPeter Meerwald };
211662a1efb9SPeter Meerwald
211762a1efb9SPeter Meerwald module_i2c_driver(vcnl4000_driver);
211862a1efb9SPeter Meerwald
211962a1efb9SPeter Meerwald MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
21208fe78d52SMathieu Othacehe MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
212162a1efb9SPeter Meerwald MODULE_DESCRIPTION("Vishay VCNL4000 proximity/ambient light sensor driver");
212262a1efb9SPeter Meerwald MODULE_LICENSE("GPL");
2123