1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * zopt2201.c - Support for IDT ZOPT2201 ambient light and UV B sensor 4 * 5 * Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net> 6 * 7 * Datasheet: https://www.idt.com/document/dst/zopt2201-datasheet 8 * 7-bit I2C slave addresses 0x53 (default) or 0x52 (programmed) 9 * 10 * TODO: interrupt support, ALS/UVB raw mode 11 */ 12 13 #include <linux/cleanup.h> 14 #include <linux/delay.h> 15 #include <linux/err.h> 16 #include <linux/i2c.h> 17 #include <linux/module.h> 18 #include <linux/mutex.h> 19 #include <linux/unaligned.h> 20 21 #include <linux/iio/iio.h> 22 #include <linux/iio/sysfs.h> 23 24 #define ZOPT2201_DRV_NAME "zopt2201" 25 26 /* Registers */ 27 #define ZOPT2201_MAIN_CTRL 0x00 28 #define ZOPT2201_LS_MEAS_RATE 0x04 29 #define ZOPT2201_LS_GAIN 0x05 30 #define ZOPT2201_PART_ID 0x06 31 #define ZOPT2201_MAIN_STATUS 0x07 32 #define ZOPT2201_ALS_DATA 0x0d /* LSB first, 13 to 20 bits */ 33 #define ZOPT2201_UVB_DATA 0x10 /* LSB first, 13 to 20 bits */ 34 #define ZOPT2201_UV_COMP_DATA 0x13 /* LSB first, 13 to 20 bits */ 35 #define ZOPT2201_COMP_DATA 0x16 /* LSB first, 13 to 20 bits */ 36 #define ZOPT2201_INT_CFG 0x19 37 #define ZOPT2201_INT_PST 0x1a 38 39 #define ZOPT2201_MAIN_CTRL_LS_MODE BIT(3) /* 0 .. ALS, 1 .. UV B */ 40 #define ZOPT2201_MAIN_CTRL_LS_EN BIT(1) 41 42 /* Values for ZOPT2201_LS_MEAS_RATE resolution / bit width */ 43 #define ZOPT2201_MEAS_RES_20BIT 0 /* takes 400 ms */ 44 #define ZOPT2201_MEAS_RES_19BIT 1 /* takes 200 ms */ 45 #define ZOPT2201_MEAS_RES_18BIT 2 /* takes 100 ms, default */ 46 #define ZOPT2201_MEAS_RES_17BIT 3 /* takes 50 ms */ 47 #define ZOPT2201_MEAS_RES_16BIT 4 /* takes 25 ms */ 48 #define ZOPT2201_MEAS_RES_13BIT 5 /* takes 3.125 ms */ 49 #define ZOPT2201_MEAS_RES_SHIFT 4 50 51 /* Values for ZOPT2201_LS_MEAS_RATE measurement rate */ 52 #define ZOPT2201_MEAS_FREQ_25MS 0 53 #define ZOPT2201_MEAS_FREQ_50MS 1 54 #define ZOPT2201_MEAS_FREQ_100MS 2 /* default */ 55 #define ZOPT2201_MEAS_FREQ_200MS 3 56 #define ZOPT2201_MEAS_FREQ_500MS 4 57 #define ZOPT2201_MEAS_FREQ_1000MS 5 58 #define ZOPT2201_MEAS_FREQ_2000MS 6 59 60 /* Values for ZOPT2201_LS_GAIN */ 61 #define ZOPT2201_LS_GAIN_1 0 62 #define ZOPT2201_LS_GAIN_3 1 63 #define ZOPT2201_LS_GAIN_6 2 64 #define ZOPT2201_LS_GAIN_9 3 65 #define ZOPT2201_LS_GAIN_18 4 66 67 /* Values for ZOPT2201_MAIN_STATUS */ 68 #define ZOPT2201_MAIN_STATUS_POWERON BIT(5) 69 #define ZOPT2201_MAIN_STATUS_INT BIT(4) 70 #define ZOPT2201_MAIN_STATUS_DRDY BIT(3) 71 72 #define ZOPT2201_PART_NUMBER 0xb2 73 74 struct zopt2201_data { 75 struct i2c_client *client; 76 struct mutex lock; 77 u8 gain; 78 u8 res; 79 u8 rate; 80 }; 81 82 static const struct { 83 unsigned int gain; /* gain factor */ 84 unsigned int scale; /* micro lux per count */ 85 } zopt2201_gain_als[] = { 86 { 1, 19200000 }, 87 { 3, 6400000 }, 88 { 6, 3200000 }, 89 { 9, 2133333 }, 90 { 18, 1066666 }, 91 }; 92 93 static const struct { 94 unsigned int gain; /* gain factor */ 95 unsigned int scale; /* micro W/m2 per count */ 96 } zopt2201_gain_uvb[] = { 97 { 1, 460800 }, 98 { 3, 153600 }, 99 { 6, 76800 }, 100 { 9, 51200 }, 101 { 18, 25600 }, 102 }; 103 104 static const struct { 105 unsigned int bits; /* sensor resolution in bits */ 106 unsigned long us; /* measurement time in micro seconds */ 107 } zopt2201_resolution[] = { 108 { 20, 400000 }, 109 { 19, 200000 }, 110 { 18, 100000 }, 111 { 17, 50000 }, 112 { 16, 25000 }, 113 { 13, 3125 }, 114 }; 115 116 struct zopt2201_scale { 117 unsigned int scale, uscale; /* scale factor as integer + micro */ 118 u8 gain; /* gain register value */ 119 u8 res; /* resolution register value */ 120 }; 121 122 static const struct zopt2201_scale zopt2201_scale_als[] = { 123 { 19, 200000, 0, 5 }, 124 { 6, 400000, 1, 5 }, 125 { 3, 200000, 2, 5 }, 126 { 2, 400000, 0, 4 }, 127 { 2, 133333, 3, 5 }, 128 { 1, 200000, 0, 3 }, 129 { 1, 66666, 4, 5 }, 130 { 0, 800000, 1, 4 }, 131 { 0, 600000, 0, 2 }, 132 { 0, 400000, 2, 4 }, 133 { 0, 300000, 0, 1 }, 134 { 0, 266666, 3, 4 }, 135 { 0, 200000, 2, 3 }, 136 { 0, 150000, 0, 0 }, 137 { 0, 133333, 4, 4 }, 138 { 0, 100000, 2, 2 }, 139 { 0, 66666, 4, 3 }, 140 { 0, 50000, 2, 1 }, 141 { 0, 33333, 4, 2 }, 142 { 0, 25000, 2, 0 }, 143 { 0, 16666, 4, 1 }, 144 { 0, 8333, 4, 0 }, 145 }; 146 147 static const struct zopt2201_scale zopt2201_scale_uvb[] = { 148 { 0, 460800, 0, 5 }, 149 { 0, 153600, 1, 5 }, 150 { 0, 76800, 2, 5 }, 151 { 0, 57600, 0, 4 }, 152 { 0, 51200, 3, 5 }, 153 { 0, 28800, 0, 3 }, 154 { 0, 25600, 4, 5 }, 155 { 0, 19200, 1, 4 }, 156 { 0, 14400, 0, 2 }, 157 { 0, 9600, 2, 4 }, 158 { 0, 7200, 0, 1 }, 159 { 0, 6400, 3, 4 }, 160 { 0, 4800, 2, 3 }, 161 { 0, 3600, 0, 0 }, 162 { 0, 3200, 4, 4 }, 163 { 0, 2400, 2, 2 }, 164 { 0, 1600, 4, 3 }, 165 { 0, 1200, 2, 1 }, 166 { 0, 800, 4, 2 }, 167 { 0, 600, 2, 0 }, 168 { 0, 400, 4, 1 }, 169 { 0, 200, 4, 0 }, 170 }; 171 172 static int zopt2201_enable_mode(struct zopt2201_data *data, bool uvb_mode) 173 { 174 u8 out = ZOPT2201_MAIN_CTRL_LS_EN; 175 176 if (uvb_mode) 177 out |= ZOPT2201_MAIN_CTRL_LS_MODE; 178 179 return i2c_smbus_write_byte_data(data->client, ZOPT2201_MAIN_CTRL, out); 180 } 181 182 static int zopt2201_read(struct zopt2201_data *data, u8 reg) 183 { 184 struct i2c_client *client = data->client; 185 int tries = 10; 186 u8 buf[3]; 187 int ret; 188 189 guard(mutex)(&data->lock); 190 ret = zopt2201_enable_mode(data, reg == ZOPT2201_UVB_DATA); 191 if (ret < 0) 192 return ret; 193 194 while (tries--) { 195 unsigned long t = zopt2201_resolution[data->res].us; 196 197 if (t <= 20000) 198 usleep_range(t, t + 1000); 199 else 200 msleep(t / 1000); 201 ret = i2c_smbus_read_byte_data(client, ZOPT2201_MAIN_STATUS); 202 if (ret < 0) 203 return ret; 204 if (ret & ZOPT2201_MAIN_STATUS_DRDY) 205 break; 206 } 207 208 if (tries < 0) { 209 ret = -ETIMEDOUT; 210 return ret; 211 } 212 213 ret = i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf); 214 if (ret < 0) 215 return ret; 216 217 ret = i2c_smbus_write_byte_data(client, ZOPT2201_MAIN_CTRL, 0x00); 218 if (ret < 0) 219 return ret; 220 221 return get_unaligned_le24(&buf[0]); 222 } 223 224 static const struct iio_chan_spec zopt2201_channels[] = { 225 { 226 .type = IIO_LIGHT, 227 .address = ZOPT2201_ALS_DATA, 228 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 229 BIT(IIO_CHAN_INFO_SCALE), 230 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), 231 }, 232 { 233 .type = IIO_INTENSITY, 234 .modified = 1, 235 .channel2 = IIO_MOD_LIGHT_UV, 236 .address = ZOPT2201_UVB_DATA, 237 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 238 BIT(IIO_CHAN_INFO_SCALE), 239 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), 240 }, 241 { 242 .type = IIO_UVINDEX, 243 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 244 }, 245 }; 246 247 static int zopt2201_read_raw(struct iio_dev *indio_dev, 248 struct iio_chan_spec const *chan, 249 int *val, int *val2, long mask) 250 { 251 struct zopt2201_data *data = iio_priv(indio_dev); 252 u64 tmp; 253 int ret; 254 255 switch (mask) { 256 case IIO_CHAN_INFO_RAW: 257 ret = zopt2201_read(data, chan->address); 258 if (ret < 0) 259 return ret; 260 *val = ret; 261 return IIO_VAL_INT; 262 case IIO_CHAN_INFO_PROCESSED: 263 ret = zopt2201_read(data, ZOPT2201_UVB_DATA); 264 if (ret < 0) 265 return ret; 266 *val = ret * 18 * 267 (1 << (20 - zopt2201_resolution[data->res].bits)) / 268 zopt2201_gain_uvb[data->gain].gain; 269 return IIO_VAL_INT; 270 case IIO_CHAN_INFO_SCALE: 271 switch (chan->address) { 272 case ZOPT2201_ALS_DATA: 273 *val = zopt2201_gain_als[data->gain].scale; 274 break; 275 case ZOPT2201_UVB_DATA: 276 *val = zopt2201_gain_uvb[data->gain].scale; 277 break; 278 default: 279 return -EINVAL; 280 } 281 282 *val2 = 1000000; 283 *val2 *= (1 << (zopt2201_resolution[data->res].bits - 13)); 284 tmp = div_s64(*val * 1000000ULL, *val2); 285 *val = div_s64_rem(tmp, 1000000, val2); 286 287 return IIO_VAL_INT_PLUS_MICRO; 288 case IIO_CHAN_INFO_INT_TIME: 289 *val = 0; 290 *val2 = zopt2201_resolution[data->res].us; 291 return IIO_VAL_INT_PLUS_MICRO; 292 default: 293 return -EINVAL; 294 } 295 } 296 297 static int zopt2201_set_resolution(struct zopt2201_data *data, u8 res) 298 { 299 int ret; 300 301 ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_MEAS_RATE, 302 (res << ZOPT2201_MEAS_RES_SHIFT) | 303 data->rate); 304 if (ret < 0) 305 return ret; 306 307 data->res = res; 308 309 return 0; 310 } 311 312 static int zopt2201_write_resolution(struct zopt2201_data *data, 313 int val, int val2) 314 { 315 int i; 316 317 if (val != 0) 318 return -EINVAL; 319 320 for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++) 321 if (val2 == zopt2201_resolution[i].us) { 322 guard(mutex)(&data->lock); 323 return zopt2201_set_resolution(data, i); 324 } 325 326 return -EINVAL; 327 } 328 329 static int zopt2201_set_gain(struct zopt2201_data *data, u8 gain) 330 { 331 int ret; 332 333 ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_GAIN, gain); 334 if (ret < 0) 335 return ret; 336 337 data->gain = gain; 338 339 return 0; 340 } 341 342 static int zopt2201_write_scale_by_idx(struct zopt2201_data *data, int idx, 343 const struct zopt2201_scale *zopt2201_scale_array) 344 { 345 int ret; 346 347 guard(mutex)(&data->lock); 348 ret = zopt2201_set_resolution(data, zopt2201_scale_array[idx].res); 349 if (ret < 0) 350 return ret; 351 352 return zopt2201_set_gain(data, zopt2201_scale_array[idx].gain); 353 } 354 355 static int zopt2201_write_scale_als(struct zopt2201_data *data, 356 int val, int val2) 357 { 358 int i; 359 360 for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++) 361 if (val == zopt2201_scale_als[i].scale && 362 val2 == zopt2201_scale_als[i].uscale) 363 return zopt2201_write_scale_by_idx(data, i, zopt2201_scale_als); 364 365 return -EINVAL; 366 } 367 368 static int zopt2201_write_scale_uvb(struct zopt2201_data *data, 369 int val, int val2) 370 { 371 int i; 372 373 for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++) 374 if (val == zopt2201_scale_uvb[i].scale && 375 val2 == zopt2201_scale_uvb[i].uscale) 376 return zopt2201_write_scale_by_idx(data, i, zopt2201_scale_uvb); 377 378 return -EINVAL; 379 } 380 381 static int zopt2201_write_raw(struct iio_dev *indio_dev, 382 struct iio_chan_spec const *chan, 383 int val, int val2, long mask) 384 { 385 struct zopt2201_data *data = iio_priv(indio_dev); 386 387 switch (mask) { 388 case IIO_CHAN_INFO_INT_TIME: 389 return zopt2201_write_resolution(data, val, val2); 390 case IIO_CHAN_INFO_SCALE: 391 switch (chan->address) { 392 case ZOPT2201_ALS_DATA: 393 return zopt2201_write_scale_als(data, val, val2); 394 case ZOPT2201_UVB_DATA: 395 return zopt2201_write_scale_uvb(data, val, val2); 396 default: 397 return -EINVAL; 398 } 399 } 400 401 return -EINVAL; 402 } 403 404 static ssize_t zopt2201_show_int_time_available(struct device *dev, 405 struct device_attribute *attr, 406 char *buf) 407 { 408 size_t len = 0; 409 int i; 410 411 for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++) 412 len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06lu ", 413 zopt2201_resolution[i].us); 414 buf[len - 1] = '\n'; 415 416 return len; 417 } 418 419 static IIO_DEV_ATTR_INT_TIME_AVAIL(zopt2201_show_int_time_available); 420 421 static ssize_t zopt2201_show_als_scale_avail(struct device *dev, 422 struct device_attribute *attr, 423 char *buf) 424 { 425 ssize_t len = 0; 426 int i; 427 428 for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++) 429 len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ", 430 zopt2201_scale_als[i].scale, 431 zopt2201_scale_als[i].uscale); 432 buf[len - 1] = '\n'; 433 434 return len; 435 } 436 437 static ssize_t zopt2201_show_uvb_scale_avail(struct device *dev, 438 struct device_attribute *attr, 439 char *buf) 440 { 441 ssize_t len = 0; 442 int i; 443 444 for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++) 445 len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ", 446 zopt2201_scale_uvb[i].scale, 447 zopt2201_scale_uvb[i].uscale); 448 buf[len - 1] = '\n'; 449 450 return len; 451 } 452 453 static IIO_DEVICE_ATTR(in_illuminance_scale_available, 0444, 454 zopt2201_show_als_scale_avail, NULL, 0); 455 static IIO_DEVICE_ATTR(in_intensity_uv_scale_available, 0444, 456 zopt2201_show_uvb_scale_avail, NULL, 0); 457 458 static struct attribute *zopt2201_attributes[] = { 459 &iio_dev_attr_integration_time_available.dev_attr.attr, 460 &iio_dev_attr_in_illuminance_scale_available.dev_attr.attr, 461 &iio_dev_attr_in_intensity_uv_scale_available.dev_attr.attr, 462 NULL 463 }; 464 465 static const struct attribute_group zopt2201_attribute_group = { 466 .attrs = zopt2201_attributes, 467 }; 468 469 static const struct iio_info zopt2201_info = { 470 .read_raw = zopt2201_read_raw, 471 .write_raw = zopt2201_write_raw, 472 .attrs = &zopt2201_attribute_group, 473 }; 474 475 static int zopt2201_probe(struct i2c_client *client) 476 { 477 struct zopt2201_data *data; 478 struct iio_dev *indio_dev; 479 int ret; 480 481 if (!i2c_check_functionality(client->adapter, 482 I2C_FUNC_SMBUS_READ_I2C_BLOCK)) 483 return -EOPNOTSUPP; 484 485 ret = i2c_smbus_read_byte_data(client, ZOPT2201_PART_ID); 486 if (ret < 0) 487 return ret; 488 if (ret != ZOPT2201_PART_NUMBER) 489 return -ENODEV; 490 491 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 492 if (!indio_dev) 493 return -ENOMEM; 494 495 data = iio_priv(indio_dev); 496 i2c_set_clientdata(client, indio_dev); 497 data->client = client; 498 mutex_init(&data->lock); 499 500 indio_dev->info = &zopt2201_info; 501 indio_dev->channels = zopt2201_channels; 502 indio_dev->num_channels = ARRAY_SIZE(zopt2201_channels); 503 indio_dev->name = ZOPT2201_DRV_NAME; 504 indio_dev->modes = INDIO_DIRECT_MODE; 505 506 data->rate = ZOPT2201_MEAS_FREQ_100MS; 507 ret = zopt2201_set_resolution(data, ZOPT2201_MEAS_RES_18BIT); 508 if (ret < 0) 509 return ret; 510 511 ret = zopt2201_set_gain(data, ZOPT2201_LS_GAIN_3); 512 if (ret < 0) 513 return ret; 514 515 return devm_iio_device_register(&client->dev, indio_dev); 516 } 517 518 static const struct i2c_device_id zopt2201_id[] = { 519 { "zopt2201" }, 520 { } 521 }; 522 MODULE_DEVICE_TABLE(i2c, zopt2201_id); 523 524 static struct i2c_driver zopt2201_driver = { 525 .driver = { 526 .name = ZOPT2201_DRV_NAME, 527 }, 528 .probe = zopt2201_probe, 529 .id_table = zopt2201_id, 530 }; 531 532 module_i2c_driver(zopt2201_driver); 533 534 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>"); 535 MODULE_DESCRIPTION("IDT ZOPT2201 ambient light and UV B sensor driver"); 536 MODULE_LICENSE("GPL"); 537