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