1 // SPDX-License-Identifier: GPL-2.0-only
3 * IIO driver for the light sensor ISL76682.
4 * ISL76682 is Ambient Light Sensor
6 * Copyright (c) 2023 Marek Vasut <marex@denx.de>
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>
20 #include <linux/iio/iio.h>
22 #define ISL76682_REG_COMMAND 0x00
24 #define ISL76682_COMMAND_EN BIT(7)
25 #define ISL76682_COMMAND_MODE_CONTINUOUS BIT(6)
26 #define ISL76682_COMMAND_LIGHT_IR BIT(5)
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)
34 #define ISL76682_REG_ALSIR_L 0x01
36 #define ISL76682_REG_ALSIR_U 0x02
38 #define ISL76682_NUM_REGS (ISL76682_REG_ALSIR_U + 1)
40 #define ISL76682_CONV_TIME_MS 100
41 #define ISL76682_INT_TIME_US 90000
43 #define ISL76682_ADC_MAX (BIT(16) - 1)
45 struct isl76682_chip
{
47 * Lock to synchronize access to device command register
48 * and the content of range variable below.
51 struct regmap
*regmap
;
56 struct isl76682_range
{
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 }
69 static int isl76682_get(struct isl76682_chip
*chip
, bool mode_ir
, int *data
)
74 command
= ISL76682_COMMAND_EN
| ISL76682_COMMAND_MODE_CONTINUOUS
|
78 command
|= ISL76682_COMMAND_LIGHT_IR
;
80 if (command
!= chip
->command
) {
81 ret
= regmap_write(chip
->regmap
, ISL76682_REG_COMMAND
, command
);
85 /* Need to wait for conversion time if ALS/IR mode enabled */
86 msleep(ISL76682_CONV_TIME_MS
);
88 chip
->command
= command
;
91 ret
= regmap_bulk_read(chip
->regmap
, ISL76682_REG_ALSIR_L
, data
, 2);
92 *data
&= ISL76682_ADC_MAX
;
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
)
100 struct isl76682_chip
*chip
= iio_priv(indio_dev
);
103 if (mask
!= IIO_CHAN_INFO_SCALE
)
109 for (i
= 0; i
< ARRAY_SIZE(isl76682_range_table
); i
++) {
110 if (chan
->type
== IIO_LIGHT
&& val2
!= isl76682_range_table
[i
].als
)
112 if (chan
->type
== IIO_INTENSITY
&& val2
!= isl76682_range_table
[i
].ir
)
115 scoped_guard(mutex
, &chip
->lock
)
116 chip
->range
= isl76682_range_table
[i
].range
;
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
)
127 struct isl76682_chip
*chip
= iio_priv(indio_dev
);
131 guard(mutex
)(&chip
->lock
);
134 case IIO_CHAN_INFO_RAW
:
135 switch (chan
->type
) {
137 ret
= isl76682_get(chip
, false, val
);
138 return (ret
< 0) ? ret
: IIO_VAL_INT
;
140 ret
= isl76682_get(chip
, true, val
);
141 return (ret
< 0) ? ret
: IIO_VAL_INT
;
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
)
151 switch (chan
->type
) {
153 *val2
= isl76682_range_table
[i
].als
;
154 return IIO_VAL_INT_PLUS_MICRO
;
156 *val2
= isl76682_range_table
[i
].ir
;
157 return IIO_VAL_INT_PLUS_MICRO
;
163 case IIO_CHAN_INFO_INT_TIME
:
165 *val2
= ISL76682_INT_TIME_US
;
166 return IIO_VAL_INT_PLUS_MICRO
;
172 static int illuminance_scale_available
[] = {
179 static int intensity_scale_available
[] = {
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
)
192 case IIO_CHAN_INFO_SCALE
:
193 switch (chan
->type
) {
195 *vals
= illuminance_scale_available
;
196 *length
= ARRAY_SIZE(illuminance_scale_available
);
197 *type
= IIO_VAL_INT_PLUS_MICRO
;
198 return IIO_AVAIL_LIST
;
200 *vals
= intensity_scale_available
;
201 *length
= ARRAY_SIZE(intensity_scale_available
);
202 *type
= IIO_VAL_INT_PLUS_MICRO
;
203 return IIO_AVAIL_LIST
;
212 static const struct iio_chan_spec isl76682_channels
[] = {
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
),
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
),
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
,
234 static int isl76682_clear_configure_reg(struct isl76682_chip
*chip
)
236 struct device
*dev
= regmap_get_device(chip
->regmap
);
239 ret
= regmap_write(chip
->regmap
, ISL76682_REG_COMMAND
, 0x0);
241 dev_err(dev
, "Error %d clearing the CONFIGURE register\n", ret
);
244 * In the success case, the command register was zeroed out.
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.
257 static void isl76682_reset_action(void *chip
)
259 isl76682_clear_configure_reg(chip
);
262 static bool isl76682_is_volatile_reg(struct device
*dev
, unsigned int reg
)
265 case ISL76682_REG_ALSIR_L
:
266 case ISL76682_REG_ALSIR_U
:
273 static const struct regmap_config isl76682_regmap_config
= {
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
,
282 static int isl76682_probe(struct i2c_client
*client
)
284 struct device
*dev
= &client
->dev
;
285 struct isl76682_chip
*chip
;
286 struct iio_dev
*indio_dev
;
289 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*chip
));
293 chip
= iio_priv(indio_dev
);
295 mutex_init(&chip
->lock
);
297 chip
->regmap
= devm_regmap_init_i2c(client
, &isl76682_regmap_config
);
298 ret
= PTR_ERR_OR_ZERO(chip
->regmap
);
300 return dev_err_probe(dev
, ret
, "Error initializing regmap\n");
302 chip
->range
= ISL76682_COMMAND_RANGE_LUX_1K
;
304 ret
= isl76682_clear_configure_reg(chip
);
308 ret
= devm_add_action_or_reset(dev
, isl76682_reset_action
, chip
);
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
;
318 return devm_iio_device_register(dev
, indio_dev
);
321 static const struct i2c_device_id isl76682_id
[] = {
325 MODULE_DEVICE_TABLE(i2c
, isl76682_id
);
327 static const struct of_device_id isl76682_of_match
[] = {
328 { .compatible
= "isil,isl76682" },
331 MODULE_DEVICE_TABLE(of
, isl76682_of_match
);
333 static struct i2c_driver isl76682_driver
= {
336 .of_match_table
= isl76682_of_match
,
338 .probe
= isl76682_probe
,
339 .id_table
= isl76682_id
,
341 module_i2c_driver(isl76682_driver
);
343 MODULE_DESCRIPTION("ISL76682 Ambient Light Sensor driver");
344 MODULE_LICENSE("GPL");
345 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");