1 // SPDX-License-Identifier: GPL-2.0-only
3 * veml6070.c - Support for Vishay VEML6070 UV A light sensor
5 * Copyright 2016 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
7 * IIO driver for VEML6070 (7-bit I2C slave addresses 0x38 and 0x39)
12 #include <linux/bitfield.h>
13 #include <linux/module.h>
14 #include <linux/i2c.h>
15 #include <linux/mutex.h>
16 #include <linux/err.h>
17 #include <linux/delay.h>
18 #include <linux/units.h>
20 #include <linux/iio/iio.h>
21 #include <linux/iio/sysfs.h>
23 #define VEML6070_DRV_NAME "veml6070"
25 #define VEML6070_ADDR_CONFIG_DATA_MSB 0x38 /* read: MSB data, write: config */
26 #define VEML6070_ADDR_DATA_LSB 0x39 /* LSB data */
28 #define VEML6070_COMMAND_ACK BIT(5) /* raise interrupt when over threshold */
29 #define VEML6070_COMMAND_IT GENMASK(3, 2) /* bit mask integration time */
30 #define VEML6070_COMMAND_RSRVD BIT(1) /* reserved, set to 1 */
31 #define VEML6070_COMMAND_SD BIT(0) /* shutdown mode when set */
33 #define VEML6070_IT_05 0x00
34 #define VEML6070_IT_10 0x01
35 #define VEML6070_IT_20 0x02
36 #define VEML6070_IT_40 0x03
38 #define VEML6070_MIN_RSET_KOHM 75
39 #define VEML6070_MIN_IT_US 15625 /* Rset = 75 kohm, IT = 1/2 */
41 struct veml6070_data
{
42 struct i2c_client
*client1
;
43 struct i2c_client
*client2
;
50 static int veml6070_calc_it(struct device
*dev
, struct veml6070_data
*data
)
55 device_property_read_u32(dev
, "vishay,rset-ohms", &data
->rset
);
57 if (data
->rset
< 75000 || data
->rset
> 1200000)
58 return dev_err_probe(dev
, -EINVAL
, "Rset out of range\n");
61 * convert to kohm to avoid overflows and work with the same units as
62 * in the datasheet and simplify UVI operations.
66 tmp_it
= VEML6070_MIN_IT_US
* data
->rset
/ VEML6070_MIN_RSET_KOHM
;
67 for (i
= 0; i
< ARRAY_SIZE(data
->it
); i
++) {
68 data
->it
[i
][0] = (tmp_it
<< i
) / MICRO
;
69 data
->it
[i
][1] = (tmp_it
<< i
) % MICRO
;
75 static int veml6070_get_it(struct veml6070_data
*data
, int *val
, int *val2
)
77 int it_idx
= FIELD_GET(VEML6070_COMMAND_IT
, data
->config
);
79 *val
= data
->it
[it_idx
][0];
80 *val2
= data
->it
[it_idx
][1];
82 return IIO_VAL_INT_PLUS_MICRO
;
85 static int veml6070_set_it(struct veml6070_data
*data
, int val
, int val2
)
89 for (it_idx
= 0; it_idx
< ARRAY_SIZE(data
->it
); it_idx
++) {
90 if (data
->it
[it_idx
][0] == val
&& data
->it
[it_idx
][1] == val2
)
94 if (it_idx
>= ARRAY_SIZE(data
->it
))
97 data
->config
= (data
->config
& ~VEML6070_COMMAND_IT
) |
98 FIELD_PREP(VEML6070_COMMAND_IT
, it_idx
);
100 return i2c_smbus_write_byte(data
->client1
, data
->config
);
103 static int veml6070_read(struct veml6070_data
*data
)
105 int ret
, it_ms
, val
, val2
;
108 guard(mutex
)(&data
->lock
);
110 /* disable shutdown */
111 ret
= i2c_smbus_write_byte(data
->client1
,
112 data
->config
& ~VEML6070_COMMAND_SD
);
116 veml6070_get_it(data
, &val
, &val2
);
117 it_ms
= val
* MILLI
+ val2
/ (MICRO
/ MILLI
);
120 ret
= i2c_smbus_read_byte(data
->client2
); /* read MSB, address 0x39 */
126 ret
= i2c_smbus_read_byte(data
->client1
); /* read LSB, address 0x38 */
133 ret
= i2c_smbus_write_byte(data
->client1
, data
->config
);
137 ret
= (msb
<< 8) | lsb
;
142 static const struct iio_chan_spec veml6070_channels
[] = {
144 .type
= IIO_INTENSITY
,
146 .channel2
= IIO_MOD_LIGHT_UV
,
147 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
),
148 .info_mask_shared_by_all
= BIT(IIO_CHAN_INFO_INT_TIME
),
149 .info_mask_shared_by_all_available
= BIT(IIO_CHAN_INFO_INT_TIME
),
153 .info_mask_separate
= BIT(IIO_CHAN_INFO_PROCESSED
),
154 .info_mask_shared_by_all
= BIT(IIO_CHAN_INFO_INT_TIME
),
155 .info_mask_shared_by_all_available
= BIT(IIO_CHAN_INFO_INT_TIME
),
159 static int veml6070_to_uv_index(struct veml6070_data
*data
, unsigned int val
)
162 * conversion of raw UV intensity values to UV index depends on
163 * integration time (IT) and value of the resistor connected to
166 unsigned int uvi
[11] = {
167 187, 373, 560, /* low */
168 746, 933, 1120, /* moderate */
169 1308, 1494, /* high */
170 1681, 1868, 2054}; /* very high */
173 it_idx
= FIELD_GET(VEML6070_COMMAND_IT
, data
->config
);
176 val
= (val
* 270 / data
->rset
) << 1;
178 val
= (val
* 270 / data
->rset
) >> (it_idx
- 1);
180 for (i
= 0; i
< ARRAY_SIZE(uvi
); i
++)
184 return 11; /* extreme */
187 static int veml6070_read_raw(struct iio_dev
*indio_dev
,
188 struct iio_chan_spec
const *chan
,
189 int *val
, int *val2
, long mask
)
191 struct veml6070_data
*data
= iio_priv(indio_dev
);
195 case IIO_CHAN_INFO_RAW
:
196 case IIO_CHAN_INFO_PROCESSED
:
197 ret
= veml6070_read(data
);
200 if (mask
== IIO_CHAN_INFO_PROCESSED
)
201 *val
= veml6070_to_uv_index(data
, ret
);
205 case IIO_CHAN_INFO_INT_TIME
:
206 return veml6070_get_it(data
, val
, val2
);
212 static int veml6070_read_avail(struct iio_dev
*indio_dev
,
213 struct iio_chan_spec
const *chan
,
214 const int **vals
, int *type
, int *length
,
217 struct veml6070_data
*data
= iio_priv(indio_dev
);
220 case IIO_CHAN_INFO_INT_TIME
:
221 *vals
= (int *)data
->it
;
222 *length
= 2 * ARRAY_SIZE(data
->it
);
223 *type
= IIO_VAL_INT_PLUS_MICRO
;
224 return IIO_AVAIL_LIST
;
230 static int veml6070_write_raw(struct iio_dev
*indio_dev
,
231 struct iio_chan_spec
const *chan
,
232 int val
, int val2
, long mask
)
234 struct veml6070_data
*data
= iio_priv(indio_dev
);
237 case IIO_CHAN_INFO_INT_TIME
:
238 return veml6070_set_it(data
, val
, val2
);
244 static const struct iio_info veml6070_info
= {
245 .read_raw
= veml6070_read_raw
,
246 .read_avail
= veml6070_read_avail
,
247 .write_raw
= veml6070_write_raw
,
250 static void veml6070_i2c_unreg(void *p
)
252 struct veml6070_data
*data
= p
;
254 i2c_unregister_device(data
->client2
);
257 static int veml6070_probe(struct i2c_client
*client
)
259 struct veml6070_data
*data
;
260 struct iio_dev
*indio_dev
;
263 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*data
));
267 data
= iio_priv(indio_dev
);
268 i2c_set_clientdata(client
, indio_dev
);
269 data
->client1
= client
;
270 mutex_init(&data
->lock
);
272 indio_dev
->info
= &veml6070_info
;
273 indio_dev
->channels
= veml6070_channels
;
274 indio_dev
->num_channels
= ARRAY_SIZE(veml6070_channels
);
275 indio_dev
->name
= VEML6070_DRV_NAME
;
276 indio_dev
->modes
= INDIO_DIRECT_MODE
;
278 ret
= veml6070_calc_it(&client
->dev
, data
);
282 ret
= devm_regulator_get_enable(&client
->dev
, "vdd");
286 data
->client2
= i2c_new_dummy_device(client
->adapter
, VEML6070_ADDR_DATA_LSB
);
287 if (IS_ERR(data
->client2
))
288 return dev_err_probe(&client
->dev
, PTR_ERR(data
->client2
),
289 "i2c device for second chip address failed\n");
291 data
->config
= FIELD_PREP(VEML6070_COMMAND_IT
, VEML6070_IT_10
) |
292 VEML6070_COMMAND_RSRVD
| VEML6070_COMMAND_SD
;
293 ret
= i2c_smbus_write_byte(data
->client1
, data
->config
);
297 ret
= devm_add_action_or_reset(&client
->dev
, veml6070_i2c_unreg
, data
);
301 return devm_iio_device_register(&client
->dev
, indio_dev
);
304 static const struct i2c_device_id veml6070_id
[] = {
308 MODULE_DEVICE_TABLE(i2c
, veml6070_id
);
310 static const struct of_device_id veml6070_of_match
[] = {
311 { .compatible
= "vishay,veml6070" },
314 MODULE_DEVICE_TABLE(of
, veml6070_of_match
);
316 static struct i2c_driver veml6070_driver
= {
318 .name
= VEML6070_DRV_NAME
,
319 .of_match_table
= veml6070_of_match
,
321 .probe
= veml6070_probe
,
322 .id_table
= veml6070_id
,
325 module_i2c_driver(veml6070_driver
);
327 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
328 MODULE_DESCRIPTION("Vishay VEML6070 UV A light sensor driver");
329 MODULE_LICENSE("GPL");