GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / iio / light / isl76682.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * IIO driver for the light sensor ISL76682.
4  * ISL76682 is Ambient Light Sensor
5  *
6  * Copyright (c) 2023 Marek Vasut <marex@denx.de>
7  */
8
9 #include <linux/array_size.h>
10 #include <linux/bits.h>
11 #include <linux/cleanup.h>
12 #include <linux/delay.h>
13 #include <linux/err.h>
14 #include <linux/i2c.h>
15 #include <linux/module.h>
16 #include <linux/mutex.h>
17 #include <linux/regmap.h>
18 #include <linux/types.h>
19
20 #include <linux/iio/iio.h>
21
22 #define ISL76682_REG_COMMAND                    0x00
23
24 #define ISL76682_COMMAND_EN                     BIT(7)
25 #define ISL76682_COMMAND_MODE_CONTINUOUS        BIT(6)
26 #define ISL76682_COMMAND_LIGHT_IR               BIT(5)
27
28 #define ISL76682_COMMAND_RANGE_LUX_1K           0x0
29 #define ISL76682_COMMAND_RANGE_LUX_4K           0x1
30 #define ISL76682_COMMAND_RANGE_LUX_16K          0x2
31 #define ISL76682_COMMAND_RANGE_LUX_64K          0x3
32 #define ISL76682_COMMAND_RANGE_LUX_MASK         GENMASK(1, 0)
33
34 #define ISL76682_REG_ALSIR_L                    0x01
35
36 #define ISL76682_REG_ALSIR_U                    0x02
37
38 #define ISL76682_NUM_REGS                       (ISL76682_REG_ALSIR_U + 1)
39
40 #define ISL76682_CONV_TIME_MS                   100
41 #define ISL76682_INT_TIME_US                    90000
42
43 #define ISL76682_ADC_MAX                        (BIT(16) - 1)
44
45 struct isl76682_chip {
46         /*
47          * Lock to synchronize access to device command register
48          * and the content of range variable below.
49          */
50         struct mutex                    lock;
51         struct regmap                   *regmap;
52         u8                              range;
53         u8                              command;
54 };
55
56 struct isl76682_range {
57         u8                              range;
58         u32                             als;
59         u32                             ir;
60 };
61
62 static struct isl76682_range isl76682_range_table[] = {
63         { ISL76682_COMMAND_RANGE_LUX_1K, 15000, 10500 },
64         { ISL76682_COMMAND_RANGE_LUX_4K, 60000, 42000 },
65         { ISL76682_COMMAND_RANGE_LUX_16K, 240000, 168000 },
66         { ISL76682_COMMAND_RANGE_LUX_64K, 960000, 673000 }
67 };
68
69 static int isl76682_get(struct isl76682_chip *chip, bool mode_ir, int *data)
70 {
71         u8 command;
72         int ret;
73
74         command = ISL76682_COMMAND_EN | ISL76682_COMMAND_MODE_CONTINUOUS |
75                   chip->range;
76
77         if (mode_ir)
78                 command |= ISL76682_COMMAND_LIGHT_IR;
79
80         if (command != chip->command) {
81                 ret = regmap_write(chip->regmap, ISL76682_REG_COMMAND, command);
82                 if (ret)
83                         return ret;
84
85                 /* Need to wait for conversion time if ALS/IR mode enabled */
86                 msleep(ISL76682_CONV_TIME_MS);
87
88                 chip->command = command;
89         }
90
91         ret = regmap_bulk_read(chip->regmap, ISL76682_REG_ALSIR_L, data, 2);
92         *data &= ISL76682_ADC_MAX;
93         return ret;
94 }
95
96 static int isl76682_write_raw(struct iio_dev *indio_dev,
97                               struct iio_chan_spec const *chan,
98                               int val, int val2, long mask)
99 {
100         struct isl76682_chip *chip = iio_priv(indio_dev);
101         int i;
102
103         if (mask != IIO_CHAN_INFO_SCALE)
104                 return -EINVAL;
105
106         if (val != 0)
107                 return -EINVAL;
108
109         for (i = 0; i < ARRAY_SIZE(isl76682_range_table); i++) {
110                 if (chan->type == IIO_LIGHT && val2 != isl76682_range_table[i].als)
111                         continue;
112                 if (chan->type == IIO_INTENSITY && val2 != isl76682_range_table[i].ir)
113                         continue;
114
115                 scoped_guard(mutex, &chip->lock)
116                         chip->range = isl76682_range_table[i].range;
117                 return 0;
118         }
119
120         return -EINVAL;
121 }
122
123 static int isl76682_read_raw(struct iio_dev *indio_dev,
124                              struct iio_chan_spec const *chan,
125                              int *val, int *val2, long mask)
126 {
127         struct isl76682_chip *chip = iio_priv(indio_dev);
128         int ret;
129         int i;
130
131         guard(mutex)(&chip->lock);
132
133         switch (mask) {
134         case IIO_CHAN_INFO_RAW:
135                 switch (chan->type) {
136                 case IIO_LIGHT:
137                         ret = isl76682_get(chip, false, val);
138                         return (ret < 0) ? ret : IIO_VAL_INT;
139                 case IIO_INTENSITY:
140                         ret = isl76682_get(chip, true, val);
141                         return (ret < 0) ? ret : IIO_VAL_INT;
142                 default:
143                         return -EINVAL;
144                 }
145         case IIO_CHAN_INFO_SCALE:
146                 for (i = 0; i < ARRAY_SIZE(isl76682_range_table); i++) {
147                         if (chip->range != isl76682_range_table[i].range)
148                                 continue;
149
150                         *val = 0;
151                         switch (chan->type) {
152                         case IIO_LIGHT:
153                                 *val2 = isl76682_range_table[i].als;
154                                 return IIO_VAL_INT_PLUS_MICRO;
155                         case IIO_INTENSITY:
156                                 *val2 = isl76682_range_table[i].ir;
157                                 return IIO_VAL_INT_PLUS_MICRO;
158                         default:
159                                 return -EINVAL;
160                         }
161                 }
162                 return -EINVAL;
163         case IIO_CHAN_INFO_INT_TIME:
164                 *val = 0;
165                 *val2 = ISL76682_INT_TIME_US;
166                 return IIO_VAL_INT_PLUS_MICRO;
167         default:
168                 return -EINVAL;
169         }
170 }
171
172 static int illuminance_scale_available[] = {
173         0, 15000,
174         0, 60000,
175         0, 240000,
176         0, 960000,
177 };
178
179 static int intensity_scale_available[] = {
180         0, 10500,
181         0, 42000,
182         0, 168000,
183         0, 673000,
184 };
185
186 static int isl76682_read_avail(struct iio_dev *indio_dev,
187                                struct iio_chan_spec const *chan,
188                                const int **vals, int *type,
189                                int *length, long mask)
190 {
191         switch (mask) {
192         case IIO_CHAN_INFO_SCALE:
193                 switch (chan->type) {
194                 case IIO_LIGHT:
195                         *vals = illuminance_scale_available;
196                         *length = ARRAY_SIZE(illuminance_scale_available);
197                         *type = IIO_VAL_INT_PLUS_MICRO;
198                         return IIO_AVAIL_LIST;
199                 case IIO_INTENSITY:
200                         *vals = intensity_scale_available;
201                         *length = ARRAY_SIZE(intensity_scale_available);
202                         *type = IIO_VAL_INT_PLUS_MICRO;
203                         return IIO_AVAIL_LIST;
204                 default:
205                         return -EINVAL;
206                 }
207         default:
208                 return -EINVAL;
209         }
210 }
211
212 static const struct iio_chan_spec isl76682_channels[] = {
213         {
214                 .type = IIO_LIGHT,
215                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
216                                       BIT(IIO_CHAN_INFO_SCALE),
217                 .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),
218                 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
219         }, {
220                 .type = IIO_INTENSITY,
221                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
222                                       BIT(IIO_CHAN_INFO_SCALE),
223                 .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),
224                 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
225         }
226 };
227
228 static const struct iio_info isl76682_info = {
229         .read_avail     = isl76682_read_avail,
230         .read_raw       = isl76682_read_raw,
231         .write_raw      = isl76682_write_raw,
232 };
233
234 static int isl76682_clear_configure_reg(struct isl76682_chip *chip)
235 {
236         struct device *dev = regmap_get_device(chip->regmap);
237         int ret;
238
239         ret = regmap_write(chip->regmap, ISL76682_REG_COMMAND, 0x0);
240         if (ret < 0)
241                 dev_err(dev, "Error %d clearing the CONFIGURE register\n", ret);
242
243         /*
244          * In the success case, the command register was zeroed out.
245          *
246          * In the error case, we do not know in which state the command
247          * register is, so we assume it is zeroed out, so that it would
248          * be reprogrammed at the next data read out, and at that time
249          * we hope it would be reprogrammed successfully. That is very
250          * much a best effort approach.
251          */
252         chip->command = 0;
253
254         return ret;
255 }
256
257 static void isl76682_reset_action(void *chip)
258 {
259         isl76682_clear_configure_reg(chip);
260 }
261
262 static bool isl76682_is_volatile_reg(struct device *dev, unsigned int reg)
263 {
264         switch (reg) {
265         case ISL76682_REG_ALSIR_L:
266         case ISL76682_REG_ALSIR_U:
267                 return true;
268         default:
269                 return false;
270         }
271 }
272
273 static const struct regmap_config isl76682_regmap_config = {
274         .reg_bits               = 8,
275         .val_bits               = 8,
276         .volatile_reg           = isl76682_is_volatile_reg,
277         .max_register           = ISL76682_NUM_REGS - 1,
278         .num_reg_defaults_raw   = ISL76682_NUM_REGS,
279         .cache_type             = REGCACHE_FLAT,
280 };
281
282 static int isl76682_probe(struct i2c_client *client)
283 {
284         struct device *dev = &client->dev;
285         struct isl76682_chip *chip;
286         struct iio_dev *indio_dev;
287         int ret;
288
289         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
290         if (!indio_dev)
291                 return -ENOMEM;
292
293         chip = iio_priv(indio_dev);
294
295         mutex_init(&chip->lock);
296
297         chip->regmap = devm_regmap_init_i2c(client, &isl76682_regmap_config);
298         ret = PTR_ERR_OR_ZERO(chip->regmap);
299         if (ret)
300                 return dev_err_probe(dev, ret, "Error initializing regmap\n");
301
302         chip->range = ISL76682_COMMAND_RANGE_LUX_1K;
303
304         ret = isl76682_clear_configure_reg(chip);
305         if (ret < 0)
306                 return ret;
307
308         ret = devm_add_action_or_reset(dev, isl76682_reset_action, chip);
309         if (ret)
310                 return ret;
311
312         indio_dev->info = &isl76682_info;
313         indio_dev->channels = isl76682_channels;
314         indio_dev->num_channels = ARRAY_SIZE(isl76682_channels);
315         indio_dev->name = "isl76682";
316         indio_dev->modes = INDIO_DIRECT_MODE;
317
318         return devm_iio_device_register(dev, indio_dev);
319 }
320
321 static const struct i2c_device_id isl76682_id[] = {
322         { "isl76682" },
323         { }
324 };
325 MODULE_DEVICE_TABLE(i2c, isl76682_id);
326
327 static const struct of_device_id isl76682_of_match[] = {
328         { .compatible = "isil,isl76682" },
329         { }
330 };
331 MODULE_DEVICE_TABLE(of, isl76682_of_match);
332
333 static struct i2c_driver isl76682_driver = {
334         .driver  = {
335                 .name           = "isl76682",
336                 .of_match_table = isl76682_of_match,
337         },
338         .probe          = isl76682_probe,
339         .id_table       = isl76682_id,
340 };
341 module_i2c_driver(isl76682_driver);
342
343 MODULE_DESCRIPTION("ISL76682 Ambient Light Sensor driver");
344 MODULE_LICENSE("GPL");
345 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");