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