xref: /linux/drivers/iio/light/isl76682.c (revision 6e7fd890f1d6ac83805409e9c346240de2705584)
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>");
346