1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * veml6070.c - Support for Vishay VEML6070 UV A light sensor 4 * 5 * Copyright 2016 Peter Meerwald-Stadler <pmeerw@pmeerw.net> 6 * 7 * IIO driver for VEML6070 (7-bit I2C slave addresses 0x38 and 0x39) 8 * 9 * TODO: integration time, ACK signal 10 */ 11 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> 17 18 #include <linux/iio/iio.h> 19 #include <linux/iio/sysfs.h> 20 21 #define VEML6070_DRV_NAME "veml6070" 22 23 #define VEML6070_ADDR_CONFIG_DATA_MSB 0x38 /* read: MSB data, write: config */ 24 #define VEML6070_ADDR_DATA_LSB 0x39 /* LSB data */ 25 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 */ 30 31 #define VEML6070_IT_10 0x04 /* integration time 1x */ 32 33 struct veml6070_data { 34 struct i2c_client *client1; 35 struct i2c_client *client2; 36 u8 config; 37 struct mutex lock; 38 }; 39 40 static int veml6070_read(struct veml6070_data *data) 41 { 42 int ret; 43 u8 msb, lsb; 44 45 mutex_lock(&data->lock); 46 47 /* disable shutdown */ 48 ret = i2c_smbus_write_byte(data->client1, 49 data->config & ~VEML6070_COMMAND_SD); 50 if (ret < 0) 51 goto out; 52 53 msleep(125 + 10); /* measurement takes up to 125 ms for IT 1x */ 54 55 ret = i2c_smbus_read_byte(data->client2); /* read MSB, address 0x39 */ 56 if (ret < 0) 57 goto out; 58 msb = ret; 59 60 ret = i2c_smbus_read_byte(data->client1); /* read LSB, address 0x38 */ 61 if (ret < 0) 62 goto out; 63 lsb = ret; 64 65 /* shutdown again */ 66 ret = i2c_smbus_write_byte(data->client1, data->config); 67 if (ret < 0) 68 goto out; 69 70 ret = (msb << 8) | lsb; 71 72 out: 73 mutex_unlock(&data->lock); 74 return ret; 75 } 76 77 static const struct iio_chan_spec veml6070_channels[] = { 78 { 79 .type = IIO_INTENSITY, 80 .modified = 1, 81 .channel2 = IIO_MOD_LIGHT_UV, 82 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 83 }, 84 { 85 .type = IIO_UVINDEX, 86 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 87 } 88 }; 89 90 static int veml6070_to_uv_index(unsigned val) 91 { 92 /* 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) 96 */ 97 unsigned uvi[11] = { 98 187, 373, 560, /* low */ 99 746, 933, 1120, /* moderate */ 100 1308, 1494, /* high */ 101 1681, 1868, 2054}; /* very high */ 102 int i; 103 104 for (i = 0; i < ARRAY_SIZE(uvi); i++) 105 if (val <= uvi[i]) 106 return i; 107 108 return 11; /* extreme */ 109 } 110 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) 114 { 115 struct veml6070_data *data = iio_priv(indio_dev); 116 int ret; 117 118 switch (mask) { 119 case IIO_CHAN_INFO_RAW: 120 case IIO_CHAN_INFO_PROCESSED: 121 ret = veml6070_read(data); 122 if (ret < 0) 123 return ret; 124 if (mask == IIO_CHAN_INFO_PROCESSED) 125 *val = veml6070_to_uv_index(ret); 126 else 127 *val = ret; 128 return IIO_VAL_INT; 129 default: 130 return -EINVAL; 131 } 132 } 133 134 static const struct iio_info veml6070_info = { 135 .read_raw = veml6070_read_raw, 136 }; 137 138 static int veml6070_probe(struct i2c_client *client) 139 { 140 struct veml6070_data *data; 141 struct iio_dev *indio_dev; 142 int ret; 143 144 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 145 if (!indio_dev) 146 return -ENOMEM; 147 148 data = iio_priv(indio_dev); 149 i2c_set_clientdata(client, indio_dev); 150 data->client1 = client; 151 mutex_init(&data->lock); 152 153 indio_dev->info = &veml6070_info; 154 indio_dev->channels = veml6070_channels; 155 indio_dev->num_channels = ARRAY_SIZE(veml6070_channels); 156 indio_dev->name = VEML6070_DRV_NAME; 157 indio_dev->modes = INDIO_DIRECT_MODE; 158 159 data->client2 = i2c_new_dummy_device(client->adapter, VEML6070_ADDR_DATA_LSB); 160 if (IS_ERR(data->client2)) { 161 dev_err(&client->dev, "i2c device for second chip address failed\n"); 162 return PTR_ERR(data->client2); 163 } 164 165 data->config = VEML6070_IT_10 | VEML6070_COMMAND_RSRVD | 166 VEML6070_COMMAND_SD; 167 ret = i2c_smbus_write_byte(data->client1, data->config); 168 if (ret < 0) 169 goto fail; 170 171 ret = iio_device_register(indio_dev); 172 if (ret < 0) 173 goto fail; 174 175 return ret; 176 177 fail: 178 i2c_unregister_device(data->client2); 179 return ret; 180 } 181 182 static void veml6070_remove(struct i2c_client *client) 183 { 184 struct iio_dev *indio_dev = i2c_get_clientdata(client); 185 struct veml6070_data *data = iio_priv(indio_dev); 186 187 iio_device_unregister(indio_dev); 188 i2c_unregister_device(data->client2); 189 } 190 191 static const struct i2c_device_id veml6070_id[] = { 192 { "veml6070" }, 193 { } 194 }; 195 MODULE_DEVICE_TABLE(i2c, veml6070_id); 196 197 static struct i2c_driver veml6070_driver = { 198 .driver = { 199 .name = VEML6070_DRV_NAME, 200 }, 201 .probe = veml6070_probe, 202 .remove = veml6070_remove, 203 .id_table = veml6070_id, 204 }; 205 206 module_i2c_driver(veml6070_driver); 207 208 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>"); 209 MODULE_DESCRIPTION("Vishay VEML6070 UV A light sensor driver"); 210 MODULE_LICENSE("GPL"); 211