Skip to content

Commit be38866

Browse files
stoupa-czjic23
authored andcommitted
iio: vcnl4000: add support for VCNL4200
VCNL4200 is an integrated long distance (up to 1500mm) proximity and ambient light sensor. The support is very basic. There is no configuration of proximity and ambient light sensing yet. Only the reading of both measured values is done. The reading of ambient light and proximity values is blocking. If you request a new value too early, the driver waits for new value to be ready. Signed-off-by: Tomas Novotny <[email protected]> Signed-off-by: Jonathan Cameron <[email protected]>
1 parent 58bf9ac commit be38866

File tree

2 files changed

+109
-10
lines changed

2 files changed

+109
-10
lines changed

drivers/iio/light/Kconfig

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,11 +450,12 @@ config US5182D
450450
will be called us5182d.
451451

452452
config VCNL4000
453-
tristate "VCNL4000/4010/4020 combined ALS and proximity sensor"
453+
tristate "VCNL4000/4010/4020/4200 combined ALS and proximity sensor"
454454
depends on I2C
455455
help
456456
Say Y here if you want to build a driver for the Vishay VCNL4000,
457-
VCNL4010, VCNL4020 combined ambient light and proximity sensor.
457+
VCNL4010, VCNL4020, VCNL4200 combined ambient light and proximity
458+
sensor.
458459

459460
To compile this driver as a module, choose M here: the
460461
module will be called vcnl4000.

drivers/iio/light/vcnl4000.c

Lines changed: 106 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* vcnl4000.c - Support for Vishay VCNL4000/4010/4020 combined ambient
2+
* vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4200 combined ambient
33
* light and proximity sensor
44
*
55
* Copyright 2012 Peter Meerwald <[email protected]>
@@ -8,13 +8,15 @@
88
* the GNU General Public License. See the file COPYING in the main
99
* directory of this archive for more details.
1010
*
11-
* IIO driver for VCNL4000 (7-bit I2C slave address 0x13)
11+
* IIO driver for:
12+
* VCNL4000/10/20 (7-bit I2C slave address 0x13)
13+
* VCNL4200 (7-bit I2C slave address 0x51)
1214
*
1315
* TODO:
1416
* allow to adjust IR current
1517
* proximity threshold and event handling
1618
* periodic ALS/proximity measurement (VCNL4010/20)
17-
* interrupts (VCNL4010/20)
19+
* interrupts (VCNL4010/20, VCNL4200)
1820
*/
1921

2022
#include <linux/module.h>
@@ -28,6 +30,7 @@
2830
#define VCNL4000_DRV_NAME "vcnl4000"
2931
#define VCNL4000_PROD_ID 0x01
3032
#define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */
33+
#define VCNL4200_PROD_ID 0x58
3134

3235
#define VCNL4000_COMMAND 0x80 /* Command register */
3336
#define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */
@@ -40,6 +43,12 @@
4043
#define VCNL4000_PS_MEAS_FREQ 0x89 /* Proximity test signal frequency */
4144
#define VCNL4000_PS_MOD_ADJ 0x8a /* Proximity modulator timing adjustment */
4245

46+
#define VCNL4200_AL_CONF 0x00 /* Ambient light configuration */
47+
#define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */
48+
#define VCNL4200_PS_DATA 0x08 /* Proximity data */
49+
#define VCNL4200_AL_DATA 0x09 /* Ambient light data */
50+
#define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */
51+
4352
/* Bit masks for COMMAND register */
4453
#define VCNL4000_AL_RDY BIT(6) /* ALS data ready? */
4554
#define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */
@@ -49,6 +58,14 @@
4958
enum vcnl4000_device_ids {
5059
VCNL4000,
5160
VCNL4010,
61+
VCNL4200,
62+
};
63+
64+
struct vcnl4200_channel {
65+
u8 reg;
66+
ktime_t last_measurement;
67+
ktime_t sampling_rate;
68+
struct mutex lock;
5269
};
5370

