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
isl76682_get(struct isl76682_chip * chip,bool mode_ir,int * data)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
isl76682_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)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
isl76682_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)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
isl76682_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)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
isl76682_clear_configure_reg(struct isl76682_chip * chip)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
isl76682_reset_action(void * chip)257 static void isl76682_reset_action(void *chip)
258 {
259 isl76682_clear_configure_reg(chip);
260 }
261
isl76682_is_volatile_reg(struct device * dev,unsigned int reg)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
isl76682_probe(struct i2c_client * client)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>");
346