linux/drivers/iio/light/veml6030.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * VEML6030 Ambient Light Sensor
   4 *
   5 * Copyright (c) 2019, Rishi Gupta <gupt21@gmail.com>
   6 *
   7 * Datasheet: https://www.vishay.com/docs/84366/veml6030.pdf
   8 * Appnote-84367: https://www.vishay.com/docs/84367/designingveml6030.pdf
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/i2c.h>
  13#include <linux/err.h>
  14#include <linux/regmap.h>
  15#include <linux/interrupt.h>
  16#include <linux/pm_runtime.h>
  17#include <linux/iio/iio.h>
  18#include <linux/iio/sysfs.h>
  19#include <linux/iio/events.h>
  20
  21/* Device registers */
  22#define VEML6030_REG_ALS_CONF   0x00
  23#define VEML6030_REG_ALS_WH     0x01
  24#define VEML6030_REG_ALS_WL     0x02
  25#define VEML6030_REG_ALS_PSM    0x03
  26#define VEML6030_REG_ALS_DATA   0x04
  27#define VEML6030_REG_WH_DATA    0x05
  28#define VEML6030_REG_ALS_INT    0x06
  29
  30/* Bit masks for specific functionality */
  31#define VEML6030_ALS_IT       GENMASK(9, 6)
  32#define VEML6030_PSM          GENMASK(2, 1)
  33#define VEML6030_ALS_PERS     GENMASK(5, 4)
  34#define VEML6030_ALS_GAIN     GENMASK(12, 11)
  35#define VEML6030_PSM_EN       BIT(0)
  36#define VEML6030_INT_TH_LOW   BIT(15)
  37#define VEML6030_INT_TH_HIGH  BIT(14)
  38#define VEML6030_ALS_INT_EN   BIT(1)
  39#define VEML6030_ALS_SD       BIT(0)
  40
  41/*
  42 * The resolution depends on both gain and integration time. The
  43 * cur_resolution stores one of the resolution mentioned in the
  44 * table during startup and gets updated whenever integration time
  45 * or gain is changed.
  46 *
  47 * Table 'resolution and maximum detection range' in appnote 84367
  48 * is visualized as a 2D array. The cur_gain stores index of gain
  49 * in this table (0-3) while the cur_integration_time holds index
  50 * of integration time (0-5).
  51 */
  52struct veml6030_data {
  53        struct i2c_client *client;
  54        struct regmap *regmap;
  55        int cur_resolution;
  56        int cur_gain;
  57        int cur_integration_time;
  58};
  59
  60/* Integration time available in seconds */
  61static IIO_CONST_ATTR(in_illuminance_integration_time_available,
  62                                "0.025 0.05 0.1 0.2 0.4 0.8");
  63
  64/*
  65 * Scale is 1/gain. Value 0.125 is ALS gain x (1/8), 0.25 is
  66 * ALS gain x (1/4), 1.0 = ALS gain x 1 and 2.0 is ALS gain x 2.
  67 */
  68static IIO_CONST_ATTR(in_illuminance_scale_available,
  69                                "0.125 0.25 1.0 2.0");
  70
  71static struct attribute *veml6030_attributes[] = {
  72        &iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr,
  73        &iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
  74        NULL
  75};
  76
  77static const struct attribute_group veml6030_attr_group = {
  78        .attrs = veml6030_attributes,
  79};
  80
  81/*
  82 * Persistence = 1/2/4/8 x integration time
  83 * Minimum time for which light readings must stay above configured
  84 * threshold to assert the interrupt.
  85 */
  86static const char * const period_values[] = {
  87                "0.1 0.2 0.4 0.8",
  88                "0.2 0.4 0.8 1.6",
  89                "0.4 0.8 1.6 3.2",
  90                "0.8 1.6 3.2 6.4",
  91                "0.05 0.1 0.2 0.4",
  92                "0.025 0.050 0.1 0.2"
  93};
  94
  95/*
  96 * Return list of valid period values in seconds corresponding to
  97 * the currently active integration time.
  98 */
  99static ssize_t in_illuminance_period_available_show(struct device *dev,
 100                                struct device_attribute *attr, char *buf)
 101{
 102        int ret, reg, x;
 103        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 104        struct veml6030_data *data = iio_priv(indio_dev);
 105
 106        ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, &reg);
 107        if (ret) {
 108                dev_err(&data->client->dev,
 109                                "can't read als conf register %d\n", ret);
 110                return ret;
 111        }
 112
 113        ret = ((reg >> 6) & 0xF);
 114        switch (ret) {
 115        case 0:
 116        case 1:
 117        case 2:
 118        case 3:
 119                x = ret;
 120                break;
 121        case 8:
 122                x = 4;
 123                break;
 124        case 12:
 125                x = 5;
 126                break;
 127        default:
 128                return -EINVAL;
 129        }
 130
 131        return sysfs_emit(buf, "%s\n", period_values[x]);
 132}
 133
 134static IIO_DEVICE_ATTR_RO(in_illuminance_period_available, 0);
 135
 136static struct attribute *veml6030_event_attributes[] = {
 137        &iio_dev_attr_in_illuminance_period_available.dev_attr.attr,
 138        NULL
 139};
 140
 141static const struct attribute_group veml6030_event_attr_group = {
 142        .attrs = veml6030_event_attributes,
 143};
 144
 145static int veml6030_als_pwr_on(struct veml6030_data *data)
 146{
 147        return regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
 148                                 VEML6030_ALS_SD, 0);
 149}
 150
 151static int veml6030_als_shut_down(struct veml6030_data *data)
 152{
 153        return regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
 154                                 VEML6030_ALS_SD, 1);
 155}
 156
 157static void veml6030_als_shut_down_action(void *data)
 158{
 159        veml6030_als_shut_down(data);
 160}
 161
 162static const struct iio_event_spec veml6030_event_spec[] = {
 163        {
 164                .type = IIO_EV_TYPE_THRESH,
 165                .dir = IIO_EV_DIR_RISING,
 166                .mask_separate = BIT(IIO_EV_INFO_VALUE),
 167        }, {
 168                .type = IIO_EV_TYPE_THRESH,
 169                .dir = IIO_EV_DIR_FALLING,
 170                .mask_separate = BIT(IIO_EV_INFO_VALUE),
 171        }, {
 172                .type = IIO_EV_TYPE_THRESH,
 173                .dir = IIO_EV_DIR_EITHER,
 174                .mask_separate = BIT(IIO_EV_INFO_PERIOD) |
 175                BIT(IIO_EV_INFO_ENABLE),
 176        },
 177};
 178
 179/* Channel number */
 180enum veml6030_chan {
 181        CH_ALS,
 182        CH_WHITE,
 183};
 184
 185static const struct iio_chan_spec veml6030_channels[] = {
 186        {
 187                .type = IIO_LIGHT,
 188                .channel = CH_ALS,
 189                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 190                                BIT(IIO_CHAN_INFO_PROCESSED) |
 191                                BIT(IIO_CHAN_INFO_INT_TIME) |
 192                                BIT(IIO_CHAN_INFO_SCALE),
 193                .event_spec = veml6030_event_spec,
 194                .num_event_specs = ARRAY_SIZE(veml6030_event_spec),
 195        },
 196        {
 197                .type = IIO_INTENSITY,
 198                .channel = CH_WHITE,
 199                .modified = 1,
 200                .channel2 = IIO_MOD_LIGHT_BOTH,
 201                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 202                                BIT(IIO_CHAN_INFO_PROCESSED),
 203        },
 204};
 205
 206static const struct regmap_config veml6030_regmap_config = {
 207        .name = "veml6030_regmap",
 208        .reg_bits = 8,
 209        .val_bits = 16,
 210        .max_register = VEML6030_REG_ALS_INT,
 211        .val_format_endian = REGMAP_ENDIAN_LITTLE,
 212};
 213
 214static int veml6030_get_intgrn_tm(struct iio_dev *indio_dev,
 215                                                int *val, int *val2)
 216{
 217        int ret, reg;
 218        struct veml6030_data *data = iio_priv(indio_dev);
 219
 220        ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, &reg);
 221        if (ret) {
 222                dev_err(&data->client->dev,
 223                                "can't read als conf register %d\n", ret);
 224                return ret;
 225        }
 226
 227        switch ((reg >> 6) & 0xF) {
 228        case 0:
 229                *val2 = 100000;
 230                break;
 231        case 1:
 232                *val2 = 200000;
 233                break;
 234        case 2:
 235                *val2 = 400000;
 236                break;
 237        case 3:
 238                *val2 = 800000;
 239                break;
 240        case 8:
 241                *val2 = 50000;
 242                break;
 243        case 12:
 244                *val2 = 25000;
 245                break;
 246        default:
 247                return -EINVAL;
 248        }
 249
 250        *val = 0;
 251        return IIO_VAL_INT_PLUS_MICRO;
 252}
 253
 254static int veml6030_set_intgrn_tm(struct iio_dev *indio_dev,
 255                                                int val, int val2)
 256{
 257        int ret, new_int_time, int_idx;
 258        struct veml6030_data *data = iio_priv(indio_dev);
 259
 260        if (val)
 261                return -EINVAL;
 262
 263        switch (val2) {
 264        case 25000:
 265                new_int_time = 0x300;
 266                int_idx = 5;
 267                break;
 268        case 50000:
 269                new_int_time = 0x200;
 270                int_idx = 4;
 271                break;
 272        case 100000:
 273                new_int_time = 0x00;
 274                int_idx = 3;
 275                break;
 276        case 200000:
 277                new_int_time = 0x40;
 278                int_idx = 2;
 279                break;
 280        case 400000:
 281                new_int_time = 0x80;
 282                int_idx = 1;
 283                break;
 284        case 800000:
 285                new_int_time = 0xC0;
 286                int_idx = 0;
 287                break;
 288        default:
 289                return -EINVAL;
 290        }
 291
 292        ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
 293                                        VEML6030_ALS_IT, new_int_time);
 294        if (ret) {
 295                dev_err(&data->client->dev,
 296                                "can't update als integration time %d\n", ret);
 297                return ret;
 298        }
 299
 300        /*
 301         * Cache current integration time and update resolution. For every
 302         * increase in integration time to next level, resolution is halved
 303         * and vice-versa.
 304         */
 305        if (data->cur_integration_time < int_idx)
 306                data->cur_resolution <<= int_idx - data->cur_integration_time;
 307        else if (data->cur_integration_time > int_idx)
 308                data->cur_resolution >>= data->cur_integration_time - int_idx;
 309
 310        data->cur_integration_time = int_idx;
 311
 312        return ret;
 313}
 314
 315static int veml6030_read_persistence(struct iio_dev *indio_dev,
 316                                                int *val, int *val2)
 317{
 318        int ret, reg, period, x, y;
 319        struct veml6030_data *data = iio_priv(indio_dev);
 320
 321        ret = veml6030_get_intgrn_tm(indio_dev, &x, &y);
 322        if (ret < 0)
 323                return ret;
 324
 325        ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, &reg);
 326        if (ret) {
 327                dev_err(&data->client->dev,
 328                                "can't read als conf register %d\n", ret);
 329        }
 330
 331        /* integration time multiplied by 1/2/4/8 */
 332        period = y * (1 << ((reg >> 4) & 0x03));
 333
 334        *val = period / 1000000;
 335        *val2 = period % 1000000;
 336
 337        return IIO_VAL_INT_PLUS_MICRO;
 338}
 339
 340static int veml6030_write_persistence(struct iio_dev *indio_dev,
 341                                                int val, int val2)
 342{
 343        int ret, period, x, y;
 344        struct veml6030_data *data = iio_priv(indio_dev);
 345
 346        ret = veml6030_get_intgrn_tm(indio_dev, &x, &y);
 347        if (ret < 0)
 348                return ret;
 349
 350        if (!val) {
 351                period = val2 / y;
 352        } else {
 353                if ((val == 1) && (val2 == 600000))
 354                        period = 1600000 / y;
 355                else if ((val == 3) && (val2 == 200000))
 356                        period = 3200000 / y;
 357                else if ((val == 6) && (val2 == 400000))
 358                        period = 6400000 / y;
 359                else
 360                        period = -1;
 361        }
 362
 363        if (period <= 0 || period > 8 || hweight8(period) != 1)
 364                return -EINVAL;
 365
 366        ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
 367                                VEML6030_ALS_PERS, (ffs(period) - 1) << 4);
 368        if (ret)
 369                dev_err(&data->client->dev,
 370                                "can't set persistence value %d\n", ret);
 371
 372        return ret;
 373}
 374
 375static int veml6030_set_als_gain(struct iio_dev *indio_dev,
 376                                                int val, int val2)
 377{
 378        int ret, new_gain, gain_idx;
 379        struct veml6030_data *data = iio_priv(indio_dev);
 380
 381        if (val == 0 && val2 == 125000) {
 382                new_gain = 0x1000; /* 0x02 << 11 */
 383                gain_idx = 3;
 384        } else if (val == 0 && val2 == 250000) {
 385                new_gain = 0x1800;
 386                gain_idx = 2;
 387        } else if (val == 1 && val2 == 0) {
 388                new_gain = 0x00;
 389                gain_idx = 1;
 390        } else if (val == 2 && val2 == 0) {
 391                new_gain = 0x800;
 392                gain_idx = 0;
 393        } else {
 394                return -EINVAL;
 395        }
 396
 397        ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
 398                                        VEML6030_ALS_GAIN, new_gain);
 399        if (ret) {
 400                dev_err(&data->client->dev,
 401                                "can't set als gain %d\n", ret);
 402                return ret;
 403        }
 404
 405        /*
 406         * Cache currently set gain & update resolution. For every
 407         * increase in the gain to next level, resolution is halved
 408         * and vice-versa.
 409         */
 410        if (data->cur_gain < gain_idx)
 411                data->cur_resolution <<= gain_idx - data->cur_gain;
 412        else if (data->cur_gain > gain_idx)
 413                data->cur_resolution >>= data->cur_gain - gain_idx;
 414
 415        data->cur_gain = gain_idx;
 416
 417        return ret;
 418}
 419
 420static int veml6030_get_als_gain(struct iio_dev *indio_dev,
 421                                                int *val, int *val2)
 422{
 423        int ret, reg;
 424        struct veml6030_data *data = iio_priv(indio_dev);
 425
 426        ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, &reg);
 427        if (ret) {
 428                dev_err(&data->client->dev,
 429                                "can't read als conf register %d\n", ret);
 430                return ret;
 431        }
 432
 433        switch ((reg >> 11) & 0x03) {
 434        case 0:
 435                *val = 1;
 436                *val2 = 0;
 437                break;
 438        case 1:
 439                *val = 2;
 440                *val2 = 0;
 441                break;
 442        case 2:
 443                *val = 0;
 444                *val2 = 125000;
 445                break;
 446        case 3:
 447                *val = 0;
 448                *val2 = 250000;
 449                break;
 450        default:
 451                return -EINVAL;
 452        }
 453
 454        return IIO_VAL_INT_PLUS_MICRO;
 455}
 456
 457static int veml6030_read_thresh(struct iio_dev *indio_dev,
 458                                                int *val, int *val2, int dir)
 459{
 460        int ret, reg;
 461        struct veml6030_data *data = iio_priv(indio_dev);
 462
 463        if (dir == IIO_EV_DIR_RISING)
 464                ret = regmap_read(data->regmap, VEML6030_REG_ALS_WH, &reg);
 465        else
 466                ret = regmap_read(data->regmap, VEML6030_REG_ALS_WL, &reg);
 467        if (ret) {
 468                dev_err(&data->client->dev,
 469                                "can't read als threshold value %d\n", ret);
 470                return ret;
 471        }
 472
 473        *val = reg & 0xffff;
 474        return IIO_VAL_INT;
 475}
 476
 477static int veml6030_write_thresh(struct iio_dev *indio_dev,
 478                                                int val, int val2, int dir)
 479{
 480        int ret;
 481        struct veml6030_data *data = iio_priv(indio_dev);
 482
 483        if (val > 0xFFFF || val < 0 || val2)
 484                return -EINVAL;
 485
 486        if (dir == IIO_EV_DIR_RISING) {
 487                ret = regmap_write(data->regmap, VEML6030_REG_ALS_WH, val);
 488                if (ret)
 489                        dev_err(&data->client->dev,
 490                                        "can't set high threshold %d\n", ret);
 491        } else {
 492                ret = regmap_write(data->regmap, VEML6030_REG_ALS_WL, val);
 493                if (ret)
 494                        dev_err(&data->client->dev,
 495                                        "can't set low threshold %d\n", ret);
 496        }
 497
 498        return ret;
 499}
 500
 501/*
 502 * Provide both raw as well as light reading in lux.
 503 * light (in lux) = resolution * raw reading
 504 */
 505static int veml6030_read_raw(struct iio_dev *indio_dev,
 506                            struct iio_chan_spec const *chan, int *val,
 507                            int *val2, long mask)
 508{
 509        int ret, reg;
 510        struct veml6030_data *data = iio_priv(indio_dev);
 511        struct regmap *regmap = data->regmap;
 512        struct device *dev = &data->client->dev;
 513
 514        switch (mask) {
 515        case IIO_CHAN_INFO_RAW:
 516        case IIO_CHAN_INFO_PROCESSED:
 517                switch (chan->type) {
 518                case IIO_LIGHT:
 519                        ret = regmap_read(regmap, VEML6030_REG_ALS_DATA, &reg);
 520                        if (ret < 0) {
 521                                dev_err(dev, "can't read als data %d\n", ret);
 522                                return ret;
 523                        }
 524                        if (mask == IIO_CHAN_INFO_PROCESSED) {
 525                                *val = (reg * data->cur_resolution) / 10000;
 526                                *val2 = (reg * data->cur_resolution) % 10000;
 527                                return IIO_VAL_INT_PLUS_MICRO;
 528                        }
 529                        *val = reg;
 530                        return IIO_VAL_INT;
 531                case IIO_INTENSITY:
 532                        ret = regmap_read(regmap, VEML6030_REG_WH_DATA, &reg);
 533                        if (ret < 0) {
 534                                dev_err(dev, "can't read white data %d\n", ret);
 535                                return ret;
 536                        }
 537                        if (mask == IIO_CHAN_INFO_PROCESSED) {
 538                                *val = (reg * data->cur_resolution) / 10000;
 539                                *val2 = (reg * data->cur_resolution) % 10000;
 540                                return IIO_VAL_INT_PLUS_MICRO;
 541                        }
 542                        *val = reg;
 543                        return IIO_VAL_INT;
 544                default:
 545                        return -EINVAL;
 546                }
 547        case IIO_CHAN_INFO_INT_TIME:
 548                if (chan->type == IIO_LIGHT)
 549                        return veml6030_get_intgrn_tm(indio_dev, val, val2);
 550                return -EINVAL;
 551        case IIO_CHAN_INFO_SCALE:
 552                if (chan->type == IIO_LIGHT)
 553                        return veml6030_get_als_gain(indio_dev, val, val2);
 554                return -EINVAL;
 555        default:
 556                return -EINVAL;
 557        }
 558}
 559
 560static int veml6030_write_raw(struct iio_dev *indio_dev,
 561                                struct iio_chan_spec const *chan,
 562                                int val, int val2, long mask)
 563{
 564        switch (mask) {
 565        case IIO_CHAN_INFO_INT_TIME:
 566                switch (chan->type) {
 567                case IIO_LIGHT:
 568                        return veml6030_set_intgrn_tm(indio_dev, val, val2);
 569                default:
 570                        return -EINVAL;
 571                }
 572        case IIO_CHAN_INFO_SCALE:
 573                switch (chan->type) {
 574                case IIO_LIGHT:
 575                        return veml6030_set_als_gain(indio_dev, val, val2);
 576                default:
 577                        return -EINVAL;
 578                }
 579        default:
 580                return -EINVAL;
 581        }
 582}
 583
 584static int veml6030_read_event_val(struct iio_dev *indio_dev,
 585                const struct iio_chan_spec *chan, enum iio_event_type type,
 586                enum iio_event_direction dir, enum iio_event_info info,
 587                int *val, int *val2)
 588{
 589        switch (info) {
 590        case IIO_EV_INFO_VALUE:
 591                switch (dir) {
 592                case IIO_EV_DIR_RISING:
 593                case IIO_EV_DIR_FALLING:
 594                        return veml6030_read_thresh(indio_dev, val, val2, dir);
 595                default:
 596                        return -EINVAL;
 597                }
 598                break;
 599        case IIO_EV_INFO_PERIOD:
 600                return veml6030_read_persistence(indio_dev, val, val2);
 601        default:
 602                return -EINVAL;
 603        }
 604}
 605
 606static int veml6030_write_event_val(struct iio_dev *indio_dev,
 607                const struct iio_chan_spec *chan, enum iio_event_type type,
 608                enum iio_event_direction dir, enum iio_event_info info,
 609                int val, int val2)
 610{
 611        switch (info) {
 612        case IIO_EV_INFO_VALUE:
 613                return veml6030_write_thresh(indio_dev, val, val2, dir);
 614        case IIO_EV_INFO_PERIOD:
 615                return veml6030_write_persistence(indio_dev, val, val2);
 616        default:
 617                return -EINVAL;
 618        }
 619}
 620
 621static int veml6030_read_interrupt_config(struct iio_dev *indio_dev,
 622                const struct iio_chan_spec *chan, enum iio_event_type type,
 623                enum iio_event_direction dir)
 624{
 625        int ret, reg;
 626        struct veml6030_data *data = iio_priv(indio_dev);
 627
 628        ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, &reg);
 629        if (ret) {
 630                dev_err(&data->client->dev,
 631                                "can't read als conf register %d\n", ret);
 632                return ret;
 633        }
 634
 635        if (reg & VEML6030_ALS_INT_EN)
 636                return 1;
 637        else
 638                return 0;
 639}
 640
 641/*
 642 * Sensor should not be measuring light when interrupt is configured.
 643 * Therefore correct sequence to configure interrupt functionality is:
 644 * shut down -> enable/disable interrupt -> power on
 645 *
 646 * state = 1 enables interrupt, state = 0 disables interrupt
 647 */
 648static int veml6030_write_interrupt_config(struct iio_dev *indio_dev,
 649                const struct iio_chan_spec *chan, enum iio_event_type type,
 650                enum iio_event_direction dir, int state)
 651{
 652        int ret;
 653        struct veml6030_data *data = iio_priv(indio_dev);
 654
 655        if (state < 0 || state > 1)
 656                return -EINVAL;
 657
 658        ret = veml6030_als_shut_down(data);
 659        if (ret < 0) {
 660                dev_err(&data->client->dev,
 661                        "can't disable als to configure interrupt %d\n", ret);
 662                return ret;
 663        }
 664
 665        /* enable interrupt + power on */
 666        ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
 667                        VEML6030_ALS_INT_EN | VEML6030_ALS_SD, state << 1);
 668        if (ret)
 669                dev_err(&data->client->dev,
 670                        "can't enable interrupt & poweron als %d\n", ret);
 671
 672        return ret;
 673}
 674
 675static const struct iio_info veml6030_info = {
 676        .read_raw  = veml6030_read_raw,
 677        .write_raw = veml6030_write_raw,
 678        .read_event_value = veml6030_read_event_val,
 679        .write_event_value      = veml6030_write_event_val,
 680        .read_event_config = veml6030_read_interrupt_config,
 681        .write_event_config     = veml6030_write_interrupt_config,
 682        .attrs = &veml6030_attr_group,
 683        .event_attrs = &veml6030_event_attr_group,
 684};
 685
 686static const struct iio_info veml6030_info_no_irq = {
 687        .read_raw  = veml6030_read_raw,
 688        .write_raw = veml6030_write_raw,
 689        .attrs = &veml6030_attr_group,
 690};
 691
 692static irqreturn_t veml6030_event_handler(int irq, void *private)
 693{
 694        int ret, reg, evtdir;
 695        struct iio_dev *indio_dev = private;
 696        struct veml6030_data *data = iio_priv(indio_dev);
 697
 698        ret = regmap_read(data->regmap, VEML6030_REG_ALS_INT, &reg);
 699        if (ret) {
 700                dev_err(&data->client->dev,
 701                                "can't read als interrupt register %d\n", ret);
 702                return IRQ_HANDLED;
 703        }
 704
 705        /* Spurious interrupt handling */
 706        if (!(reg & (VEML6030_INT_TH_HIGH | VEML6030_INT_TH_LOW)))
 707                return IRQ_NONE;
 708
 709        if (reg & VEML6030_INT_TH_HIGH)
 710                evtdir = IIO_EV_DIR_RISING;
 711        else
 712                evtdir = IIO_EV_DIR_FALLING;
 713
 714        iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_INTENSITY,
 715                                        0, IIO_EV_TYPE_THRESH, evtdir),
 716                                        iio_get_time_ns(indio_dev));
 717
 718        return IRQ_HANDLED;
 719}
 720
 721/*
 722 * Set ALS gain to 1/8, integration time to 100 ms, PSM to mode 2,
 723 * persistence to 1 x integration time and the threshold
 724 * interrupt disabled by default. First shutdown the sensor,
 725 * update registers and then power on the sensor.
 726 */
 727static int veml6030_hw_init(struct iio_dev *indio_dev)
 728{
 729        int ret, val;
 730        struct veml6030_data *data = iio_priv(indio_dev);
 731        struct i2c_client *client = data->client;
 732
 733        ret = veml6030_als_shut_down(data);
 734        if (ret) {
 735                dev_err(&client->dev, "can't shutdown als %d\n", ret);
 736                return ret;
 737        }
 738
 739        ret = regmap_write(data->regmap, VEML6030_REG_ALS_CONF, 0x1001);
 740        if (ret) {
 741                dev_err(&client->dev, "can't setup als configs %d\n", ret);
 742                return ret;
 743        }
 744
 745        ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_PSM,
 746                                 VEML6030_PSM | VEML6030_PSM_EN, 0x03);
 747        if (ret) {
 748                dev_err(&client->dev, "can't setup default PSM %d\n", ret);
 749                return ret;
 750        }
 751
 752        ret = regmap_write(data->regmap, VEML6030_REG_ALS_WH, 0xFFFF);
 753        if (ret) {
 754                dev_err(&client->dev, "can't setup high threshold %d\n", ret);
 755                return ret;
 756        }
 757
 758        ret = regmap_write(data->regmap, VEML6030_REG_ALS_WL, 0x0000);
 759        if (ret) {
 760                dev_err(&client->dev, "can't setup low threshold %d\n", ret);
 761                return ret;
 762        }
 763
 764        ret = veml6030_als_pwr_on(data);
 765        if (ret) {
 766                dev_err(&client->dev, "can't poweron als %d\n", ret);
 767                return ret;
 768        }
 769
 770        /* Wait 4 ms to let processor & oscillator start correctly */
 771        usleep_range(4000, 4002);
 772
 773        /* Clear stale interrupt status bits if any during start */
 774        ret = regmap_read(data->regmap, VEML6030_REG_ALS_INT, &val);
 775        if (ret < 0) {
 776                dev_err(&client->dev,
 777                        "can't clear als interrupt status %d\n", ret);
 778                return ret;
 779        }
 780
 781        /* Cache currently active measurement parameters */
 782        data->cur_gain = 3;
 783        data->cur_resolution = 4608;
 784        data->cur_integration_time = 3;
 785
 786        return ret;
 787}
 788
 789static int veml6030_probe(struct i2c_client *client,
 790                          const struct i2c_device_id *id)
 791{
 792        int ret;
 793        struct veml6030_data *data;
 794        struct iio_dev *indio_dev;
 795        struct regmap *regmap;
 796
 797        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 798                dev_err(&client->dev, "i2c adapter doesn't support plain i2c\n");
 799                return -EOPNOTSUPP;
 800        }
 801
 802        regmap = devm_regmap_init_i2c(client, &veml6030_regmap_config);
 803        if (IS_ERR(regmap)) {
 804                dev_err(&client->dev, "can't setup regmap\n");
 805                return PTR_ERR(regmap);
 806        }
 807
 808        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 809        if (!indio_dev)
 810                return -ENOMEM;
 811
 812        data = iio_priv(indio_dev);
 813        i2c_set_clientdata(client, indio_dev);
 814        data->client = client;
 815        data->regmap = regmap;
 816
 817        indio_dev->name = "veml6030";
 818        indio_dev->channels = veml6030_channels;
 819        indio_dev->num_channels = ARRAY_SIZE(veml6030_channels);
 820        indio_dev->modes = INDIO_DIRECT_MODE;
 821
 822        if (client->irq) {
 823                ret = devm_request_threaded_irq(&client->dev, client->irq,
 824                                                NULL, veml6030_event_handler,
 825                                                IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 826                                                "veml6030", indio_dev);
 827                if (ret < 0) {
 828                        dev_err(&client->dev,
 829                                        "irq %d request failed\n", client->irq);
 830                        return ret;
 831                }
 832                indio_dev->info = &veml6030_info;
 833        } else {
 834                indio_dev->info = &veml6030_info_no_irq;
 835        }
 836
 837        ret = veml6030_hw_init(indio_dev);
 838        if (ret < 0)
 839                return ret;
 840
 841        ret = devm_add_action_or_reset(&client->dev,
 842                                        veml6030_als_shut_down_action, data);
 843        if (ret < 0)
 844                return ret;
 845
 846        return devm_iio_device_register(&client->dev, indio_dev);
 847}
 848
 849static int __maybe_unused veml6030_runtime_suspend(struct device *dev)
 850{
 851        int ret;
 852        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 853        struct veml6030_data *data = iio_priv(indio_dev);
 854
 855        ret = veml6030_als_shut_down(data);
 856        if (ret < 0)
 857                dev_err(&data->client->dev, "can't suspend als %d\n", ret);
 858
 859        return ret;
 860}
 861
 862static int __maybe_unused veml6030_runtime_resume(struct device *dev)
 863{
 864        int ret;
 865        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 866        struct veml6030_data *data = iio_priv(indio_dev);
 867
 868        ret = veml6030_als_pwr_on(data);
 869        if (ret < 0)
 870                dev_err(&data->client->dev, "can't resume als %d\n", ret);
 871
 872        return ret;
 873}
 874
 875static const struct dev_pm_ops veml6030_pm_ops = {
 876        SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 877                                pm_runtime_force_resume)
 878        SET_RUNTIME_PM_OPS(veml6030_runtime_suspend,
 879                                veml6030_runtime_resume, NULL)
 880};
 881
 882static const struct of_device_id veml6030_of_match[] = {
 883        { .compatible = "vishay,veml6030" },
 884        { }
 885};
 886MODULE_DEVICE_TABLE(of, veml6030_of_match);
 887
 888static const struct i2c_device_id veml6030_id[] = {
 889        { "veml6030", 0 },
 890        { }
 891};
 892MODULE_DEVICE_TABLE(i2c, veml6030_id);
 893
 894static struct i2c_driver veml6030_driver = {
 895        .driver = {
 896                .name = "veml6030",
 897                .of_match_table = veml6030_of_match,
 898                .pm = &veml6030_pm_ops,
 899        },
 900        .probe = veml6030_probe,
 901        .id_table = veml6030_id,
 902};
 903module_i2c_driver(veml6030_driver);
 904
 905MODULE_AUTHOR("Rishi Gupta <gupt21@gmail.com>");
 906MODULE_DESCRIPTION("VEML6030 Ambient Light Sensor");
 907MODULE_LICENSE("GPL v2");
 908