1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Vishay VEML6075 UVA and UVB light sensor
4 *
5 * Copyright 2023 Javier Carrasco <[email protected]>
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, int_index;
199
200 ret = regmap_read(data->regmap, VEML6075_CMD_CONF, &conf);
201 if (ret < 0)
202 return ret;
203
204 int_index = FIELD_GET(VEML6075_CONF_IT, conf);
205 if (int_index >= ARRAY_SIZE(veml6075_it_ms))
206 return -EINVAL;
207
208 return int_index;
209 }
210
veml6075_read_int_time_ms(struct veml6075_data * data,int * val)211 static int veml6075_read_int_time_ms(struct veml6075_data *data, int *val)
212 {
213 int int_index;
214
215 guard(mutex)(&data->lock);
216 int_index = veml6075_read_int_time_index(data);
217 if (int_index < 0)
218 return int_index;
219
220 *val = veml6075_it_ms[int_index];
221
222 return IIO_VAL_INT;
223 }
224
veml6075_get_uvi_micro(struct veml6075_data * data,int uva_comp,int uvb_comp)225 static int veml6075_get_uvi_micro(struct veml6075_data *data, int uva_comp,
226 int uvb_comp)
227 {
228 int uvia_micro = uva_comp * VEML6075_UVA_RESP;
229 int uvib_micro = uvb_comp * VEML6075_UVB_RESP;
230 int int_index;
231
232 int_index = veml6075_read_int_time_index(data);
233 if (int_index < 0)
234 return int_index;
235
236 switch (int_index) {
237 case VEML6075_IT_50_MS:
238 return uvia_micro + uvib_micro;
239 case VEML6075_IT_100_MS:
240 case VEML6075_IT_200_MS:
241 case VEML6075_IT_400_MS:
242 case VEML6075_IT_800_MS:
243 return (uvia_micro + uvib_micro) / (2 << int_index);
244 default:
245 return -EINVAL;
246 }
247 }
248
veml6075_read_uvi(struct veml6075_data * data,int * val,int * val2)249 static int veml6075_read_uvi(struct veml6075_data *data, int *val, int *val2)
250 {
251 int ret, c1, c2, uva, uvb, uvi_micro;
252
253 guard(mutex)(&data->lock);
254
255 ret = veml6075_request_measurement(data);
256 if (ret < 0)
257 return ret;
258
259 ret = veml6075_read_comp(data, &c1, &c2);
260 if (ret < 0)
261 return ret;
262
263 ret = regmap_read(data->regmap, VEML6075_CMD_UVA, &uva);
264 if (ret < 0)
265 return ret;
266
267 ret = regmap_read(data->regmap, VEML6075_CMD_UVB, &uvb);
268 if (ret < 0)
269 return ret;
270
271 uvi_micro = veml6075_get_uvi_micro(data, veml6075_uva_comp(uva, c1, c2),
272 veml6075_uvb_comp(uvb, c1, c2));
273 if (uvi_micro < 0)
274 return uvi_micro;
275
276 *val = uvi_micro / MICRO;
277 *val2 = uvi_micro % MICRO;
278
279 return IIO_VAL_INT_PLUS_MICRO;
280 }
281
veml6075_read_responsivity(int chan,int * val,int * val2)282 static int veml6075_read_responsivity(int chan, int *val, int *val2)
283 {
284 /* scale = 1 / resp */
285 switch (chan) {
286 case CH_UVA:
287 /* resp = 0.93 c/uW/cm2: scale = 1.75268817 */
288 *val = 1;
289 *val2 = 75268817;
290 return IIO_VAL_INT_PLUS_NANO;
291 case CH_UVB:
292 /* resp = 2.1 c/uW/cm2: scale = 0.476190476 */
293 *val = 0;
294 *val2 = 476190476;
295 return IIO_VAL_INT_PLUS_NANO;
296 default:
297 return -EINVAL;
298 }
299 }
300
veml6075_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)301 static int veml6075_read_avail(struct iio_dev *indio_dev,
302 struct iio_chan_spec const *chan,
303 const int **vals, int *type, int *length,
304 long mask)
305 {
306 switch (mask) {
307 case IIO_CHAN_INFO_INT_TIME:
308 *length = ARRAY_SIZE(veml6075_it_ms);
309 *vals = veml6075_it_ms;
310 *type = IIO_VAL_INT;
311 return IIO_AVAIL_LIST;
312
313 default:
314 return -EINVAL;
315 }
316 }
317
veml6075_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)318 static int veml6075_read_raw(struct iio_dev *indio_dev,
319 struct iio_chan_spec const *chan,
320 int *val, int *val2, long mask)
321 {
322 struct veml6075_data *data = iio_priv(indio_dev);
323
324 switch (mask) {
325 case IIO_CHAN_INFO_RAW:
326 return veml6075_read_uv_direct(data, chan->channel, val);
327 case IIO_CHAN_INFO_PROCESSED:
328 return veml6075_read_uvi(data, val, val2);
329 case IIO_CHAN_INFO_INT_TIME:
330 return veml6075_read_int_time_ms(data, val);
331 case IIO_CHAN_INFO_SCALE:
332 return veml6075_read_responsivity(chan->channel, val, val2);
333 default:
334 return -EINVAL;
335 }
336 }
337
veml6075_write_int_time_ms(struct veml6075_data * data,int val)338 static int veml6075_write_int_time_ms(struct veml6075_data *data, int val)
339 {
340 int i = ARRAY_SIZE(veml6075_it_ms);
341
342 guard(mutex)(&data->lock);
343
344 while (i-- > 0) {
345 if (val == veml6075_it_ms[i])
346 break;
347 }
348 if (i < 0)
349 return -EINVAL;
350
351 return regmap_update_bits(data->regmap, VEML6075_CMD_CONF,
352 VEML6075_CONF_IT,
353 FIELD_PREP(VEML6075_CONF_IT, i));
354 }
355
veml6075_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)356 static int veml6075_write_raw(struct iio_dev *indio_dev,
357 struct iio_chan_spec const *chan,
358 int val, int val2, long mask)
359 {
360 struct veml6075_data *data = iio_priv(indio_dev);
361
362 switch (mask) {
363 case IIO_CHAN_INFO_INT_TIME:
364 return veml6075_write_int_time_ms(data, val);
365 default:
366 return -EINVAL;
367 }
368 }
369
370 static const struct iio_info veml6075_info = {
371 .read_avail = veml6075_read_avail,
372 .read_raw = veml6075_read_raw,
373 .write_raw = veml6075_write_raw,
374 };
375
veml6075_readable_reg(struct device * dev,unsigned int reg)376 static bool veml6075_readable_reg(struct device *dev, unsigned int reg)
377 {
378 switch (reg) {
379 case VEML6075_CMD_CONF:
380 case VEML6075_CMD_UVA:
381 case VEML6075_CMD_UVB:
382 case VEML6075_CMD_COMP1:
383 case VEML6075_CMD_COMP2:
384 case VEML6075_CMD_ID:
385 return true;
386 default:
387 return false;
388 }
389 }
390
veml6075_writable_reg(struct device * dev,unsigned int reg)391 static bool veml6075_writable_reg(struct device *dev, unsigned int reg)
392 {
393 switch (reg) {
394 case VEML6075_CMD_CONF:
395 return true;
396 default:
397 return false;
398 }
399 }
400
401 static const struct regmap_config veml6075_regmap_config = {
402 .name = "veml6075",
403 .reg_bits = 8,
404 .val_bits = 16,
405 .max_register = VEML6075_CMD_ID,
406 .readable_reg = veml6075_readable_reg,
407 .writeable_reg = veml6075_writable_reg,
408 .val_format_endian = REGMAP_ENDIAN_LITTLE,
409 };
410
veml6075_probe(struct i2c_client * client)411 static int veml6075_probe(struct i2c_client *client)
412 {
413 struct veml6075_data *data;
414 struct iio_dev *indio_dev;
415 struct regmap *regmap;
416 int config, ret;
417
418 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
419 if (!indio_dev)
420 return -ENOMEM;
421
422 regmap = devm_regmap_init_i2c(client, &veml6075_regmap_config);
423 if (IS_ERR(regmap))
424 return PTR_ERR(regmap);
425
426 data = iio_priv(indio_dev);
427 data->client = client;
428 data->regmap = regmap;
429
430 mutex_init(&data->lock);
431
432 indio_dev->name = "veml6075";
433 indio_dev->info = &veml6075_info;
434 indio_dev->channels = veml6075_channels;
435 indio_dev->num_channels = ARRAY_SIZE(veml6075_channels);
436 indio_dev->modes = INDIO_DIRECT_MODE;
437
438 ret = devm_regulator_get_enable(&client->dev, "vdd");
439 if (ret < 0)
440 return ret;
441
442 /* default: 100ms integration time, active force enable, shutdown */
443 config = FIELD_PREP(VEML6075_CONF_IT, VEML6075_IT_100_MS) |
444 FIELD_PREP(VEML6075_CONF_AF, VEML6075_AF_ENABLE) |
445 FIELD_PREP(VEML6075_CONF_SD, VEML6075_SD_ENABLE);
446 ret = regmap_write(data->regmap, VEML6075_CMD_CONF, config);
447 if (ret < 0)
448 return ret;
449
450 return devm_iio_device_register(&client->dev, indio_dev);
451 }
452
453 static const struct i2c_device_id veml6075_id[] = {
454 { "veml6075" },
455 { }
456 };
457 MODULE_DEVICE_TABLE(i2c, veml6075_id);
458
459 static const struct of_device_id veml6075_of_match[] = {
460 { .compatible = "vishay,veml6075" },
461 {}
462 };
463 MODULE_DEVICE_TABLE(of, veml6075_of_match);
464
465 static struct i2c_driver veml6075_driver = {
466 .driver = {
467 .name = "veml6075",
468 .of_match_table = veml6075_of_match,
469 },
470 .probe = veml6075_probe,
471 .id_table = veml6075_id,
472 };
473
474 module_i2c_driver(veml6075_driver);
475
476 MODULE_AUTHOR("Javier Carrasco <[email protected]>");
477 MODULE_DESCRIPTION("Vishay VEML6075 UVA and UVB light sensor driver");
478 MODULE_LICENSE("GPL");
479