linux/drivers/iio/light/vcnl4035.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * VCNL4035 Ambient Light and Proximity Sensor - 7-bit I2C slave address 0x60
   4 *
   5 * Copyright (c) 2018, DENX Software Engineering GmbH
   6 * Author: Parthiban Nallathambi <pn@denx.de>
   7 *
   8 * TODO: Proximity
   9 */
  10#include <linux/bitops.h>
  11#include <linux/i2c.h>
  12#include <linux/module.h>
  13#include <linux/pm_runtime.h>
  14#include <linux/regmap.h>
  15
  16#include <linux/iio/buffer.h>
  17#include <linux/iio/events.h>
  18#include <linux/iio/iio.h>
  19#include <linux/iio/sysfs.h>
  20#include <linux/iio/trigger.h>
  21#include <linux/iio/trigger_consumer.h>
  22#include <linux/iio/triggered_buffer.h>
  23
  24#define VCNL4035_DRV_NAME       "vcnl4035"
  25#define VCNL4035_IRQ_NAME       "vcnl4035_event"
  26#define VCNL4035_REGMAP_NAME    "vcnl4035_regmap"
  27
  28/* Device registers */
  29#define VCNL4035_ALS_CONF       0x00
  30#define VCNL4035_ALS_THDH       0x01
  31#define VCNL4035_ALS_THDL       0x02
  32#define VCNL4035_ALS_DATA       0x0B
  33#define VCNL4035_WHITE_DATA     0x0C
  34#define VCNL4035_INT_FLAG       0x0D
  35#define VCNL4035_DEV_ID         0x0E
  36
  37/* Register masks */
  38#define VCNL4035_MODE_ALS_MASK          BIT(0)
  39#define VCNL4035_MODE_ALS_WHITE_CHAN    BIT(8)
  40#define VCNL4035_MODE_ALS_INT_MASK      BIT(1)
  41#define VCNL4035_ALS_IT_MASK            GENMASK(7, 5)
  42#define VCNL4035_ALS_PERS_MASK          GENMASK(3, 2)
  43#define VCNL4035_INT_ALS_IF_H_MASK      BIT(12)
  44#define VCNL4035_INT_ALS_IF_L_MASK      BIT(13)
  45
  46/* Default values */
  47#define VCNL4035_MODE_ALS_ENABLE        BIT(0)
  48#define VCNL4035_MODE_ALS_DISABLE       0x00
  49#define VCNL4035_MODE_ALS_INT_ENABLE    BIT(1)
  50#define VCNL4035_MODE_ALS_INT_DISABLE   0
  51#define VCNL4035_DEV_ID_VAL             0x80
  52#define VCNL4035_ALS_IT_DEFAULT         0x01
  53#define VCNL4035_ALS_PERS_DEFAULT       0x00
  54#define VCNL4035_ALS_THDH_DEFAULT       5000
  55#define VCNL4035_ALS_THDL_DEFAULT       100
  56#define VCNL4035_SLEEP_DELAY_MS         2000
  57
  58struct vcnl4035_data {
  59        struct i2c_client *client;
  60        struct regmap *regmap;
  61        unsigned int als_it_val;
  62        unsigned int als_persistence;
  63        unsigned int als_thresh_low;
  64        unsigned int als_thresh_high;
  65        struct iio_trigger *drdy_trigger0;
  66};
  67
  68static inline bool vcnl4035_is_triggered(struct vcnl4035_data *data)
  69{
  70        int ret;
  71        int reg;
  72
  73        ret = regmap_read(data->regmap, VCNL4035_INT_FLAG, &reg);
  74        if (ret < 0)
  75                return false;
  76
  77        return !!(reg &
  78                (VCNL4035_INT_ALS_IF_H_MASK | VCNL4035_INT_ALS_IF_L_MASK));
  79}
  80
  81static irqreturn_t vcnl4035_drdy_irq_thread(int irq, void *private)
  82{
  83        struct iio_dev *indio_dev = private;
  84        struct vcnl4035_data *data = iio_priv(indio_dev);
  85
  86        if (vcnl4035_is_triggered(data)) {
  87                iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
  88                                                        0,
  89                                                        IIO_EV_TYPE_THRESH,
  90                                                        IIO_EV_DIR_EITHER),
  91                                iio_get_time_ns(indio_dev));
  92                iio_trigger_poll_chained(data->drdy_trigger0);
  93                return IRQ_HANDLED;
  94        }
  95
  96        return IRQ_NONE;
  97}
  98
  99/* Triggered buffer */
 100static irqreturn_t vcnl4035_trigger_consumer_handler(int irq, void *p)
 101{
 102        struct iio_poll_func *pf = p;
 103        struct iio_dev *indio_dev = pf->indio_dev;
 104        struct vcnl4035_data *data = iio_priv(indio_dev);
 105        u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)];
 106        int ret;
 107
 108        ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer);
 109        if (ret < 0) {
 110                dev_err(&data->client->dev,
 111                        "Trigger consumer can't read from sensor.\n");
 112                goto fail_read;
 113        }
 114        iio_push_to_buffers_with_timestamp(indio_dev, buffer,
 115                                        iio_get_time_ns(indio_dev));
 116
 117fail_read:
 118        iio_trigger_notify_done(indio_dev->trig);
 119
 120        return IRQ_HANDLED;
 121}
 122
 123static int vcnl4035_als_drdy_set_state(struct iio_trigger *trigger,
 124                                        bool enable_drdy)
 125{
 126        struct iio_dev *indio_dev = iio_trigger_get_drvdata(trigger);
 127        struct vcnl4035_data *data = iio_priv(indio_dev);
 128        int val = enable_drdy ? VCNL4035_MODE_ALS_INT_ENABLE :
 129                                        VCNL4035_MODE_ALS_INT_DISABLE;
 130
 131        return regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
 132                                 VCNL4035_MODE_ALS_INT_MASK,
 133                                 val);
 134}
 135
 136static const struct iio_trigger_ops vcnl4035_trigger_ops = {
 137        .validate_device = iio_trigger_validate_own_device,
 138        .set_trigger_state = vcnl4035_als_drdy_set_state,
 139};
 140
 141static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on)
 142{
 143        int ret;
 144        struct device *dev = &data->client->dev;
 145
 146        if (on) {
 147                ret = pm_runtime_get_sync(dev);
 148                if (ret < 0)
 149                        pm_runtime_put_noidle(dev);
 150        } else {
 151                pm_runtime_mark_last_busy(dev);
 152                ret = pm_runtime_put_autosuspend(dev);
 153        }
 154
 155        return ret;
 156}
 157
 158/*
 159 *      Device IT       INT Time (ms)   Scale (lux/step)
 160 *      000             50              0.064
 161 *      001             100             0.032
 162 *      010             200             0.016
 163 *      100             400             0.008
 164 *      101 - 111       800             0.004
 165 * Values are proportional, so ALS INT is selected for input due to
 166 * simplicity reason. Integration time value and scaling is
 167 * calculated based on device INT value
 168 *
 169 * Raw value needs to be scaled using ALS steps
 170 */
 171static int vcnl4035_read_raw(struct iio_dev *indio_dev,
 172                            struct iio_chan_spec const *chan, int *val,
 173                            int *val2, long mask)
 174{
 175        struct vcnl4035_data *data = iio_priv(indio_dev);
 176        int ret;
 177        int raw_data;
 178        unsigned int reg;
 179
 180        switch (mask) {
 181        case IIO_CHAN_INFO_RAW:
 182                ret = vcnl4035_set_pm_runtime_state(data, true);
 183                if  (ret < 0)
 184                        return ret;
 185
 186                ret = iio_device_claim_direct_mode(indio_dev);
 187                if (!ret) {
 188                        if (chan->channel)
 189                                reg = VCNL4035_ALS_DATA;
 190                        else
 191                                reg = VCNL4035_WHITE_DATA;
 192                        ret = regmap_read(data->regmap, reg, &raw_data);
 193                        iio_device_release_direct_mode(indio_dev);
 194                        if (!ret) {
 195                                *val = raw_data;
 196                                ret = IIO_VAL_INT;
 197                        }
 198                }
 199                vcnl4035_set_pm_runtime_state(data, false);
 200                return ret;
 201        case IIO_CHAN_INFO_INT_TIME:
 202                *val = 50;
 203                if (data->als_it_val)
 204                        *val = data->als_it_val * 100;
 205                return IIO_VAL_INT;
 206        case IIO_CHAN_INFO_SCALE:
 207                *val = 64;
 208                if (!data->als_it_val)
 209                        *val2 = 1000;
 210                else
 211                        *val2 = data->als_it_val * 2 * 1000;
 212                return IIO_VAL_FRACTIONAL;
 213        default:
 214                return -EINVAL;
 215        }
 216}
 217
 218static int vcnl4035_write_raw(struct iio_dev *indio_dev,
 219                                struct iio_chan_spec const *chan,
 220                                int val, int val2, long mask)
 221{
 222        int ret;
 223        struct vcnl4035_data *data = iio_priv(indio_dev);
 224
 225        switch (mask) {
 226        case IIO_CHAN_INFO_INT_TIME:
 227                if (val <= 0 || val > 800)
 228                        return -EINVAL;
 229
 230                ret = vcnl4035_set_pm_runtime_state(data, true);
 231                if  (ret < 0)
 232                        return ret;
 233
 234                ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
 235                                         VCNL4035_ALS_IT_MASK,
 236                                         val / 100);
 237                if (!ret)
 238                        data->als_it_val = val / 100;
 239
 240                vcnl4035_set_pm_runtime_state(data, false);
 241                return ret;
 242        default:
 243                return -EINVAL;
 244        }
 245}
 246
 247/* No direct ABI for persistence and threshold, so eventing */
 248static int vcnl4035_read_thresh(struct iio_dev *indio_dev,
 249                const struct iio_chan_spec *chan, enum iio_event_type type,
 250                enum iio_event_direction dir, enum iio_event_info info,
 251                int *val, int *val2)
 252{
 253        struct vcnl4035_data *data = iio_priv(indio_dev);
 254
 255        switch (info) {
 256        case IIO_EV_INFO_VALUE:
 257                switch (dir) {
 258                case IIO_EV_DIR_RISING:
 259                        *val = data->als_thresh_high;
 260                        return IIO_VAL_INT;
 261                case IIO_EV_DIR_FALLING:
 262                        *val = data->als_thresh_low;
 263                        return IIO_VAL_INT;
 264                default:
 265                        return -EINVAL;
 266                }
 267                break;
 268        case IIO_EV_INFO_PERIOD:
 269                *val = data->als_persistence;
 270                return IIO_VAL_INT;
 271        default:
 272                return -EINVAL;
 273        }
 274
 275}
 276
 277static int vcnl4035_write_thresh(struct iio_dev *indio_dev,
 278                const struct iio_chan_spec *chan, enum iio_event_type type,
 279                enum iio_event_direction dir, enum iio_event_info info, int val,
 280                int val2)
 281{
 282        struct vcnl4035_data *data = iio_priv(indio_dev);
 283        int ret;
 284
 285        switch (info) {
 286        case IIO_EV_INFO_VALUE:
 287                /* 16 bit threshold range 0 - 65535 */
 288                if (val < 0 || val > 65535)
 289                        return -EINVAL;
 290                if (dir == IIO_EV_DIR_RISING) {
 291                        if (val < data->als_thresh_low)
 292                                return -EINVAL;
 293                        ret = regmap_write(data->regmap, VCNL4035_ALS_THDH,
 294                                           val);
 295                        if (ret)
 296                                return ret;
 297                        data->als_thresh_high = val;
 298                } else {
 299                        if (val > data->als_thresh_high)
 300                                return -EINVAL;
 301                        ret = regmap_write(data->regmap, VCNL4035_ALS_THDL,
 302                                           val);
 303                        if (ret)
 304                                return ret;
 305                        data->als_thresh_low = val;
 306                }
 307                return ret;
 308        case IIO_EV_INFO_PERIOD:
 309                /* allow only 1 2 4 8 as persistence value */
 310                if (val < 0 || val > 8 || hweight8(val) != 1)
 311                        return -EINVAL;
 312                ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
 313                                         VCNL4035_ALS_PERS_MASK, val);
 314                if (!ret)
 315                        data->als_persistence = val;
 316                return ret;
 317        default:
 318                return -EINVAL;
 319        }
 320}
 321
 322static IIO_CONST_ATTR_INT_TIME_AVAIL("50 100 200 400 800");
 323
 324static struct attribute *vcnl4035_attributes[] = {
 325        &iio_const_attr_integration_time_available.dev_attr.attr,
 326        NULL,
 327};
 328
 329static const struct attribute_group vcnl4035_attribute_group = {
 330        .attrs = vcnl4035_attributes,
 331};
 332
 333static const struct iio_info vcnl4035_info = {
 334        .read_raw               = vcnl4035_read_raw,
 335        .write_raw              = vcnl4035_write_raw,
 336        .read_event_value       = vcnl4035_read_thresh,
 337        .write_event_value      = vcnl4035_write_thresh,
 338        .attrs                  = &vcnl4035_attribute_group,
 339};
 340
 341static const struct iio_event_spec vcnl4035_event_spec[] = {
 342        {
 343                .type = IIO_EV_TYPE_THRESH,
 344                .dir = IIO_EV_DIR_RISING,
 345                .mask_separate = BIT(IIO_EV_INFO_VALUE),
 346        }, {
 347                .type = IIO_EV_TYPE_THRESH,
 348                .dir = IIO_EV_DIR_FALLING,
 349                .mask_separate = BIT(IIO_EV_INFO_VALUE),
 350        }, {
 351                .type = IIO_EV_TYPE_THRESH,
 352                .dir = IIO_EV_DIR_EITHER,
 353                .mask_separate = BIT(IIO_EV_INFO_PERIOD),
 354        },
 355};
 356
 357enum vcnl4035_scan_index_order {
 358        VCNL4035_CHAN_INDEX_LIGHT,
 359        VCNL4035_CHAN_INDEX_WHITE_LED,
 360};
 361
 362static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
 363        .validate_scan_mask = &iio_validate_scan_mask_onehot,
 364};
 365
 366static const struct iio_chan_spec vcnl4035_channels[] = {
 367        {
 368                .type = IIO_LIGHT,
 369                .channel = 0,
 370                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 371                                BIT(IIO_CHAN_INFO_INT_TIME) |
 372                                BIT(IIO_CHAN_INFO_SCALE),
 373                .event_spec = vcnl4035_event_spec,
 374                .num_event_specs = ARRAY_SIZE(vcnl4035_event_spec),
 375                .scan_index = VCNL4035_CHAN_INDEX_LIGHT,
 376                .scan_type = {
 377                        .sign = 'u',
 378                        .realbits = 16,
 379                        .storagebits = 16,
 380                        .endianness = IIO_LE,
 381                },
 382        },
 383        {
 384                .type = IIO_INTENSITY,
 385                .channel = 1,
 386                .modified = 1,
 387                .channel2 = IIO_MOD_LIGHT_BOTH,
 388                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
 389                .scan_index = VCNL4035_CHAN_INDEX_WHITE_LED,
 390                .scan_type = {
 391                        .sign = 'u',
 392                        .realbits = 16,
 393                        .storagebits = 16,
 394                        .endianness = IIO_LE,
 395                },
 396        },
 397};
 398
 399static int vcnl4035_set_als_power_state(struct vcnl4035_data *data, u8 status)
 400{
 401        return regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
 402                                        VCNL4035_MODE_ALS_MASK,
 403                                        status);
 404}
 405
 406static int vcnl4035_init(struct vcnl4035_data *data)
 407{
 408        int ret;
 409        int id;
 410
 411        ret = regmap_read(data->regmap, VCNL4035_DEV_ID, &id);
 412        if (ret < 0) {
 413                dev_err(&data->client->dev, "Failed to read DEV_ID register\n");
 414                return ret;
 415        }
 416
 417        if (id != VCNL4035_DEV_ID_VAL) {
 418                dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n",
 419                        id, VCNL4035_DEV_ID_VAL);
 420                return -ENODEV;
 421        }
 422
 423        ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
 424        if (ret < 0)
 425                return ret;
 426
 427        /* ALS white channel enable */
 428        ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
 429                                 VCNL4035_MODE_ALS_WHITE_CHAN,
 430                                 1);
 431        if (ret) {
 432                dev_err(&data->client->dev, "set white channel enable %d\n",
 433                        ret);
 434                return ret;
 435        }
 436
 437        /* set default integration time - 100 ms for ALS */
 438        ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
 439                                 VCNL4035_ALS_IT_MASK,
 440                                 VCNL4035_ALS_IT_DEFAULT);
 441        if (ret) {
 442                dev_err(&data->client->dev, "set default ALS IT returned %d\n",
 443                        ret);
 444                return ret;
 445        }
 446        data->als_it_val = VCNL4035_ALS_IT_DEFAULT;
 447
 448        /* set default persistence time - 1 for ALS */
 449        ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
 450                                 VCNL4035_ALS_PERS_MASK,
 451                                 VCNL4035_ALS_PERS_DEFAULT);
 452        if (ret) {
 453                dev_err(&data->client->dev, "set default PERS returned %d\n",
 454                        ret);
 455                return ret;
 456        }
 457        data->als_persistence = VCNL4035_ALS_PERS_DEFAULT;
 458
 459        /* set default HIGH threshold for ALS */
 460        ret = regmap_write(data->regmap, VCNL4035_ALS_THDH,
 461                                VCNL4035_ALS_THDH_DEFAULT);
 462        if (ret) {
 463                dev_err(&data->client->dev, "set default THDH returned %d\n",
 464                        ret);
 465                return ret;
 466        }
 467        data->als_thresh_high = VCNL4035_ALS_THDH_DEFAULT;
 468
 469        /* set default LOW threshold for ALS */
 470        ret = regmap_write(data->regmap, VCNL4035_ALS_THDL,
 471                                VCNL4035_ALS_THDL_DEFAULT);
 472        if (ret) {
 473                dev_err(&data->client->dev, "set default THDL returned %d\n",
 474                        ret);
 475                return ret;
 476        }
 477        data->als_thresh_low = VCNL4035_ALS_THDL_DEFAULT;
 478
 479        return 0;
 480}
 481
 482static bool vcnl4035_is_volatile_reg(struct device *dev, unsigned int reg)
 483{
 484        switch (reg) {
 485        case VCNL4035_ALS_CONF:
 486        case VCNL4035_DEV_ID:
 487                return false;
 488        default:
 489                return true;
 490        }
 491}
 492
 493static const struct regmap_config vcnl4035_regmap_config = {
 494        .name           = VCNL4035_REGMAP_NAME,
 495        .reg_bits       = 8,
 496        .val_bits       = 16,
 497        .max_register   = VCNL4035_DEV_ID,
 498        .cache_type     = REGCACHE_RBTREE,
 499        .volatile_reg   = vcnl4035_is_volatile_reg,
 500        .val_format_endian = REGMAP_ENDIAN_LITTLE,
 501};
 502
 503static int vcnl4035_probe_trigger(struct iio_dev *indio_dev)
 504{
 505        int ret;
 506        struct vcnl4035_data *data = iio_priv(indio_dev);
 507
 508        data->drdy_trigger0 = devm_iio_trigger_alloc(
 509                        indio_dev->dev.parent,
 510                        "%s-dev%d", indio_dev->name, indio_dev->id);
 511        if (!data->drdy_trigger0)
 512                return -ENOMEM;
 513
 514        data->drdy_trigger0->dev.parent = indio_dev->dev.parent;
 515        data->drdy_trigger0->ops = &vcnl4035_trigger_ops;
 516        iio_trigger_set_drvdata(data->drdy_trigger0, indio_dev);
 517        ret = devm_iio_trigger_register(indio_dev->dev.parent,
 518                                        data->drdy_trigger0);
 519        if (ret) {
 520                dev_err(&data->client->dev, "iio trigger register failed\n");
 521                return ret;
 522        }
 523
 524        /* Trigger setup */
 525        ret = devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
 526                                        NULL, vcnl4035_trigger_consumer_handler,
 527                                        &iio_triggered_buffer_setup_ops);
 528        if (ret < 0) {
 529                dev_err(&data->client->dev, "iio triggered buffer setup failed\n");
 530                return ret;
 531        }
 532
 533        /* IRQ to trigger mapping */
 534        ret = devm_request_threaded_irq(&data->client->dev, data->client->irq,
 535                        NULL, vcnl4035_drdy_irq_thread,
 536                        IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 537                        VCNL4035_IRQ_NAME, indio_dev);
 538        if (ret < 0)
 539                dev_err(&data->client->dev, "request irq %d for trigger0 failed\n",
 540                                data->client->irq);
 541        return ret;
 542}
 543
 544static int vcnl4035_probe(struct i2c_client *client,
 545                                const struct i2c_device_id *id)
 546{
 547        struct vcnl4035_data *data;
 548        struct iio_dev *indio_dev;
 549        struct regmap *regmap;
 550        int ret;
 551
 552        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 553        if (!indio_dev)
 554                return -ENOMEM;
 555
 556        regmap = devm_regmap_init_i2c(client, &vcnl4035_regmap_config);
 557        if (IS_ERR(regmap)) {
 558                dev_err(&client->dev, "regmap_init failed!\n");
 559                return PTR_ERR(regmap);
 560        }
 561
 562        data = iio_priv(indio_dev);
 563        i2c_set_clientdata(client, indio_dev);
 564        data->client = client;
 565        data->regmap = regmap;
 566
 567        indio_dev->dev.parent = &client->dev;
 568        indio_dev->info = &vcnl4035_info;
 569        indio_dev->name = VCNL4035_DRV_NAME;
 570        indio_dev->channels = vcnl4035_channels;
 571        indio_dev->num_channels = ARRAY_SIZE(vcnl4035_channels);
 572        indio_dev->modes = INDIO_DIRECT_MODE;
 573
 574        ret = vcnl4035_init(data);
 575        if (ret < 0) {
 576                dev_err(&client->dev, "vcnl4035 chip init failed\n");
 577                return ret;
 578        }
 579
 580        if (client->irq > 0) {
 581                ret = vcnl4035_probe_trigger(indio_dev);
 582                if (ret < 0) {
 583                        dev_err(&client->dev, "vcnl4035 unable init trigger\n");
 584                        goto fail_poweroff;
 585                }
 586        }
 587
 588        ret = pm_runtime_set_active(&client->dev);
 589        if (ret < 0)
 590                goto fail_poweroff;
 591
 592        ret = iio_device_register(indio_dev);
 593        if (ret < 0)
 594                goto fail_poweroff;
 595
 596        pm_runtime_enable(&client->dev);
 597        pm_runtime_set_autosuspend_delay(&client->dev, VCNL4035_SLEEP_DELAY_MS);
 598        pm_runtime_use_autosuspend(&client->dev);
 599
 600        return 0;
 601
 602fail_poweroff:
 603        vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_DISABLE);
 604        return ret;
 605}
 606
 607static int vcnl4035_remove(struct i2c_client *client)
 608{
 609        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 610
 611        pm_runtime_dont_use_autosuspend(&client->dev);
 612        pm_runtime_disable(&client->dev);
 613        iio_device_unregister(indio_dev);
 614        pm_runtime_set_suspended(&client->dev);
 615
 616        return vcnl4035_set_als_power_state(iio_priv(indio_dev),
 617                                        VCNL4035_MODE_ALS_DISABLE);
 618}
 619
 620static int __maybe_unused vcnl4035_runtime_suspend(struct device *dev)
 621{
 622        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 623        struct vcnl4035_data *data = iio_priv(indio_dev);
 624        int ret;
 625
 626        ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_DISABLE);
 627        regcache_mark_dirty(data->regmap);
 628
 629        return ret;
 630}
 631
 632static int __maybe_unused vcnl4035_runtime_resume(struct device *dev)
 633{
 634        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 635        struct vcnl4035_data *data = iio_priv(indio_dev);
 636        int ret;
 637
 638        regcache_sync(data->regmap);
 639        ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
 640        if (ret < 0)
 641                return ret;
 642
 643        /* wait for 1 ALS integration cycle */
 644        msleep(data->als_it_val * 100);
 645
 646        return 0;
 647}
 648
 649static const struct dev_pm_ops vcnl4035_pm_ops = {
 650        SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 651                                pm_runtime_force_resume)
 652        SET_RUNTIME_PM_OPS(vcnl4035_runtime_suspend,
 653                           vcnl4035_runtime_resume, NULL)
 654};
 655
 656static const struct of_device_id vcnl4035_of_match[] = {
 657        { .compatible = "vishay,vcnl4035", },
 658        { }
 659};
 660MODULE_DEVICE_TABLE(of, vcnl4035_of_match);
 661
 662static struct i2c_driver vcnl4035_driver = {
 663        .driver = {
 664                .name   = VCNL4035_DRV_NAME,
 665                .pm     = &vcnl4035_pm_ops,
 666                .of_match_table = vcnl4035_of_match,
 667        },
 668        .probe  = vcnl4035_probe,
 669        .remove = vcnl4035_remove,
 670};
 671
 672module_i2c_driver(vcnl4035_driver);
 673
 674MODULE_AUTHOR("Parthiban Nallathambi <pn@denx.de>");
 675MODULE_DESCRIPTION("VCNL4035 Ambient Light Sensor driver");
 676MODULE_LICENSE("GPL v2");
 677