GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / iio / light / veml6075.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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");