5471
struct vcnl4000_data {
@@ -57,7 +74,9 @@ struct vcnl4000_data {
5774
int rev;
5875
int al_scale;
5976
const struct vcnl4000_chip_spec *chip_spec;
60-
struct mutex lock;
77+
struct mutex vcnl4000_lock;
78+
struct vcnl4200_channel vcnl4200_al;
79+
struct vcnl4200_channel vcnl4200_ps;
6180
};
6281

6382
struct vcnl4000_chip_spec {
@@ -71,6 +90,7 @@ static const struct i2c_device_id vcnl4000_id[] = {
7190
{ "vcnl4000", VCNL4000 },
7291
{ "vcnl4010", VCNL4010 },
7392
{ "vcnl4020", VCNL4010 },
93+
{ "vcnl4200", VCNL4200 },
7494
{ }
7595
};
7696
MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
@@ -101,6 +121,42 @@ static int vcnl4000_init(struct vcnl4000_data *data)
101121

102122
data->rev = ret & 0xf;
103123
data->al_scale = 250000;
124+
mutex_init(&data->vcnl4000_lock);
125+
126+
return 0;
127+
};
128+
129+
static int vcnl4200_init(struct vcnl4000_data *data)
130+
{
131+
int ret;
132+
133+
ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
134+
if (ret < 0)
135+
return ret;
136+
137+
if ((ret & 0xff) != VCNL4200_PROD_ID)
138+
return -ENODEV;
139+
140+
data->rev = (ret >> 8) & 0xf;
141+
142+
/* Set defaults and enable both channels */
143+
ret = i2c_smbus_write_byte_data(data->client, VCNL4200_AL_CONF, 0x00);
144+
if (ret < 0)
145+
return ret;
146+
ret = i2c_smbus_write_byte_data(data->client, VCNL4200_PS_CONF1, 0x00);
147+
if (ret < 0)
148+
return ret;
149+
150+
data->al_scale = 24000;
151+
data->vcnl4200_al.reg = VCNL4200_AL_DATA;
152+
data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
153+
/* Integration time is 50ms, but the experiments show 54ms in total. */
154+
data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000);
155+
data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000);
156+
data->vcnl4200_al.last_measurement = ktime_set(0, 0);
157+
data->vcnl4200_ps.last_measurement = ktime_set(0, 0);
158+
mutex_init(&data->vcnl4200_al.lock);
159+
mutex_init(&data->vcnl4200_ps.lock);
104160

105161
return 0;
106162
};
@@ -112,7 +168,7 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
112168
__be16 buf;
113169
int ret;
114170

115-
mutex_lock(&data->lock);
171+
mutex_lock(&data->vcnl4000_lock);
116172

117173
ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
118174
req_mask);
@@ -141,30 +197,67 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
141197
if (ret < 0)
142198
goto fail;
143199

144-
mutex_unlock(&data->lock);
200+
mutex_unlock(&data->vcnl4000_lock);
145201
*val = be16_to_cpu(buf);
146202

147203
return 0;
148204

149205
fail:
150-
mutex_unlock(&data->lock);
206+
mutex_unlock(&data->vcnl4000_lock);
151207
return ret;
152208
}
153209

210+
static int vcnl4200_measure(struct vcnl4000_data *data,
211+
struct vcnl4200_channel *chan, int *val)
212+
{
213+
int ret;
214+
s64 delta;
215+
ktime_t next_measurement;
216+
217+
mutex_lock(&chan->lock);
218+
219+
next_measurement = ktime_add(chan->last_measurement,
220+
chan->sampling_rate);
221+
delta = ktime_us_delta(next_measurement, ktime_get());
222+
if (delta > 0)
223+
usleep_range(delta, delta + 500);
224+
chan->last_measurement = ktime_get();
225+
226+
mutex_unlock(&chan->lock);
227+
228+
ret = i2c_smbus_read_word_data(data->client, chan->reg);
229+
if (ret < 0)
230+
return ret;
231+
232+
*val = ret;
233+
234+
return 0;
235+
}
236+
154237
static int vcnl4000_measure_light(struct vcnl4000_data *data, int *val)
155238
{
156239
return vcnl4000_measure(data,
157240
VCNL4000_AL_OD, VCNL4000_AL_RDY,
158241
VCNL4000_AL_RESULT_HI, val);
159242
}
160243

244+
static int vcnl4200_measure_light(struct vcnl4000_data *data, int *val)
245+
{
246+
return vcnl4200_measure(data, &data->vcnl4200_al, val);
247+
}
248+
161249
static int vcnl4000_measure_proximity(struct vcnl4000_data *data, int *val)
162250
{
163251
return vcnl4000_measure(data,
164252
VCNL4000_PS_OD, VCNL4000_PS_RDY,
165253
VCNL4000_PS_RESULT_HI, val);
166254
}
167255

256+
static int vcnl4200_measure_proximity(struct vcnl4000_data *data, int *val)
257+
{
258+
return vcnl4200_measure(data, &data->vcnl4200_ps, val);
259+
}
260+
168261
static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
169262
[VCNL4000] = {
170263
.prod = "VCNL4000",
@@ -178,6 +271,12 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
178271
.measure_light = vcnl4000_measure_light,
179272
.measure_proximity = vcnl4000_measure_proximity,
180273
},
274+
[VCNL4200] = {
275+
.prod = "VCNL4200",
276+
.init = vcnl4200_init,
277+
.measure_light = vcnl4200_measure_light,
278+
.measure_proximity = vcnl4200_measure_proximity,
279+
},
181280
};
182281

183282
static const struct iio_chan_spec vcnl4000_channels[] = {
@@ -246,7 +345,6 @@ static int vcnl4000_probe(struct i2c_client *client,
246345
data->client = client;
247346
data->id = id->driver_data;
248347
data->chip_spec = &vcnl4000_chip_spec_cfg[data->id];
249-
mutex_init(&data->lock);
250348

251349
ret = data->chip_spec->init(data);
252350
if (ret < 0)

0 commit comments

Comments
 (0)