xref: /linux/drivers/iio/light/veml6075.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Vishay VEML6075 UVA and UVB light sensor
4  *
5  * Copyright 2023 Javier Carrasco <javier.carrasco.cruz@gmail.com>
6  *
7  * 7-bit I2C slave, address 0x10
8  */
9 
10 #include <linux/bitfield.h>
11 #include <linux/delay.h>
12 #include <linux/err.h>
13 #include <linux/i2c.h>
14 #include <linux/module.h>
15 #include <linux/mutex.h>
16 #include <linux/regmap.h>
17 #include <linux/units.h>
18 
19 #include <linux/iio/iio.h>
20 
21 #define VEML6075_CMD_CONF	0x00 /* configuration register */
22 #define VEML6075_CMD_UVA	0x07 /* UVA channel */
23 #define VEML6075_CMD_UVB	0x09 /* UVB channel */
24 #define VEML6075_CMD_COMP1	0x0A /* visible light compensation */
25 #define VEML6075_CMD_COMP2	0x0B /* infrarred light compensation */
26 #define VEML6075_CMD_ID		0x0C /* device ID */
27 
28 #define VEML6075_CONF_IT	GENMASK(6, 4) /* intregration time */
29 #define VEML6075_CONF_HD	BIT(3) /* dynamic setting */
30 #define VEML6075_CONF_TRIG	BIT(2) /* trigger */
31 #define VEML6075_CONF_AF	BIT(1) /* active force enable */
32 #define VEML6075_CONF_SD	BIT(0) /* shutdown */
33 
34 #define VEML6075_IT_50_MS	0x00
35 #define VEML6075_IT_100_MS	0x01
36 #define VEML6075_IT_200_MS	0x02
37 #define VEML6075_IT_400_MS	0x03
38 #define VEML6075_IT_800_MS	0x04
39 
40 #define VEML6075_AF_DISABLE	0x00
41 #define VEML6075_AF_ENABLE	0x01
42 
43 #define VEML6075_SD_DISABLE	0x00
44 #define VEML6075_SD_ENABLE	0x01
45 
46 /* Open-air coefficients and responsivity */
47 #define VEML6075_A_COEF		2220
48 #define VEML6075_B_COEF		1330
49 #define VEML6075_C_COEF		2950
50 #define VEML6075_D_COEF		1740
51 #define VEML6075_UVA_RESP	1461
52 #define VEML6075_UVB_RESP	2591
53 
54 static const int veml6075_it_ms[] = { 50, 100, 200, 400, 800 };
55 
56 struct veml6075_data {
57 	struct i2c_client *client;
58 	struct regmap *regmap;
59 	/*
60 	 * prevent integration time modification and triggering
61 	 * measurements while a measurement is underway.
62 	 */
63 	struct mutex lock;
64 };
65 
66 /* channel number */
67 enum veml6075_chan {
68 	CH_UVA,
69 	CH_UVB,
70 };
71 
72 static const struct iio_chan_spec veml6075_channels[] = {
73 	{
74 		.type = IIO_INTENSITY,
75 		.channel = CH_UVA,
76 		.modified = 1,
77 		.channel2 = IIO_MOD_LIGHT_UVA,
78 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
79 			BIT(IIO_CHAN_INFO_SCALE),
80 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
81 		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
82 	},
83 	{
84 		.type = IIO_INTENSITY,
85 		.channel = CH_UVB,
86 		.modified = 1,
87 		.channel2 = IIO_MOD_LIGHT_UVB,
88 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
89 			BIT(IIO_CHAN_INFO_SCALE),
90 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
91 		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
92 	},
93 	{
94 		.type = IIO_UVINDEX,
95 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
96 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
97 		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
98 	},
99 };
100 
veml6075_request_measurement(struct veml6075_data * data)101 static int veml6075_request_measurement(struct veml6075_data *data)
102 {
103 	int ret, conf, int_time;
104 
105 	ret = regmap_read(data->regmap, VEML6075_CMD_CONF, &conf);
106 	if (ret < 0)
107 		return ret;
108 
109 	/* disable shutdown and trigger measurement */
110 	ret = regmap_write(data->regmap, VEML6075_CMD_CONF,
111 			   (conf | VEML6075_CONF_TRIG) & ~VEML6075_CONF_SD);
112 	if (ret < 0)
113 		return ret;
114 
115 	/*
116 	 * A measurement requires between 1.30 and 1.40 times the integration
117 	 * time for all possible configurations. Using a 1.50 factor simplifies
118 	 * operations and ensures reliability under all circumstances.
119 	 */
120 	int_time = veml6075_it_ms[FIELD_GET(VEML6075_CONF_IT, conf)];
121 	msleep(int_time + (int_time / 2));
122 
123 	/* shutdown again, data registers are still accessible */
124 	return regmap_update_bits(data->regmap, VEML6075_CMD_CONF,
125 				  VEML6075_CONF_SD, VEML6075_CONF_SD);
126 }
127 
veml6075_uva_comp(int raw_uva,int comp1,int comp2)128 static int veml6075_uva_comp(int raw_uva, int comp1, int comp2)
129 {
130 	int comp1a_c, comp2a_c, uva_comp;
131 
132 	comp1a_c = (comp1 * VEML6075_A_COEF) / 1000U;
133 	comp2a_c = (comp2 * VEML6075_B_COEF) / 1000U;
134 	uva_comp = raw_uva - comp1a_c - comp2a_c;
135 
136 	return clamp_val(uva_comp, 0, U16_MAX);
137 }
138 
veml6075_uvb_comp(int raw_uvb,int comp1,int comp2)139 static int veml6075_uvb_comp(int raw_uvb, int comp1, int comp2)
140 {
141 	int comp1b_c, comp2b_c, uvb_comp;
142 
143 	comp1b_c = (comp1 * VEML6075_C_COEF) / 1000U;
144 	comp2b_c = (comp2 * VEML6075_D_COEF) / 1000U;
145 	uvb_comp = raw_uvb - comp1b_c - comp2b_c;
146 
147 	return clamp_val(uvb_comp, 0, U16_MAX);
148 }
149 
veml6075_read_comp(struct veml6075_data * data,int * c1,int * c2)150 static int veml6075_read_comp(struct veml6075_data *data, int *c1, int *c2)
151 {
152 	int ret;
153 
154 	ret = regmap_read(data->regmap, VEML6075_CMD_COMP1, c1);
155 	if (ret < 0)
156 		return ret;
157 
158 	return regmap_read(data->regmap, VEML6075_CMD_COMP2, c2);
159 }
160 
veml6075_read_uv_direct(struct veml6075_data * data,int chan,int * val)161 static int veml6075_read_uv_direct(struct veml6075_data *data, int chan,
162 				   int *val)
163 {
164 	int c1, c2, ret;
165 
166 	guard(mutex)(&data->lock);
167 
168 	ret = veml6075_request_measurement(data);
169 	if (ret < 0)
170 		return ret;
171 
172 	ret = veml6075_read_comp(data, &c1, &c2);
173 	if (ret < 0)
174 		return ret;
175 
176 	switch (chan) {
177 	case CH_UVA:
178 		ret = regmap_read(data->regmap, VEML6075_CMD_UVA, val);
179 		if (ret < 0)
180 			return ret;
181 
182 		*val = veml6075_uva_comp(*val, c1, c2);
183 		return IIO_VAL_INT;
184 	case CH_UVB:
185 		ret = regmap_read(data->regmap, VEML6075_CMD_UVB, val);
186 		if (ret < 0)
187 			return ret;
188 
189 		*val = veml6075_uvb_comp(*val, c1, c2);
190 		return IIO_VAL_INT;
191 	default:
192 		return -EINVAL;
193 	}
194 }
195 
veml6075_read_int_time_index(struct veml6075_data * data)196 static int veml6075_read_int_time_index(struct veml6075_data *data)
197 {
198 	int ret, conf;
199 
200 	ret = regmap_read(data->regmap, VEML6075_CMD_CONF, &conf);
201 	if (ret < 0)
202 		return ret;
203 
204 	return FIELD_GET(VEML6075_CONF_IT, conf);
205 }
206 
veml6075_read_int_time_ms(struct veml6075_data * data,int * val)207 static int veml6075_read_int_time_ms(struct veml6075_data *data, int *val)
208 {
209 	int int_index;
210 
211 	guard(mutex)(&data->lock);
212 	int_index = veml6075_read_int_time_index(data);
213 	if (int_index < 0)
214 		return int_index;
215 
216 	*val = veml6075_it_ms[int_index];
217 
218 	return IIO_VAL_INT;
219 }
220 
veml6075_get_uvi_micro(struct veml6075_data * data,int uva_comp,int uvb_comp)221 static int veml6075_get_uvi_micro(struct veml6075_data *data, int uva_comp,
222 				  int uvb_comp)
223 {
224 	int uvia_micro = uva_comp * VEML6075_UVA_RESP;
225 	int uvib_micro = uvb_comp * VEML6075_UVB_RESP;
226 	int int_index;
227 
228 	int_index = veml6075_read_int_time_index(data);
229 	if (int_index < 0)
230 		return int_index;
231 
232 	switch (int_index) {
233 	case VEML6075_IT_50_MS:
234 		return uvia_micro + uvib_micro;
235 	case VEML6075_IT_100_MS:
236 	case VEML6075_IT_200_MS:
237 	case VEML6075_IT_400_MS:
238 	case VEML6075_IT_800_MS:
239 		return (uvia_micro + uvib_micro) / (2 << int_index);
240 	default:
241 		return -EINVAL;
242 	}
243 }
244 
veml6075_read_uvi(struct veml6075_data * data,int * val,int * val2)245 static int veml6075_read_uvi(struct veml6075_data *data, int *val, int *val2)
246 {
247 	int ret, c1, c2, uva, uvb, uvi_micro;
248 
249 	guard(mutex)(&data->lock);
250 
251 	ret = veml6075_request_measurement(data);
252 	if (ret < 0)
253 		return ret;
254 
255 	ret = veml6075_read_comp(data, &c1, &c2);
256 	if (ret < 0)
257 		return ret;
258 
259 	ret = regmap_read(data->regmap, VEML6075_CMD_UVA, &uva);
260 	if (ret < 0)
261 		return ret;
262 
263 	ret = regmap_read(data->regmap, VEML6075_CMD_UVB, &uvb);
264 	if (ret < 0)
265 		return ret;
266 
267 	uvi_micro = veml6075_get_uvi_micro(data, veml6075_uva_comp(uva, c1, c2),
268 					   veml6075_uvb_comp(uvb, c1, c2));
269 	if (uvi_micro < 0)
270 		return uvi_micro;
271 
272 	*val = uvi_micro / MICRO;
273 	*val2 = uvi_micro % MICRO;
274 
275 	return IIO_VAL_INT_PLUS_MICRO;
276 }
277 
veml6075_read_responsivity(int chan,int * val,int * val2)278 static int veml6075_read_responsivity(int chan, int *val, int *val2)
279 {
280 	/* scale = 1 / resp */
281 	switch (chan) {
282 	case CH_UVA:
283 		/* resp = 0.93 c/uW/cm2: scale = 1.75268817 */
284 		*val = 1;
285 		*val2 = 75268817;
286 		return IIO_VAL_INT_PLUS_NANO;
287 	case CH_UVB:
288 		/* resp = 2.1 c/uW/cm2: scale = 0.476190476 */
289 		*val = 0;
290 		*val2 = 476190476;
291 		return IIO_VAL_INT_PLUS_NANO;
292 	default:
293 		return -EINVAL;
294 	}
295 }
296 
veml6075_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)297 static int veml6075_read_avail(struct iio_dev *indio_dev,
298 			       struct iio_chan_spec const *chan,
299 			       const int **vals, int *type, int *length,
300 			       long mask)
301 {
302 	switch (mask) {
303 	case IIO_CHAN_INFO_INT_TIME:
304 		*length = ARRAY_SIZE(veml6075_it_ms);
305 		*vals = veml6075_it_ms;
306 		*type = IIO_VAL_INT;
307 		return IIO_AVAIL_LIST;
308 
309 	default:
310 		return -EINVAL;
311 	}
312 }
313 
veml6075_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)314 static int veml6075_read_raw(struct iio_dev *indio_dev,
315 			     struct iio_chan_spec const *chan,
316 			     int *val, int *val2, long mask)
317 {
318 	struct veml6075_data *data = iio_priv(indio_dev);
319 
320 	switch (mask) {
321 	case IIO_CHAN_INFO_RAW:
322 		return veml6075_read_uv_direct(data, chan->channel, val);
323 	case IIO_CHAN_INFO_PROCESSED:
324 		return veml6075_read_uvi(data, val, val2);
325 	case IIO_CHAN_INFO_INT_TIME:
326 		return veml6075_read_int_time_ms(data, val);
327 	case IIO_CHAN_INFO_SCALE:
328 		return veml6075_read_responsivity(chan->channel, val, val2);
329 	default:
330 		return -EINVAL;
331 	}
332 }
333 
veml6075_write_int_time_ms(struct veml6075_data * data,int val)334 static int veml6075_write_int_time_ms(struct veml6075_data *data, int val)
335 {
336 	int i = ARRAY_SIZE(veml6075_it_ms);
337 
338 	guard(mutex)(&data->lock);
339 
340 	while (i-- > 0) {
341 		if (val == veml6075_it_ms[i])
342 			break;
343 	}
344 	if (i < 0)
345 		return -EINVAL;
346 
347 	return regmap_update_bits(data->regmap, VEML6075_CMD_CONF,
348 				  VEML6075_CONF_IT,
349 				  FIELD_PREP(VEML6075_CONF_IT, i));
350 }
351 
veml6075_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)352 static int veml6075_write_raw(struct iio_dev *indio_dev,
353 			      struct iio_chan_spec const *chan,
354 			      int val, int val2, long mask)
355 {
356 	struct veml6075_data *data = iio_priv(indio_dev);
357 
358 	switch (mask) {
359 	case IIO_CHAN_INFO_INT_TIME:
360 		return veml6075_write_int_time_ms(data, val);
361 	default:
362 		return -EINVAL;
363 	}
364 }
365 
366 static const struct iio_info veml6075_info = {
367 	.read_avail = veml6075_read_avail,
368 	.read_raw = veml6075_read_raw,
369 	.write_raw = veml6075_write_raw,
370 };
371 
veml6075_readable_reg(struct device * dev,unsigned int reg)372 static bool veml6075_readable_reg(struct device *dev, unsigned int reg)
373 {
374 	switch (reg) {
375 	case VEML6075_CMD_CONF:
376 	case VEML6075_CMD_UVA:
377 	case VEML6075_CMD_UVB:
378 	case VEML6075_CMD_COMP1:
379 	case VEML6075_CMD_COMP2:
380 	case VEML6075_CMD_ID:
381 		return true;
382 	default:
383 		return false;
384 	}
385 }
386 
veml6075_writable_reg(struct device * dev,unsigned int reg)387 static bool veml6075_writable_reg(struct device *dev, unsigned int reg)
388 {
389 	switch (reg) {
390 	case VEML6075_CMD_CONF:
391 		return true;
392 	default:
393 		return false;
394 	}
395 }
396 
397 static const struct regmap_config veml6075_regmap_config = {
398 	.name = "veml6075",
399 	.reg_bits = 8,
400 	.val_bits = 16,
401 	.max_register = VEML6075_CMD_ID,
402 	.readable_reg = veml6075_readable_reg,
403 	.writeable_reg = veml6075_writable_reg,
404 	.val_format_endian = REGMAP_ENDIAN_LITTLE,
405 };
406 
veml6075_probe(struct i2c_client * client)407 static int veml6075_probe(struct i2c_client *client)
408 {
409 	struct veml6075_data *data;
410 	struct iio_dev *indio_dev;
411 	struct regmap *regmap;
412 	int config, ret;
413 
414 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
415 	if (!indio_dev)
416 		return -ENOMEM;
417 
418 	regmap = devm_regmap_init_i2c(client, &veml6075_regmap_config);
419 	if (IS_ERR(regmap))
420 		return PTR_ERR(regmap);
421 
422 	data = iio_priv(indio_dev);
423 	data->client = client;
424 	data->regmap = regmap;
425 
426 	mutex_init(&data->lock);
427 
428 	indio_dev->name = "veml6075";
429 	indio_dev->info = &veml6075_info;
430 	indio_dev->channels = veml6075_channels;
431 	indio_dev->num_channels = ARRAY_SIZE(veml6075_channels);
432 	indio_dev->modes = INDIO_DIRECT_MODE;
433 
434 	ret = devm_regulator_get_enable(&client->dev, "vdd");
435 	if (ret < 0)
436 		return ret;
437 
438 	/* default: 100ms integration time, active force enable, shutdown */
439 	config = FIELD_PREP(VEML6075_CONF_IT, VEML6075_IT_100_MS) |
440 		FIELD_PREP(VEML6075_CONF_AF, VEML6075_AF_ENABLE) |
441 		FIELD_PREP(VEML6075_CONF_SD, VEML6075_SD_ENABLE);
442 	ret = regmap_write(data->regmap, VEML6075_CMD_CONF, config);
443 	if (ret < 0)
444 		return ret;
445 
446 	return devm_iio_device_register(&client->dev, indio_dev);
447 }
448 
449 static const struct i2c_device_id veml6075_id[] = {
450 	{ "veml6075" },
451 	{ }
452 };
453 MODULE_DEVICE_TABLE(i2c, veml6075_id);
454 
455 static const struct of_device_id veml6075_of_match[] = {
456 	{ .compatible = "vishay,veml6075" },
457 	{}
458 };
459 MODULE_DEVICE_TABLE(of, veml6075_of_match);
460 
461 static struct i2c_driver veml6075_driver = {
462 	.driver = {
463 		.name   = "veml6075",
464 		.of_match_table = veml6075_of_match,
465 	},
466 	.probe = veml6075_probe,
467 	.id_table = veml6075_id,
468 };
469 
470 module_i2c_driver(veml6075_driver);
471 
472 MODULE_AUTHOR("Javier Carrasco <javier.carrasco.cruz@gmail.com>");
473 MODULE_DESCRIPTION("Vishay VEML6075 UVA and UVB light sensor driver");
474 MODULE_LICENSE("GPL");
475