root/drivers/iio/light/zopt2201.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zopt2201_enable_mode
  2. zopt2201_read
  3. zopt2201_read_raw
  4. zopt2201_set_resolution
  5. zopt2201_write_resolution
  6. zopt2201_set_gain
  7. zopt2201_write_scale_als_by_idx
  8. zopt2201_write_scale_als
  9. zopt2201_write_scale_uvb_by_idx
  10. zopt2201_write_scale_uvb
  11. zopt2201_write_raw
  12. zopt2201_show_int_time_available
  13. zopt2201_show_als_scale_avail
  14. zopt2201_show_uvb_scale_avail
  15. zopt2201_probe

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

/* [<][>][^][v][top][bottom][index][help] */