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: ACK signal 10 */ 11 12 #include <linux/bitfield.h> 13 #include <linux/module.h> 14 #include <linux/i2c.h> 15 #include <linux/mutex.h> 16 #include <linux/err.h> 17 #include <linux/delay.h> 18 #include <linux/units.h> 19 20 #include <linux/iio/iio.h> 21 #include <linux/iio/sysfs.h> 22 23 #define VEML6070_DRV_NAME "veml6070" 24 25 #define VEML6070_ADDR_CONFIG_DATA_MSB 0x38 /* read: MSB data, write: config */ 26 #define VEML6070_ADDR_DATA_LSB 0x39 /* LSB data */ 27 28 #define VEML6070_COMMAND_ACK BIT(5) /* raise interrupt when over threshold */ 29 #define VEML6070_COMMAND_IT GENMASK(3, 2) /* bit mask integration time */ 30 #define VEML6070_COMMAND_RSRVD BIT(1) /* reserved, set to 1 */ 31 #define VEML6070_COMMAND_SD BIT(0) /* shutdown mode when set */ 32 33 #define VEML6070_IT_05 0x00 34 #define VEML6070_IT_10 0x01 35 #define VEML6070_IT_20 0x02 36 #define VEML6070_IT_40 0x03 37 38 #define VEML6070_MIN_RSET_KOHM 75 39 #define VEML6070_MIN_IT_US 15625 /* Rset = 75 kohm, IT = 1/2 */ 40 41 struct veml6070_data { 42 struct i2c_client *client1; 43 struct i2c_client *client2; 44 u8 config; 45 struct mutex lock; 46 u32 rset; 47 int it[4][2]; 48 }; 49 50 static int veml6070_calc_it(struct device *dev, struct veml6070_data *data) 51 { 52 int i, tmp_it; 53 54 data->rset = 270000; 55 device_property_read_u32(dev, "vishay,rset-ohms", &data->rset); 56 57 if (data->rset < 75000 || data->rset > 1200000) 58 return dev_err_probe(dev, -EINVAL, "Rset out of range\n"); 59 60 /* 61 * convert to kohm to avoid overflows and work with the same units as 62 * in the datasheet and simplify UVI operations. 63 */ 64 data->rset /= KILO; 65 66 tmp_it = VEML6070_MIN_IT_US * data->rset / VEML6070_MIN_RSET_KOHM; 67 for (i = 0; i < ARRAY_SIZE(data->it); i++) { 68 data->it[i][0] = (tmp_it << i) / MICRO; 69 data->it[i][1] = (tmp_it << i) % MICRO; 70 } 71 72 return 0; 73 } 74 75 static int veml6070_get_it(struct veml6070_data *data, int *val, int *val2) 76 { 77 int it_idx = FIELD_GET(VEML6070_COMMAND_IT, data->config); 78 79 *val = data->it[it_idx][0]; 80 *val2 = data->it[it_idx][1]; 81 82 return IIO_VAL_INT_PLUS_MICRO; 83 } 84 85 static int veml6070_set_it(struct veml6070_data *data, int val, int val2) 86 { 87 int it_idx; 88 89 for (it_idx = 0; it_idx < ARRAY_SIZE(data->it); it_idx++) { 90 if (data->it[it_idx][0] == val && data->it[it_idx][1] == val2) 91 break; 92 } 93 94 if (it_idx >= ARRAY_SIZE(data->it)) 95 return -EINVAL; 96 97 data->config = (data->config & ~VEML6070_COMMAND_IT) | 98 FIELD_PREP(VEML6070_COMMAND_IT, it_idx); 99 100 return i2c_smbus_write_byte(data->client1, data->config); 101 } 102 103 static int veml6070_read(struct veml6070_data *data) 104 { 105 int ret, it_ms, val, val2; 106 u8 msb, lsb; 107 108 guard(mutex)(&data->lock); 109 110 /* disable shutdown */ 111 ret = i2c_smbus_write_byte(data->client1, 112 data->config & ~VEML6070_COMMAND_SD); 113 if (ret < 0) 114 return ret; 115 116 veml6070_get_it(data, &val, &val2); 117 it_ms = val * MILLI + val2 / (MICRO / MILLI); 118 msleep(it_ms + 10); 119 120 ret = i2c_smbus_read_byte(data->client2); /* read MSB, address 0x39 */ 121 if (ret < 0) 122 return ret; 123 124 msb = ret; 125 126 ret = i2c_smbus_read_byte(data->client1); /* read LSB, address 0x38 */ 127 if (ret < 0) 128 return ret; 129 130 lsb = ret; 131 132 /* shutdown again */ 133 ret = i2c_smbus_write_byte(data->client1, data->config); 134 if (ret < 0) 135 return ret; 136 137 ret = (msb << 8) | lsb; 138 139 return 0; 140 } 141 142 static const struct iio_chan_spec veml6070_channels[] = { 143 { 144 .type = IIO_INTENSITY, 145 .modified = 1, 146 .channel2 = IIO_MOD_LIGHT_UV, 147 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 148 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), 149 .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), 150 }, 151 { 152 .type = IIO_UVINDEX, 153 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 154 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), 155 .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), 156 } 157 }; 158 159 static int veml6070_to_uv_index(struct veml6070_data *data, unsigned int val) 160 { 161 /* 162 * conversion of raw UV intensity values to UV index depends on 163 * integration time (IT) and value of the resistor connected to 164 * the RSET pin. 165 */ 166 unsigned int uvi[11] = { 167 187, 373, 560, /* low */ 168 746, 933, 1120, /* moderate */ 169 1308, 1494, /* high */ 170 1681, 1868, 2054}; /* very high */ 171 int i, it_idx; 172 173 it_idx = FIELD_GET(VEML6070_COMMAND_IT, data->config); 174 175 if (!it_idx) 176 val = (val * 270 / data->rset) << 1; 177 else 178 val = (val * 270 / data->rset) >> (it_idx - 1); 179 180 for (i = 0; i < ARRAY_SIZE(uvi); i++) 181 if (val <= uvi[i]) 182 return i; 183 184 return 11; /* extreme */ 185 } 186 187 static int veml6070_read_raw(struct iio_dev *indio_dev, 188 struct iio_chan_spec const *chan, 189 int *val, int *val2, long mask) 190 { 191 struct veml6070_data *data = iio_priv(indio_dev); 192 int ret; 193 194 switch (mask) { 195 case IIO_CHAN_INFO_RAW: 196 case IIO_CHAN_INFO_PROCESSED: 197 ret = veml6070_read(data); 198 if (ret < 0) 199 return ret; 200 if (mask == IIO_CHAN_INFO_PROCESSED) 201 *val = veml6070_to_uv_index(data, ret); 202 else 203 *val = ret; 204 return IIO_VAL_INT; 205 case IIO_CHAN_INFO_INT_TIME: 206 return veml6070_get_it(data, val, val2); 207 default: 208 return -EINVAL; 209 } 210 } 211 212 static int veml6070_read_avail(struct iio_dev *indio_dev, 213 struct iio_chan_spec const *chan, 214 const int **vals, int *type, int *length, 215 long mask) 216 { 217 struct veml6070_data *data = iio_priv(indio_dev); 218 219 switch (mask) { 220 case IIO_CHAN_INFO_INT_TIME: 221 *vals = (int *)data->it; 222 *length = 2 * ARRAY_SIZE(data->it); 223 *type = IIO_VAL_INT_PLUS_MICRO; 224 return IIO_AVAIL_LIST; 225 default: 226 return -EINVAL; 227 } 228 } 229 230 static int veml6070_write_raw(struct iio_dev *indio_dev, 231 struct iio_chan_spec const *chan, 232 int val, int val2, long mask) 233 { 234 struct veml6070_data *data = iio_priv(indio_dev); 235 236 switch (mask) { 237 case IIO_CHAN_INFO_INT_TIME: 238 return veml6070_set_it(data, val, val2); 239 default: 240 return -EINVAL; 241 } 242 } 243 244 static const struct iio_info veml6070_info = { 245 .read_raw = veml6070_read_raw, 246 .read_avail = veml6070_read_avail, 247 .write_raw = veml6070_write_raw, 248 }; 249 250 static void veml6070_i2c_unreg(void *p) 251 { 252 struct veml6070_data *data = p; 253 254 i2c_unregister_device(data->client2); 255 } 256 257 static int veml6070_probe(struct i2c_client *client) 258 { 259 struct veml6070_data *data; 260 struct iio_dev *indio_dev; 261 int ret; 262 263 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 264 if (!indio_dev) 265 return -ENOMEM; 266 267 data = iio_priv(indio_dev); 268 i2c_set_clientdata(client, indio_dev); 269 data->client1 = client; 270 mutex_init(&data->lock); 271 272 indio_dev->info = &veml6070_info; 273 indio_dev->channels = veml6070_channels; 274 indio_dev->num_channels = ARRAY_SIZE(veml6070_channels); 275 indio_dev->name = VEML6070_DRV_NAME; 276 indio_dev->modes = INDIO_DIRECT_MODE; 277 278 ret = veml6070_calc_it(&client->dev, data); 279 if (ret < 0) 280 return ret; 281 282 ret = devm_regulator_get_enable(&client->dev, "vdd"); 283 if (ret < 0) 284 return ret; 285 286 data->client2 = i2c_new_dummy_device(client->adapter, VEML6070_ADDR_DATA_LSB); 287 if (IS_ERR(data->client2)) 288 return dev_err_probe(&client->dev, PTR_ERR(data->client2), 289 "i2c device for second chip address failed\n"); 290 291 data->config = FIELD_PREP(VEML6070_COMMAND_IT, VEML6070_IT_10) | 292 VEML6070_COMMAND_RSRVD | VEML6070_COMMAND_SD; 293 ret = i2c_smbus_write_byte(data->client1, data->config); 294 if (ret < 0) 295 return ret; 296 297 ret = devm_add_action_or_reset(&client->dev, veml6070_i2c_unreg, data); 298 if (ret < 0) 299 return ret; 300 301 return devm_iio_device_register(&client->dev, indio_dev); 302 } 303 304 static const struct i2c_device_id veml6070_id[] = { 305 { "veml6070" }, 306 { } 307 }; 308 MODULE_DEVICE_TABLE(i2c, veml6070_id); 309 310 static const struct of_device_id veml6070_of_match[] = { 311 { .compatible = "vishay,veml6070" }, 312 { } 313 }; 314 MODULE_DEVICE_TABLE(of, veml6070_of_match); 315 316 static struct i2c_driver veml6070_driver = { 317 .driver = { 318 .name = VEML6070_DRV_NAME, 319 .of_match_table = veml6070_of_match, 320 }, 321 .probe = veml6070_probe, 322 .id_table = veml6070_id, 323 }; 324 325 module_i2c_driver(veml6070_driver); 326 327 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>"); 328 MODULE_DESCRIPTION("Vishay VEML6070 UV A light sensor driver"); 329 MODULE_LICENSE("GPL"); 330