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 const struct i2c_device_id *id) 140 { 141 struct veml6070_data *data; 142 struct iio_dev *indio_dev; 143 int ret; 144 145 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 146 if (!indio_dev) 147 return -ENOMEM; 148 149 data = iio_priv(indio_dev); 150 i2c_set_clientdata(client, indio_dev); 151 data->client1 = client; 152 mutex_init(&data->lock); 153 154 indio_dev->dev.parent = &client->dev; 155 indio_dev->info = &veml6070_info; 156 indio_dev->channels = veml6070_channels; 157 indio_dev->num_channels = ARRAY_SIZE(veml6070_channels); 158 indio_dev->name = VEML6070_DRV_NAME; 159 indio_dev->modes = INDIO_DIRECT_MODE; 160 161 data->client2 = i2c_new_dummy(client->adapter, VEML6070_ADDR_DATA_LSB); 162 if (!data->client2) { 163 dev_err(&client->dev, "i2c device for second chip address failed\n"); 164 return -ENODEV; 165 } 166 167 data->config = VEML6070_IT_10 | VEML6070_COMMAND_RSRVD | 168 VEML6070_COMMAND_SD; 169 ret = i2c_smbus_write_byte(data->client1, data->config); 170 if (ret < 0) 171 goto fail; 172 173 ret = iio_device_register(indio_dev); 174 if (ret < 0) 175 goto fail; 176 177 return ret; 178 179 fail: 180 i2c_unregister_device(data->client2); 181 return ret; 182 } 183 184 static int veml6070_remove(struct i2c_client *client) 185 { 186 struct iio_dev *indio_dev = i2c_get_clientdata(client); 187 struct veml6070_data *data = iio_priv(indio_dev); 188 189 iio_device_unregister(indio_dev); 190 i2c_unregister_device(data->client2); 191 192 return 0; 193 } 194 195 static const struct i2c_device_id veml6070_id[] = { 196 { "veml6070", 0 }, 197 { } 198 }; 199 MODULE_DEVICE_TABLE(i2c, veml6070_id); 200 201 static struct i2c_driver veml6070_driver = { 202 .driver = { 203 .name = VEML6070_DRV_NAME, 204 }, 205 .probe = veml6070_probe, 206 .remove = veml6070_remove, 207 .id_table = veml6070_id, 208 }; 209 210 module_i2c_driver(veml6070_driver); 211 212 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>"); 213 MODULE_DESCRIPTION("Vishay VEML6070 UV A light sensor driver"); 214 MODULE_LICENSE("GPL"); 215