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)
9 * TODO: integration time, ACK signal
12 #include <linux/module.h>
13 #include <linux/i2c.h>
14 #include <linux/mutex.h>
15 #include <linux/err.h>
16 #include <linux/delay.h>
18 #include <linux/iio/iio.h>
19 #include <linux/iio/sysfs.h>
21 #define VEML6070_DRV_NAME "veml6070"
23 #define VEML6070_ADDR_CONFIG_DATA_MSB 0x38 /* read: MSB data, write: config */
24 #define VEML6070_ADDR_DATA_LSB 0x39 /* LSB data */
26 #define VEML6070_COMMAND_ACK BIT(5) /* raise interrupt when over threshold */
27 #define VEML6070_COMMAND_IT GENMASK(3, 2) /* bit mask integration time */
28 #define VEML6070_COMMAND_RSRVD BIT(1) /* reserved, set to 1 */
29 #define VEML6070_COMMAND_SD BIT(0) /* shutdown mode when set */
31 #define VEML6070_IT_10 0x04 /* integration time 1x */
33 struct veml6070_data
{
34 struct i2c_client
*client1
;
35 struct i2c_client
*client2
;
40 static int veml6070_read(struct veml6070_data
*data
)
45 mutex_lock(&data
->lock
);
47 /* disable shutdown */
48 ret
= i2c_smbus_write_byte(data
->client1
,
49 data
->config
& ~VEML6070_COMMAND_SD
);
53 msleep(125 + 10); /* measurement takes up to 125 ms for IT 1x */
55 ret
= i2c_smbus_read_byte(data
->client2
); /* read MSB, address 0x39 */
60 ret
= i2c_smbus_read_byte(data
->client1
); /* read LSB, address 0x38 */
66 ret
= i2c_smbus_write_byte(data
->client1
, data
->config
);
70 ret
= (msb
<< 8) | lsb
;
73 mutex_unlock(&data
->lock
);
77 static const struct iio_chan_spec veml6070_channels
[] = {
79 .type
= IIO_INTENSITY
,
81 .channel2
= IIO_MOD_LIGHT_UV
,
82 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
),
86 .info_mask_separate
= BIT(IIO_CHAN_INFO_PROCESSED
),
90 static int veml6070_to_uv_index(unsigned val
)
93 * conversion of raw UV intensity values to UV index depends on
94 * integration time (IT) and value of the resistor connected to
95 * the RSET pin (default: 270 KOhm)
98 187, 373, 560, /* low */
99 746, 933, 1120, /* moderate */
100 1308, 1494, /* high */
101 1681, 1868, 2054}; /* very high */
104 for (i
= 0; i
< ARRAY_SIZE(uvi
); i
++)
108 return 11; /* extreme */
111 static int veml6070_read_raw(struct iio_dev
*indio_dev
,
112 struct iio_chan_spec
const *chan
,
113 int *val
, int *val2
, long mask
)
115 struct veml6070_data
*data
= iio_priv(indio_dev
);
119 case IIO_CHAN_INFO_RAW
:
120 case IIO_CHAN_INFO_PROCESSED
:
121 ret
= veml6070_read(data
);
124 if (mask
== IIO_CHAN_INFO_PROCESSED
)
125 *val
= veml6070_to_uv_index(ret
);
134 static const struct iio_info veml6070_info
= {
135 .read_raw
= veml6070_read_raw
,
138 static int veml6070_probe(struct i2c_client
*client
,
139 const struct i2c_device_id
*id
)
141 struct veml6070_data
*data
;
142 struct iio_dev
*indio_dev
;
145 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*data
));
149 data
= iio_priv(indio_dev
);
150 i2c_set_clientdata(client
, indio_dev
);
151 data
->client1
= client
;
152 mutex_init(&data
->lock
);
154 indio_dev
->info
= &veml6070_info
;
155 indio_dev
->channels
= veml6070_channels
;
156 indio_dev
->num_channels
= ARRAY_SIZE(veml6070_channels
);
157 indio_dev
->name
= VEML6070_DRV_NAME
;
158 indio_dev
->modes
= INDIO_DIRECT_MODE
;
160 data
->client2
= i2c_new_dummy_device(client
->adapter
, VEML6070_ADDR_DATA_LSB
);
161 if (IS_ERR(data
->client2
)) {
162 dev_err(&client
->dev
, "i2c device for second chip address failed\n");
163 return PTR_ERR(data
->client2
);
166 data
->config
= VEML6070_IT_10
| VEML6070_COMMAND_RSRVD
|
168 ret
= i2c_smbus_write_byte(data
->client1
, data
->config
);
172 ret
= iio_device_register(indio_dev
);
179 i2c_unregister_device(data
->client2
);
183 static int veml6070_remove(struct i2c_client
*client
)
185 struct iio_dev
*indio_dev
= i2c_get_clientdata(client
);
186 struct veml6070_data
*data
= iio_priv(indio_dev
);
188 iio_device_unregister(indio_dev
);
189 i2c_unregister_device(data
->client2
);
194 static const struct i2c_device_id veml6070_id
[] = {
198 MODULE_DEVICE_TABLE(i2c
, veml6070_id
);
200 static struct i2c_driver veml6070_driver
= {
202 .name
= VEML6070_DRV_NAME
,
204 .probe
= veml6070_probe
,
205 .remove
= veml6070_remove
,
206 .id_table
= veml6070_id
,
209 module_i2c_driver(veml6070_driver
);
211 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
212 MODULE_DESCRIPTION("Vishay VEML6070 UV A light sensor driver");
213 MODULE_LICENSE("GPL");