2123 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4040/4200 combined ambient4 * light and proximity sensor5 *6 * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>7 * Copyright 2019 Pursim SPC8 * Copyright 2020 Mathieu Othacehe <m.othacehe@gmail.com>9 *10 * IIO driver for:11 * VCNL4000/10/20 (7-bit I2C slave address 0x13)12 * VCNL4040 (7-bit I2C slave address 0x60)13 * VCNL4200 (7-bit I2C slave address 0x51)14 *15 * TODO:16 * allow to adjust IR current17 * interrupts (VCNL4040, VCNL4200)18 */19 20#include <linux/bitfield.h>21#include <linux/module.h>22#include <linux/i2c.h>23#include <linux/err.h>24#include <linux/delay.h>25#include <linux/pm_runtime.h>26#include <linux/interrupt.h>27#include <linux/units.h>28 29#include <linux/iio/buffer.h>30#include <linux/iio/events.h>31#include <linux/iio/iio.h>32#include <linux/iio/sysfs.h>33#include <linux/iio/trigger.h>34#include <linux/iio/trigger_consumer.h>35#include <linux/iio/triggered_buffer.h>36 37#define VCNL4000_DRV_NAME "vcnl4000"38#define VCNL4000_PROD_ID 0x0139#define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */40#define VCNL4040_PROD_ID 0x8641#define VCNL4200_PROD_ID 0x5842 43#define VCNL4000_COMMAND 0x80 /* Command register */44#define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */45#define VCNL4010_PROX_RATE 0x82 /* Proximity rate */46#define VCNL4000_LED_CURRENT 0x83 /* IR LED current for proximity mode */47#define VCNL4000_AL_PARAM 0x84 /* Ambient light parameter register */48#define VCNL4010_ALS_PARAM 0x84 /* ALS rate */49#define VCNL4000_AL_RESULT_HI 0x85 /* Ambient light result register, MSB */50#define VCNL4000_AL_RESULT_LO 0x86 /* Ambient light result register, LSB */51#define VCNL4000_PS_RESULT_HI 0x87 /* Proximity result register, MSB */52#define VCNL4000_PS_RESULT_LO 0x88 /* Proximity result register, LSB */53#define VCNL4000_PS_MEAS_FREQ 0x89 /* Proximity test signal frequency */54#define VCNL4010_INT_CTRL 0x89 /* Interrupt control */55#define VCNL4000_PS_MOD_ADJ 0x8a /* Proximity modulator timing adjustment */56#define VCNL4010_LOW_THR_HI 0x8a /* Low threshold, MSB */57#define VCNL4010_LOW_THR_LO 0x8b /* Low threshold, LSB */58#define VCNL4010_HIGH_THR_HI 0x8c /* High threshold, MSB */59#define VCNL4010_HIGH_THR_LO 0x8d /* High threshold, LSB */60#define VCNL4010_ISR 0x8e /* Interrupt status */61 62#define VCNL4200_AL_CONF 0x00 /* Ambient light configuration */63#define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */64#define VCNL4200_PS_CONF3 0x04 /* Proximity configuration */65#define VCNL4040_PS_THDL_LM 0x06 /* Proximity threshold low */66#define VCNL4040_PS_THDH_LM 0x07 /* Proximity threshold high */67#define VCNL4040_ALS_THDL_LM 0x02 /* Ambient light threshold low */68#define VCNL4040_ALS_THDH_LM 0x01 /* Ambient light threshold high */69#define VCNL4200_PS_DATA 0x08 /* Proximity data */70#define VCNL4200_AL_DATA 0x09 /* Ambient light data */71#define VCNL4040_INT_FLAGS 0x0b /* Interrupt register */72#define VCNL4200_INT_FLAGS 0x0d /* Interrupt register */73#define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */74 75#define VCNL4040_DEV_ID 0x0c /* Device ID and version */76 77/* Bit masks for COMMAND register */78#define VCNL4000_AL_RDY BIT(6) /* ALS data ready? */79#define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */80#define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */81#define VCNL4000_PS_OD BIT(3) /* start on-demand proximity measurement */82#define VCNL4000_ALS_EN BIT(2) /* start ALS measurement */83#define VCNL4000_PROX_EN BIT(1) /* start proximity measurement */84#define VCNL4000_SELF_TIMED_EN BIT(0) /* start self-timed measurement */85 86#define VCNL4040_ALS_CONF_ALS_SHUTDOWN BIT(0)87#define VCNL4040_ALS_CONF_IT GENMASK(7, 6) /* Ambient integration time */88#define VCNL4040_ALS_CONF_INT_EN BIT(1) /* Ambient light Interrupt enable */89#define VCNL4040_ALS_CONF_PERS GENMASK(3, 2) /* Ambient interrupt persistence setting */90#define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0)91#define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */92#define VCNL4040_CONF1_PS_PERS GENMASK(5, 4) /* Proximity interrupt persistence setting */93#define VCNL4040_PS_CONF2_PS_HD BIT(11) /* Proximity high definition */94#define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */95#define VCNL4040_PS_CONF3_MPS GENMASK(6, 5) /* Proximity multi pulse number */96#define VCNL4040_PS_MS_LED_I GENMASK(10, 8) /* Proximity current */97#define VCNL4040_PS_IF_AWAY BIT(8) /* Proximity event cross low threshold */98#define VCNL4040_PS_IF_CLOSE BIT(9) /* Proximity event cross high threshold */99#define VCNL4040_ALS_RISING BIT(12) /* Ambient Light cross high threshold */100#define VCNL4040_ALS_FALLING BIT(13) /* Ambient Light cross low threshold */101 102/* Bit masks for interrupt registers. */103#define VCNL4010_INT_THR_SEL BIT(0) /* Select threshold interrupt source */104#define VCNL4010_INT_THR_EN BIT(1) /* Threshold interrupt type */105#define VCNL4010_INT_ALS_EN BIT(2) /* Enable on ALS data ready */106#define VCNL4010_INT_PROX_EN BIT(3) /* Enable on proximity data ready */107 108#define VCNL4010_INT_THR_HIGH 0 /* High threshold exceeded */109#define VCNL4010_INT_THR_LOW 1 /* Low threshold exceeded */110#define VCNL4010_INT_ALS 2 /* ALS data ready */111#define VCNL4010_INT_PROXIMITY 3 /* Proximity data ready */112 113#define VCNL4010_INT_THR \114 (BIT(VCNL4010_INT_THR_LOW) | BIT(VCNL4010_INT_THR_HIGH))115#define VCNL4010_INT_DRDY \116 (BIT(VCNL4010_INT_PROXIMITY) | BIT(VCNL4010_INT_ALS))117 118#define VCNL4040_CONF3_PS_MPS_16BITS 3 /* 8 multi pulses */119#define VCNL4040_CONF3_PS_LED_I_16BITS 3 /* 120 mA */120 121#define VCNL4040_CONF3_PS_SAMPLE_16BITS \122 (FIELD_PREP(VCNL4040_PS_CONF3_MPS, VCNL4040_CONF3_PS_MPS_16BITS) | \123 FIELD_PREP(VCNL4040_PS_MS_LED_I, VCNL4040_CONF3_PS_LED_I_16BITS))124 125static const int vcnl4010_prox_sampling_frequency[][2] = {126 {1, 950000},127 {3, 906250},128 {7, 812500},129 {16, 625000},130 {31, 250000},131 {62, 500000},132 {125, 0},133 {250, 0},134};135 136static const int vcnl4040_ps_it_times[][2] = {137 {0, 100},138 {0, 150},139 {0, 200},140 {0, 250},141 {0, 300},142 {0, 350},143 {0, 400},144 {0, 800},145};146 147static const int vcnl4200_ps_it_times[][2] = {148 {0, 96},149 {0, 144},150 {0, 192},151 {0, 384},152 {0, 768},153 {0, 864},154};155 156static const int vcnl4040_als_it_times[][2] = {157 {0, 80000},158 {0, 160000},159 {0, 320000},160 {0, 640000},161};162 163static const int vcnl4200_als_it_times[][2] = {164 {0, 50000},165 {0, 100000},166 {0, 200000},167 {0, 400000},168};169 170static const int vcnl4040_ps_calibbias_ua[][2] = {171 {0, 50000},172 {0, 75000},173 {0, 100000},174 {0, 120000},175 {0, 140000},176 {0, 160000},177 {0, 180000},178 {0, 200000},179};180 181static const int vcnl4040_als_persistence[] = {1, 2, 4, 8};182static const int vcnl4040_ps_persistence[] = {1, 2, 3, 4};183static const int vcnl4040_ps_oversampling_ratio[] = {1, 2, 4, 8};184 185#define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */186 187enum vcnl4000_device_ids {188 VCNL4000,189 VCNL4010,190 VCNL4040,191 VCNL4200,192};193 194struct vcnl4200_channel {195 u8 reg;196 ktime_t last_measurement;197 ktime_t sampling_rate;198 struct mutex lock;199};200 201struct vcnl4000_data {202 struct i2c_client *client;203 enum vcnl4000_device_ids id;204 int rev;205 int al_scale;206 int ps_scale;207 u8 ps_int; /* proximity interrupt mode */208 u8 als_int; /* ambient light interrupt mode*/209 const struct vcnl4000_chip_spec *chip_spec;210 struct mutex vcnl4000_lock;211 struct vcnl4200_channel vcnl4200_al;212 struct vcnl4200_channel vcnl4200_ps;213 uint32_t near_level;214};215 216struct vcnl4000_chip_spec {217 const char *prod;218 struct iio_chan_spec const *channels;219 const int num_channels;220 const struct iio_info *info;221 const struct iio_buffer_setup_ops *buffer_setup_ops;222 int (*init)(struct vcnl4000_data *data);223 int (*measure_light)(struct vcnl4000_data *data, int *val);224 int (*measure_proximity)(struct vcnl4000_data *data, int *val);225 int (*set_power_state)(struct vcnl4000_data *data, bool on);226 irqreturn_t (*irq_thread)(int irq, void *priv);227 irqreturn_t (*trig_buffer_func)(int irq, void *priv);228 229 u8 int_reg;230 const int(*ps_it_times)[][2];231 const int num_ps_it_times;232 const int(*als_it_times)[][2];233 const int num_als_it_times;234 const unsigned int ulux_step;235};236 237static const struct i2c_device_id vcnl4000_id[] = {238 { "vcnl4000", VCNL4000 },239 { "vcnl4010", VCNL4010 },240 { "vcnl4020", VCNL4010 },241 { "vcnl4040", VCNL4040 },242 { "vcnl4200", VCNL4200 },243 { }244};245MODULE_DEVICE_TABLE(i2c, vcnl4000_id);246 247static int vcnl4000_set_power_state(struct vcnl4000_data *data, bool on)248{249 /* no suspend op */250 return 0;251}252 253static int vcnl4000_init(struct vcnl4000_data *data)254{255 int ret, prod_id;256 257 ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);258 if (ret < 0)259 return ret;260 261 prod_id = ret >> 4;262 switch (prod_id) {263 case VCNL4000_PROD_ID:264 if (data->id != VCNL4000)265 dev_warn(&data->client->dev,266 "wrong device id, use vcnl4000");267 break;268 case VCNL4010_PROD_ID:269 if (data->id != VCNL4010)270 dev_warn(&data->client->dev,271 "wrong device id, use vcnl4010/4020");272 break;273 default:274 return -ENODEV;275 }276 277 data->rev = ret & 0xf;278 data->al_scale = 250000;279 280 return data->chip_spec->set_power_state(data, true);281};282 283static ssize_t vcnl4000_write_als_enable(struct vcnl4000_data *data, bool en)284{285 int ret;286 287 mutex_lock(&data->vcnl4000_lock);288 289 ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);290 if (ret < 0)291 goto out;292 293 if (en)294 ret &= ~VCNL4040_ALS_CONF_ALS_SHUTDOWN;295 else296 ret |= VCNL4040_ALS_CONF_ALS_SHUTDOWN;297 298 ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, ret);299 300out:301 mutex_unlock(&data->vcnl4000_lock);302 303 return ret;304}305 306static ssize_t vcnl4000_write_ps_enable(struct vcnl4000_data *data, bool en)307{308 int ret;309 310 mutex_lock(&data->vcnl4000_lock);311 312 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);313 if (ret < 0)314 goto out;315 316 if (en)317 ret &= ~VCNL4040_PS_CONF1_PS_SHUTDOWN;318 else319 ret |= VCNL4040_PS_CONF1_PS_SHUTDOWN;320 321 ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, ret);322 323out:324 mutex_unlock(&data->vcnl4000_lock);325 326 return ret;327}328 329static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)330{331 int ret;332 333 /* Do not power down if interrupts are enabled */334 if (!on && (data->ps_int || data->als_int))335 return 0;336 337 ret = vcnl4000_write_als_enable(data, on);338 if (ret < 0)339 return ret;340 341 ret = vcnl4000_write_ps_enable(data, on);342 if (ret < 0)343 return ret;344 345 if (on) {346 /* Wait at least one integration cycle before fetching data */347 data->vcnl4200_al.last_measurement = ktime_get();348 data->vcnl4200_ps.last_measurement = ktime_get();349 }350 351 return 0;352}353 354static int vcnl4200_init(struct vcnl4000_data *data)355{356 int ret, id;357 u16 regval;358 359 ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);360 if (ret < 0)361 return ret;362 363 id = ret & 0xff;364 365 if (id != VCNL4200_PROD_ID) {366 ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID);367 if (ret < 0)368 return ret;369 370 id = ret & 0xff;371 372 if (id != VCNL4040_PROD_ID)373 return -ENODEV;374 }375 376 dev_dbg(&data->client->dev, "device id 0x%x", id);377 378 data->rev = (ret >> 8) & 0xf;379 data->ps_int = 0;380 data->als_int = 0;381 382 data->vcnl4200_al.reg = VCNL4200_AL_DATA;383 data->vcnl4200_ps.reg = VCNL4200_PS_DATA;384 switch (id) {385 case VCNL4200_PROD_ID:386 /* Default wait time is 50ms, add 20% tolerance. */387 data->vcnl4200_al.sampling_rate = ktime_set(0, 60000 * 1000);388 /* Default wait time is 4.8ms, add 20% tolerance. */389 data->vcnl4200_ps.sampling_rate = ktime_set(0, 5760 * 1000);390 break;391 case VCNL4040_PROD_ID:392 /* Default wait time is 80ms, add 20% tolerance. */393 data->vcnl4200_al.sampling_rate = ktime_set(0, 96000 * 1000);394 /* Default wait time is 5ms, add 20% tolerance. */395 data->vcnl4200_ps.sampling_rate = ktime_set(0, 6000 * 1000);396 break;397 }398 data->al_scale = data->chip_spec->ulux_step;399 data->ps_scale = 16;400 mutex_init(&data->vcnl4200_al.lock);401 mutex_init(&data->vcnl4200_ps.lock);402 403 /* Use 16 bits proximity sensor readings */404 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);405 if (ret < 0)406 return ret;407 408 regval = ret | VCNL4040_PS_CONF2_PS_HD;409 ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,410 regval);411 if (ret < 0)412 return ret;413 414 /* Align proximity sensor sample rate to 16 bits data width */415 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);416 if (ret < 0)417 return ret;418 419 regval = ret | VCNL4040_CONF3_PS_SAMPLE_16BITS;420 ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,421 regval);422 if (ret < 0)423 return ret;424 425 ret = data->chip_spec->set_power_state(data, true);426 if (ret < 0)427 return ret;428 429 return 0;430};431 432static int vcnl4000_read_data(struct vcnl4000_data *data, u8 data_reg, int *val)433{434 s32 ret;435 436 ret = i2c_smbus_read_word_swapped(data->client, data_reg);437 if (ret < 0)438 return ret;439 440 *val = ret;441 return 0;442}443 444static int vcnl4000_write_data(struct vcnl4000_data *data, u8 data_reg, int val)445{446 if (val > U16_MAX)447 return -ERANGE;448 449 return i2c_smbus_write_word_swapped(data->client, data_reg, val);450}451 452 453static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,454 u8 rdy_mask, u8 data_reg, int *val)455{456 int tries = 20;457 int ret;458 459 mutex_lock(&data->vcnl4000_lock);460 461 ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,462 req_mask);463 if (ret < 0)464 goto fail;465 466 /* wait for data to become ready */467 while (tries--) {468 ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);469 if (ret < 0)470 goto fail;471 if (ret & rdy_mask)472 break;473 msleep(20); /* measurement takes up to 100 ms */474 }475 476 if (tries < 0) {477 dev_err(&data->client->dev,478 "vcnl4000_measure() failed, data not ready\n");479 ret = -EIO;480 goto fail;481 }482 483 ret = vcnl4000_read_data(data, data_reg, val);484 if (ret < 0)485 goto fail;486 487 mutex_unlock(&data->vcnl4000_lock);488 489 return 0;490 491fail:492 mutex_unlock(&data->vcnl4000_lock);493 return ret;494}495 496static int vcnl4200_measure(struct vcnl4000_data *data,497 struct vcnl4200_channel *chan, int *val)498{499 int ret;500 s64 delta;501 ktime_t next_measurement;502 503 mutex_lock(&chan->lock);504 505 next_measurement = ktime_add(chan->last_measurement,506 chan->sampling_rate);507 delta = ktime_us_delta(next_measurement, ktime_get());508 if (delta > 0)509 usleep_range(delta, delta + 500);510 chan->last_measurement = ktime_get();511 512 mutex_unlock(&chan->lock);513 514 ret = i2c_smbus_read_word_data(data->client, chan->reg);515 if (ret < 0)516 return ret;517 518 *val = ret;519 520 return 0;521}522 523static int vcnl4000_measure_light(struct vcnl4000_data *data, int *val)524{525 return vcnl4000_measure(data,526 VCNL4000_AL_OD, VCNL4000_AL_RDY,527 VCNL4000_AL_RESULT_HI, val);528}529 530static int vcnl4200_measure_light(struct vcnl4000_data *data, int *val)531{532 return vcnl4200_measure(data, &data->vcnl4200_al, val);533}534 535static int vcnl4000_measure_proximity(struct vcnl4000_data *data, int *val)536{537 return vcnl4000_measure(data,538 VCNL4000_PS_OD, VCNL4000_PS_RDY,539 VCNL4000_PS_RESULT_HI, val);540}541 542static int vcnl4200_measure_proximity(struct vcnl4000_data *data, int *val)543{544 return vcnl4200_measure(data, &data->vcnl4200_ps, val);545}546 547static int vcnl4010_read_proxy_samp_freq(struct vcnl4000_data *data, int *val,548 int *val2)549{550 int ret;551 552 ret = i2c_smbus_read_byte_data(data->client, VCNL4010_PROX_RATE);553 if (ret < 0)554 return ret;555 556 if (ret >= ARRAY_SIZE(vcnl4010_prox_sampling_frequency))557 return -EINVAL;558 559 *val = vcnl4010_prox_sampling_frequency[ret][0];560 *val2 = vcnl4010_prox_sampling_frequency[ret][1];561 562 return 0;563}564 565static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data)566{567 int ret;568 569 ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);570 if (ret < 0)571 return false;572 573 return !!(ret & VCNL4000_SELF_TIMED_EN);574}575 576static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)577{578 struct device *dev = &data->client->dev;579 int ret;580 581 if (on) {582 ret = pm_runtime_resume_and_get(dev);583 } else {584 pm_runtime_mark_last_busy(dev);585 ret = pm_runtime_put_autosuspend(dev);586 }587 588 return ret;589}590 591static int vcnl4040_read_als_it(struct vcnl4000_data *data, int *val, int *val2)592{593 int ret;594 595 ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);596 if (ret < 0)597 return ret;598 599 ret = FIELD_GET(VCNL4040_ALS_CONF_IT, ret);600 if (ret >= data->chip_spec->num_als_it_times)601 return -EINVAL;602 603 *val = (*data->chip_spec->als_it_times)[ret][0];604 *val2 = (*data->chip_spec->als_it_times)[ret][1];605 606 return 0;607}608 609static ssize_t vcnl4040_write_als_it(struct vcnl4000_data *data, int val)610{611 unsigned int i;612 int ret;613 u16 regval;614 615 for (i = 0; i < data->chip_spec->num_als_it_times; i++) {616 if (val == (*data->chip_spec->als_it_times)[i][1])617 break;618 }619 620 if (i == data->chip_spec->num_als_it_times)621 return -EINVAL;622 623 data->vcnl4200_al.sampling_rate = ktime_set(0, val * 1200);624 data->al_scale = div_u64(mul_u32_u32(data->chip_spec->ulux_step,625 (*data->chip_spec->als_it_times)[0][1]),626 val);627 628 mutex_lock(&data->vcnl4000_lock);629 630 ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);631 if (ret < 0)632 goto out_unlock;633 634 regval = FIELD_PREP(VCNL4040_ALS_CONF_IT, i);635 regval |= (ret & ~VCNL4040_ALS_CONF_IT);636 ret = i2c_smbus_write_word_data(data->client,637 VCNL4200_AL_CONF,638 regval);639 640out_unlock:641 mutex_unlock(&data->vcnl4000_lock);642 return ret;643}644 645static int vcnl4040_read_ps_it(struct vcnl4000_data *data, int *val, int *val2)646{647 int ret;648 649 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);650 if (ret < 0)651 return ret;652 653 ret = FIELD_GET(VCNL4040_PS_CONF2_PS_IT, ret);654 655 if (ret >= data->chip_spec->num_ps_it_times)656 return -EINVAL;657 658 *val = (*data->chip_spec->ps_it_times)[ret][0];659 *val2 = (*data->chip_spec->ps_it_times)[ret][1];660 661 return 0;662}663 664static ssize_t vcnl4040_write_ps_it(struct vcnl4000_data *data, int val)665{666 unsigned int i;667 int ret, index = -1;668 u16 regval;669 670 for (i = 0; i < data->chip_spec->num_ps_it_times; i++) {671 if (val == (*data->chip_spec->ps_it_times)[i][1]) {672 index = i;673 break;674 }675 }676 677 if (index < 0)678 return -EINVAL;679 680 data->vcnl4200_ps.sampling_rate = ktime_set(0, val * 60 * NSEC_PER_USEC);681 682 mutex_lock(&data->vcnl4000_lock);683 684 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);685 if (ret < 0)686 goto out;687 688 regval = (ret & ~VCNL4040_PS_CONF2_PS_IT) |689 FIELD_PREP(VCNL4040_PS_CONF2_PS_IT, index);690 ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,691 regval);692 693out:694 mutex_unlock(&data->vcnl4000_lock);695 return ret;696}697 698static ssize_t vcnl4040_read_als_period(struct vcnl4000_data *data, int *val, int *val2)699{700 int ret, ret_pers, it;701 int64_t val_c;702 703 ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);704 if (ret < 0)705 return ret;706 707 ret_pers = FIELD_GET(VCNL4040_ALS_CONF_PERS, ret);708 if (ret_pers >= ARRAY_SIZE(vcnl4040_als_persistence))709 return -EINVAL;710 711 it = FIELD_GET(VCNL4040_ALS_CONF_IT, ret);712 if (it >= data->chip_spec->num_als_it_times)713 return -EINVAL;714 715 val_c = mul_u32_u32((*data->chip_spec->als_it_times)[it][1],716 vcnl4040_als_persistence[ret_pers]);717 *val = div_u64_rem(val_c, MICRO, val2);718 719 return IIO_VAL_INT_PLUS_MICRO;720}721 722static ssize_t vcnl4040_write_als_period(struct vcnl4000_data *data, int val, int val2)723{724 unsigned int i;725 int ret, it;726 u16 regval;727 u64 val_n = mul_u32_u32(val, MICRO) + val2;728 729 ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);730 if (ret < 0)731 return ret;732 733 it = FIELD_GET(VCNL4040_ALS_CONF_IT, ret);734 if (it >= data->chip_spec->num_als_it_times)735 return -EINVAL;736 737 for (i = 0; i < ARRAY_SIZE(vcnl4040_als_persistence) - 1; i++) {738 if (val_n < mul_u32_u32(vcnl4040_als_persistence[i],739 (*data->chip_spec->als_it_times)[it][1]))740 break;741 }742 743 mutex_lock(&data->vcnl4000_lock);744 745 ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);746 if (ret < 0)747 goto out_unlock;748 749 regval = FIELD_PREP(VCNL4040_ALS_CONF_PERS, i);750 regval |= (ret & ~VCNL4040_ALS_CONF_PERS);751 ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF,752 regval);753 754out_unlock:755 mutex_unlock(&data->vcnl4000_lock);756 return ret;757}758 759static ssize_t vcnl4040_read_ps_period(struct vcnl4000_data *data, int *val, int *val2)760{761 int ret, ret_pers, it;762 763 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);764 if (ret < 0)765 return ret;766 767 ret_pers = FIELD_GET(VCNL4040_CONF1_PS_PERS, ret);768 if (ret_pers >= ARRAY_SIZE(vcnl4040_ps_persistence))769 return -EINVAL;770 771 it = FIELD_GET(VCNL4040_PS_CONF2_PS_IT, ret);772 if (it >= data->chip_spec->num_ps_it_times)773 return -EINVAL;774 775 *val = (*data->chip_spec->ps_it_times)[it][0];776 *val2 = (*data->chip_spec->ps_it_times)[it][1] *777 vcnl4040_ps_persistence[ret_pers];778 779 return IIO_VAL_INT_PLUS_MICRO;780}781 782static ssize_t vcnl4040_write_ps_period(struct vcnl4000_data *data, int val, int val2)783{784 int ret, it, i;785 u16 regval;786 787 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);788 if (ret < 0)789 return ret;790 791 it = FIELD_GET(VCNL4040_PS_CONF2_PS_IT, ret);792 if (it >= data->chip_spec->num_ps_it_times)793 return -EINVAL;794 795 if (val > 0)796 i = ARRAY_SIZE(vcnl4040_ps_persistence) - 1;797 else {798 for (i = 0; i < ARRAY_SIZE(vcnl4040_ps_persistence) - 1; i++) {799 if (val2 <= vcnl4040_ps_persistence[i] *800 (*data->chip_spec->ps_it_times)[it][1])801 break;802 }803 }804 805 mutex_lock(&data->vcnl4000_lock);806 807 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);808 if (ret < 0)809 goto out_unlock;810 811 regval = FIELD_PREP(VCNL4040_CONF1_PS_PERS, i);812 regval |= (ret & ~VCNL4040_CONF1_PS_PERS);813 ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,814 regval);815 816out_unlock:817 mutex_unlock(&data->vcnl4000_lock);818 return ret;819}820 821static ssize_t vcnl4040_read_ps_oversampling_ratio(struct vcnl4000_data *data, int *val)822{823 int ret;824 825 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);826 if (ret < 0)827 return ret;828 829 ret = FIELD_GET(VCNL4040_PS_CONF3_MPS, ret);830 if (ret >= ARRAY_SIZE(vcnl4040_ps_oversampling_ratio))831 return -EINVAL;832 833 *val = vcnl4040_ps_oversampling_ratio[ret];834 835 return ret;836}837 838static ssize_t vcnl4040_write_ps_oversampling_ratio(struct vcnl4000_data *data, int val)839{840 unsigned int i;841 int ret;842 u16 regval;843 844 for (i = 0; i < ARRAY_SIZE(vcnl4040_ps_oversampling_ratio); i++) {845 if (val == vcnl4040_ps_oversampling_ratio[i])846 break;847 }848 849 if (i >= ARRAY_SIZE(vcnl4040_ps_oversampling_ratio))850 return -EINVAL;851 852 mutex_lock(&data->vcnl4000_lock);853 854 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);855 if (ret < 0)856 goto out_unlock;857 858 regval = FIELD_PREP(VCNL4040_PS_CONF3_MPS, i);859 regval |= (ret & ~VCNL4040_PS_CONF3_MPS);860 ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,861 regval);862 863out_unlock:864 mutex_unlock(&data->vcnl4000_lock);865 return ret;866}867 868static ssize_t vcnl4040_read_ps_calibbias(struct vcnl4000_data *data, int *val, int *val2)869{870 int ret;871 872 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);873 if (ret < 0)874 return ret;875 876 ret = FIELD_GET(VCNL4040_PS_MS_LED_I, ret);877 if (ret >= ARRAY_SIZE(vcnl4040_ps_calibbias_ua))878 return -EINVAL;879 880 *val = vcnl4040_ps_calibbias_ua[ret][0];881 *val2 = vcnl4040_ps_calibbias_ua[ret][1];882 883 return ret;884}885 886static ssize_t vcnl4040_write_ps_calibbias(struct vcnl4000_data *data, int val)887{888 unsigned int i;889 int ret;890 u16 regval;891 892 for (i = 0; i < ARRAY_SIZE(vcnl4040_ps_calibbias_ua); i++) {893 if (val == vcnl4040_ps_calibbias_ua[i][1])894 break;895 }896 897 if (i >= ARRAY_SIZE(vcnl4040_ps_calibbias_ua))898 return -EINVAL;899 900 mutex_lock(&data->vcnl4000_lock);901 902 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);903 if (ret < 0)904 goto out_unlock;905 906 regval = (ret & ~VCNL4040_PS_MS_LED_I);907 regval |= FIELD_PREP(VCNL4040_PS_MS_LED_I, i);908 ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,909 regval);910 911out_unlock:912 mutex_unlock(&data->vcnl4000_lock);913 return ret;914}915 916static int vcnl4000_read_raw(struct iio_dev *indio_dev,917 struct iio_chan_spec const *chan,918 int *val, int *val2, long mask)919{920 int ret;921 struct vcnl4000_data *data = iio_priv(indio_dev);922 923 switch (mask) {924 case IIO_CHAN_INFO_RAW:925 ret = vcnl4000_set_pm_runtime_state(data, true);926 if (ret < 0)927 return ret;928 929 switch (chan->type) {930 case IIO_LIGHT:931 ret = data->chip_spec->measure_light(data, val);932 if (!ret)933 ret = IIO_VAL_INT;934 break;935 case IIO_PROXIMITY:936 ret = data->chip_spec->measure_proximity(data, val);937 *val2 = data->ps_scale;938 if (!ret)939 ret = IIO_VAL_FRACTIONAL;940 break;941 default:942 ret = -EINVAL;943 }944 vcnl4000_set_pm_runtime_state(data, false);945 return ret;946 case IIO_CHAN_INFO_SCALE:947 if (chan->type != IIO_LIGHT)948 return -EINVAL;949 950 *val = 0;951 *val2 = data->al_scale;952 return IIO_VAL_INT_PLUS_MICRO;953 case IIO_CHAN_INFO_INT_TIME:954 switch (chan->type) {955 case IIO_LIGHT:956 ret = vcnl4040_read_als_it(data, val, val2);957 break;958 case IIO_PROXIMITY:959 ret = vcnl4040_read_ps_it(data, val, val2);960 break;961 default:962 return -EINVAL;963 }964 if (ret < 0)965 return ret;966 return IIO_VAL_INT_PLUS_MICRO;967 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:968 switch (chan->type) {969 case IIO_PROXIMITY:970 ret = vcnl4040_read_ps_oversampling_ratio(data, val);971 if (ret < 0)972 return ret;973 return IIO_VAL_INT;974 default:975 return -EINVAL;976 }977 case IIO_CHAN_INFO_CALIBBIAS:978 switch (chan->type) {979 case IIO_PROXIMITY:980 ret = vcnl4040_read_ps_calibbias(data, val, val2);981 if (ret < 0)982 return ret;983 return IIO_VAL_INT_PLUS_MICRO;984 default:985 return -EINVAL;986 }987 default:988 return -EINVAL;989 }990}991 992static int vcnl4040_write_raw(struct iio_dev *indio_dev,993 struct iio_chan_spec const *chan,994 int val, int val2, long mask)995{996 struct vcnl4000_data *data = iio_priv(indio_dev);997 998 switch (mask) {999 case IIO_CHAN_INFO_INT_TIME:1000 if (val != 0)1001 return -EINVAL;1002 switch (chan->type) {1003 case IIO_LIGHT:1004 return vcnl4040_write_als_it(data, val2);1005 case IIO_PROXIMITY:1006 return vcnl4040_write_ps_it(data, val2);1007 default:1008 return -EINVAL;1009 }1010 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:1011 switch (chan->type) {1012 case IIO_PROXIMITY:1013 return vcnl4040_write_ps_oversampling_ratio(data, val);1014 default:1015 return -EINVAL;1016 }1017 case IIO_CHAN_INFO_CALIBBIAS:1018 switch (chan->type) {1019 case IIO_PROXIMITY:1020 return vcnl4040_write_ps_calibbias(data, val2);1021 default:1022 return -EINVAL;1023 }1024 default:1025 return -EINVAL;1026 }1027}1028 1029static int vcnl4040_read_avail(struct iio_dev *indio_dev,1030 struct iio_chan_spec const *chan,1031 const int **vals, int *type, int *length,1032 long mask)1033{1034 struct vcnl4000_data *data = iio_priv(indio_dev);1035 1036 switch (mask) {1037 case IIO_CHAN_INFO_INT_TIME:1038 switch (chan->type) {1039 case IIO_LIGHT:1040 *vals = (int *)(*data->chip_spec->als_it_times);1041 *length = 2 * data->chip_spec->num_als_it_times;1042 break;1043 case IIO_PROXIMITY:1044 *vals = (int *)(*data->chip_spec->ps_it_times);1045 *length = 2 * data->chip_spec->num_ps_it_times;1046 break;1047 default:1048 return -EINVAL;1049 }1050 *type = IIO_VAL_INT_PLUS_MICRO;1051 return IIO_AVAIL_LIST;1052 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:1053 switch (chan->type) {1054 case IIO_PROXIMITY:1055 *vals = (int *)vcnl4040_ps_oversampling_ratio;1056 *length = ARRAY_SIZE(vcnl4040_ps_oversampling_ratio);1057 *type = IIO_VAL_INT;1058 return IIO_AVAIL_LIST;1059 default:1060 return -EINVAL;1061 }1062 case IIO_CHAN_INFO_CALIBBIAS:1063 switch (chan->type) {1064 case IIO_PROXIMITY:1065 *vals = (int *)vcnl4040_ps_calibbias_ua;1066 *length = 2 * ARRAY_SIZE(vcnl4040_ps_calibbias_ua);1067 *type = IIO_VAL_INT_PLUS_MICRO;1068 return IIO_AVAIL_LIST;1069 default:1070 return -EINVAL;1071 }1072 default:1073 return -EINVAL;1074 }1075}1076 1077static int vcnl4010_read_raw(struct iio_dev *indio_dev,1078 struct iio_chan_spec const *chan,1079 int *val, int *val2, long mask)1080{1081 int ret;1082 struct vcnl4000_data *data = iio_priv(indio_dev);1083 1084 switch (mask) {1085 case IIO_CHAN_INFO_RAW:1086 case IIO_CHAN_INFO_SCALE:1087 ret = iio_device_claim_direct_mode(indio_dev);1088 if (ret)1089 return ret;1090 1091 /* Protect against event capture. */1092 if (vcnl4010_is_in_periodic_mode(data)) {1093 ret = -EBUSY;1094 } else {1095 ret = vcnl4000_read_raw(indio_dev, chan, val, val2,1096 mask);1097 }1098 1099 iio_device_release_direct_mode(indio_dev);1100 return ret;1101 case IIO_CHAN_INFO_SAMP_FREQ:1102 switch (chan->type) {1103 case IIO_PROXIMITY:1104 ret = vcnl4010_read_proxy_samp_freq(data, val, val2);1105 if (ret < 0)1106 return ret;1107 return IIO_VAL_INT_PLUS_MICRO;1108 default:1109 return -EINVAL;1110 }1111 default:1112 return -EINVAL;1113 }1114}1115 1116static int vcnl4010_read_avail(struct iio_dev *indio_dev,1117 struct iio_chan_spec const *chan,1118 const int **vals, int *type, int *length,1119 long mask)1120{1121 switch (mask) {1122 case IIO_CHAN_INFO_SAMP_FREQ:1123 *vals = (int *)vcnl4010_prox_sampling_frequency;1124 *type = IIO_VAL_INT_PLUS_MICRO;1125 *length = 2 * ARRAY_SIZE(vcnl4010_prox_sampling_frequency);1126 return IIO_AVAIL_LIST;1127 default:1128 return -EINVAL;1129 }1130}1131 1132static int vcnl4010_write_proxy_samp_freq(struct vcnl4000_data *data, int val,1133 int val2)1134{1135 unsigned int i;1136 int index = -1;1137 1138 for (i = 0; i < ARRAY_SIZE(vcnl4010_prox_sampling_frequency); i++) {1139 if (val == vcnl4010_prox_sampling_frequency[i][0] &&1140 val2 == vcnl4010_prox_sampling_frequency[i][1]) {1141 index = i;1142 break;1143 }1144 }1145 1146 if (index < 0)1147 return -EINVAL;1148 1149 return i2c_smbus_write_byte_data(data->client, VCNL4010_PROX_RATE,1150 index);1151}1152 1153static int vcnl4010_write_raw(struct iio_dev *indio_dev,1154 struct iio_chan_spec const *chan,1155 int val, int val2, long mask)1156{1157 int ret;1158 struct vcnl4000_data *data = iio_priv(indio_dev);1159 1160 ret = iio_device_claim_direct_mode(indio_dev);1161 if (ret)1162 return ret;1163 1164 /* Protect against event capture. */1165 if (vcnl4010_is_in_periodic_mode(data)) {1166 ret = -EBUSY;1167 goto end;1168 }1169 1170 switch (mask) {1171 case IIO_CHAN_INFO_SAMP_FREQ:1172 switch (chan->type) {1173 case IIO_PROXIMITY:1174 ret = vcnl4010_write_proxy_samp_freq(data, val, val2);1175 goto end;1176 default:1177 ret = -EINVAL;1178 goto end;1179 }1180 default:1181 ret = -EINVAL;1182 goto end;1183 }1184 1185end:1186 iio_device_release_direct_mode(indio_dev);1187 return ret;1188}1189 1190static int vcnl4010_read_event(struct iio_dev *indio_dev,1191 const struct iio_chan_spec *chan,1192 enum iio_event_type type,1193 enum iio_event_direction dir,1194 enum iio_event_info info,1195 int *val, int *val2)1196{1197 int ret;1198 struct vcnl4000_data *data = iio_priv(indio_dev);1199 1200 switch (info) {1201 case IIO_EV_INFO_VALUE:1202 switch (dir) {1203 case IIO_EV_DIR_RISING:1204 ret = vcnl4000_read_data(data, VCNL4010_HIGH_THR_HI,1205 val);1206 if (ret < 0)1207 return ret;1208 return IIO_VAL_INT;1209 case IIO_EV_DIR_FALLING:1210 ret = vcnl4000_read_data(data, VCNL4010_LOW_THR_HI,1211 val);1212 if (ret < 0)1213 return ret;1214 return IIO_VAL_INT;1215 default:1216 return -EINVAL;1217 }1218 default:1219 return -EINVAL;1220 }1221}1222 1223static int vcnl4010_write_event(struct iio_dev *indio_dev,1224 const struct iio_chan_spec *chan,1225 enum iio_event_type type,1226 enum iio_event_direction dir,1227 enum iio_event_info info,1228 int val, int val2)1229{1230 int ret;1231 struct vcnl4000_data *data = iio_priv(indio_dev);1232 1233 switch (info) {1234 case IIO_EV_INFO_VALUE:1235 switch (dir) {1236 case IIO_EV_DIR_RISING:1237 ret = vcnl4000_write_data(data, VCNL4010_HIGH_THR_HI,1238 val);1239 if (ret < 0)1240 return ret;1241 return IIO_VAL_INT;1242 case IIO_EV_DIR_FALLING:1243 ret = vcnl4000_write_data(data, VCNL4010_LOW_THR_HI,1244 val);1245 if (ret < 0)1246 return ret;1247 return IIO_VAL_INT;1248 default:1249 return -EINVAL;1250 }1251 default:1252 return -EINVAL;1253 }1254}1255 1256static int vcnl4040_read_event(struct iio_dev *indio_dev,1257 const struct iio_chan_spec *chan,1258 enum iio_event_type type,1259 enum iio_event_direction dir,1260 enum iio_event_info info,1261 int *val, int *val2)1262{1263 int ret;1264 struct vcnl4000_data *data = iio_priv(indio_dev);1265 1266 switch (chan->type) {1267 case IIO_LIGHT:1268 switch (info) {1269 case IIO_EV_INFO_PERIOD:1270 return vcnl4040_read_als_period(data, val, val2);1271 case IIO_EV_INFO_VALUE:1272 switch (dir) {1273 case IIO_EV_DIR_RISING:1274 ret = i2c_smbus_read_word_data(data->client,1275 VCNL4040_ALS_THDH_LM);1276 break;1277 case IIO_EV_DIR_FALLING:1278 ret = i2c_smbus_read_word_data(data->client,1279 VCNL4040_ALS_THDL_LM);1280 break;1281 default:1282 return -EINVAL;1283 }1284 break;1285 default:1286 return -EINVAL;1287 }1288 break;1289 case IIO_PROXIMITY:1290 switch (info) {1291 case IIO_EV_INFO_PERIOD:1292 return vcnl4040_read_ps_period(data, val, val2);1293 case IIO_EV_INFO_VALUE:1294 switch (dir) {1295 case IIO_EV_DIR_RISING:1296 ret = i2c_smbus_read_word_data(data->client,1297 VCNL4040_PS_THDH_LM);1298 break;1299 case IIO_EV_DIR_FALLING:1300 ret = i2c_smbus_read_word_data(data->client,1301 VCNL4040_PS_THDL_LM);1302 break;1303 default:1304 return -EINVAL;1305 }1306 break;1307 default:1308 return -EINVAL;1309 }1310 break;1311 default:1312 return -EINVAL;1313 }1314 if (ret < 0)1315 return ret;1316 *val = ret;1317 return IIO_VAL_INT;1318}1319 1320static int vcnl4040_write_event(struct iio_dev *indio_dev,1321 const struct iio_chan_spec *chan,1322 enum iio_event_type type,1323 enum iio_event_direction dir,1324 enum iio_event_info info,1325 int val, int val2)1326{1327 int ret;1328 struct vcnl4000_data *data = iio_priv(indio_dev);1329 1330 switch (chan->type) {1331 case IIO_LIGHT:1332 switch (info) {1333 case IIO_EV_INFO_PERIOD:1334 return vcnl4040_write_als_period(data, val, val2);1335 case IIO_EV_INFO_VALUE:1336 switch (dir) {1337 case IIO_EV_DIR_RISING:1338 ret = i2c_smbus_write_word_data(data->client,1339 VCNL4040_ALS_THDH_LM,1340 val);1341 break;1342 case IIO_EV_DIR_FALLING:1343 ret = i2c_smbus_write_word_data(data->client,1344 VCNL4040_ALS_THDL_LM,1345 val);1346 break;1347 default:1348 return -EINVAL;1349 }1350 break;1351 default:1352 return -EINVAL;1353 }1354 break;1355 case IIO_PROXIMITY:1356 switch (info) {1357 case IIO_EV_INFO_PERIOD:1358 return vcnl4040_write_ps_period(data, val, val2);1359 case IIO_EV_INFO_VALUE:1360 switch (dir) {1361 case IIO_EV_DIR_RISING:1362 ret = i2c_smbus_write_word_data(data->client,1363 VCNL4040_PS_THDH_LM,1364 val);1365 break;1366 case IIO_EV_DIR_FALLING:1367 ret = i2c_smbus_write_word_data(data->client,1368 VCNL4040_PS_THDL_LM,1369 val);1370 break;1371 default:1372 return -EINVAL;1373 }1374 break;1375 default:1376 return -EINVAL;1377 }1378 break;1379 default:1380 return -EINVAL;1381 }1382 if (ret < 0)1383 return ret;1384 return IIO_VAL_INT;1385}1386 1387static bool vcnl4010_is_thr_enabled(struct vcnl4000_data *data)1388{1389 int ret;1390 1391 ret = i2c_smbus_read_byte_data(data->client, VCNL4010_INT_CTRL);1392 if (ret < 0)1393 return false;1394 1395 return !!(ret & VCNL4010_INT_THR_EN);1396}1397 1398static int vcnl4010_read_event_config(struct iio_dev *indio_dev,1399 const struct iio_chan_spec *chan,1400 enum iio_event_type type,1401 enum iio_event_direction dir)1402{1403 struct vcnl4000_data *data = iio_priv(indio_dev);1404 1405 switch (chan->type) {1406 case IIO_PROXIMITY:1407 return vcnl4010_is_thr_enabled(data);1408 default:1409 return -EINVAL;1410 }1411}1412 1413static int vcnl4010_config_threshold(struct iio_dev *indio_dev, bool state)1414{1415 struct vcnl4000_data *data = iio_priv(indio_dev);1416 int ret;1417 int icr;1418 int command;1419 1420 if (state) {1421 ret = iio_device_claim_direct_mode(indio_dev);1422 if (ret)1423 return ret;1424 1425 /* Enable periodic measurement of proximity data. */1426 command = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;1427 1428 /*1429 * Enable interrupts on threshold, for proximity data by1430 * default.1431 */1432 icr = VCNL4010_INT_THR_EN;1433 } else {1434 if (!vcnl4010_is_thr_enabled(data))1435 return 0;1436 1437 command = 0;1438 icr = 0;1439 }1440 1441 ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,1442 command);1443 if (ret < 0)1444 goto end;1445 1446 ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, icr);1447 1448end:1449 if (state)1450 iio_device_release_direct_mode(indio_dev);1451 1452 return ret;1453}1454 1455static int vcnl4010_write_event_config(struct iio_dev *indio_dev,1456 const struct iio_chan_spec *chan,1457 enum iio_event_type type,1458 enum iio_event_direction dir,1459 int state)1460{1461 switch (chan->type) {1462 case IIO_PROXIMITY:1463 return vcnl4010_config_threshold(indio_dev, state);1464 default:1465 return -EINVAL;1466 }1467}1468 1469static int vcnl4040_read_event_config(struct iio_dev *indio_dev,1470 const struct iio_chan_spec *chan,1471 enum iio_event_type type,1472 enum iio_event_direction dir)1473{1474 int ret;1475 struct vcnl4000_data *data = iio_priv(indio_dev);1476 1477 switch (chan->type) {1478 case IIO_LIGHT:1479 ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);1480 if (ret < 0)1481 return ret;1482 1483 data->als_int = FIELD_GET(VCNL4040_ALS_CONF_INT_EN, ret);1484 1485 return data->als_int;1486 case IIO_PROXIMITY:1487 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);1488 if (ret < 0)1489 return ret;1490 1491 data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, ret);1492 1493 return (dir == IIO_EV_DIR_RISING) ?1494 FIELD_GET(VCNL4040_PS_IF_AWAY, ret) :1495 FIELD_GET(VCNL4040_PS_IF_CLOSE, ret);1496 default:1497 return -EINVAL;1498 }1499}1500 1501static int vcnl4040_write_event_config(struct iio_dev *indio_dev,1502 const struct iio_chan_spec *chan,1503 enum iio_event_type type,1504 enum iio_event_direction dir, int state)1505{1506 int ret = -EINVAL;1507 u16 val, mask;1508 struct vcnl4000_data *data = iio_priv(indio_dev);1509 1510 mutex_lock(&data->vcnl4000_lock);1511 1512 switch (chan->type) {1513 case IIO_LIGHT:1514 ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);1515 if (ret < 0)1516 goto out;1517 1518 mask = VCNL4040_ALS_CONF_INT_EN;1519 if (state)1520 val = (ret | mask);1521 else1522 val = (ret & ~mask);1523 1524 data->als_int = FIELD_GET(VCNL4040_ALS_CONF_INT_EN, val);1525 ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF,1526 val);1527 break;1528 case IIO_PROXIMITY:1529 ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);1530 if (ret < 0)1531 goto out;1532 1533 if (dir == IIO_EV_DIR_RISING)1534 mask = VCNL4040_PS_IF_AWAY;1535 else1536 mask = VCNL4040_PS_IF_CLOSE;1537 1538 val = state ? (ret | mask) : (ret & ~mask);1539 1540 data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, val);1541 ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,1542 val);1543 break;1544 default:1545 break;1546 }1547 1548out:1549 mutex_unlock(&data->vcnl4000_lock);1550 1551 return ret;1552}1553 1554static irqreturn_t vcnl4040_irq_thread(int irq, void *p)1555{1556 struct iio_dev *indio_dev = p;1557 struct vcnl4000_data *data = iio_priv(indio_dev);1558 int ret;1559 1560 ret = i2c_smbus_read_word_data(data->client, data->chip_spec->int_reg);1561 if (ret < 0)1562 return IRQ_HANDLED;1563 1564 if (ret & VCNL4040_PS_IF_CLOSE) {1565 iio_push_event(indio_dev,1566 IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,1567 IIO_EV_TYPE_THRESH,1568 IIO_EV_DIR_RISING),1569 iio_get_time_ns(indio_dev));1570 }1571 1572 if (ret & VCNL4040_PS_IF_AWAY) {1573 iio_push_event(indio_dev,1574 IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,1575 IIO_EV_TYPE_THRESH,1576 IIO_EV_DIR_FALLING),1577 iio_get_time_ns(indio_dev));1578 }1579 1580 if (ret & VCNL4040_ALS_FALLING) {1581 iio_push_event(indio_dev,1582 IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,1583 IIO_EV_TYPE_THRESH,1584 IIO_EV_DIR_FALLING),1585 iio_get_time_ns(indio_dev));1586 }1587 1588 if (ret & VCNL4040_ALS_RISING) {1589 iio_push_event(indio_dev,1590 IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,1591 IIO_EV_TYPE_THRESH,1592 IIO_EV_DIR_RISING),1593 iio_get_time_ns(indio_dev));1594 }1595 1596 return IRQ_HANDLED;1597}1598 1599static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,1600 uintptr_t priv,1601 const struct iio_chan_spec *chan,1602 char *buf)1603{1604 struct vcnl4000_data *data = iio_priv(indio_dev);1605 1606 return sprintf(buf, "%u\n", data->near_level);1607}1608 1609static irqreturn_t vcnl4010_irq_thread(int irq, void *p)1610{1611 struct iio_dev *indio_dev = p;1612 struct vcnl4000_data *data = iio_priv(indio_dev);1613 unsigned long isr;1614 int ret;1615 1616 ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);1617 if (ret < 0)1618 goto end;1619 1620 isr = ret;1621 1622 if (isr & VCNL4010_INT_THR) {1623 if (test_bit(VCNL4010_INT_THR_LOW, &isr)) {1624 iio_push_event(indio_dev,1625 IIO_UNMOD_EVENT_CODE(1626 IIO_PROXIMITY,1627 1,1628 IIO_EV_TYPE_THRESH,1629 IIO_EV_DIR_FALLING),1630 iio_get_time_ns(indio_dev));1631 }1632 1633 if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) {1634 iio_push_event(indio_dev,1635 IIO_UNMOD_EVENT_CODE(1636 IIO_PROXIMITY,1637 1,1638 IIO_EV_TYPE_THRESH,1639 IIO_EV_DIR_RISING),1640 iio_get_time_ns(indio_dev));1641 }1642 1643 i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,1644 isr & VCNL4010_INT_THR);1645 }1646 1647 if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev))1648 iio_trigger_poll_nested(indio_dev->trig);1649 1650end:1651 return IRQ_HANDLED;1652}1653 1654static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)1655{1656 struct iio_poll_func *pf = p;1657 struct iio_dev *indio_dev = pf->indio_dev;1658 struct vcnl4000_data *data = iio_priv(indio_dev);1659 const unsigned long *active_scan_mask = indio_dev->active_scan_mask;1660 u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */1661 bool data_read = false;1662 unsigned long isr;1663 int val = 0;1664 int ret;1665 1666 ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);1667 if (ret < 0)1668 goto end;1669 1670 isr = ret;1671 1672 if (test_bit(0, active_scan_mask)) {1673 if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) {1674 ret = vcnl4000_read_data(data,1675 VCNL4000_PS_RESULT_HI,1676 &val);1677 if (ret < 0)1678 goto end;1679 1680 buffer[0] = val;1681 data_read = true;1682 }1683 }1684 1685 ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,1686 isr & VCNL4010_INT_DRDY);1687 if (ret < 0)1688 goto end;1689 1690 if (!data_read)1691 goto end;1692 1693 iio_push_to_buffers_with_timestamp(indio_dev, buffer,1694 iio_get_time_ns(indio_dev));1695 1696end:1697 iio_trigger_notify_done(indio_dev->trig);1698 return IRQ_HANDLED;1699}1700 1701static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev)1702{1703 struct vcnl4000_data *data = iio_priv(indio_dev);1704 int ret;1705 int cmd;1706 1707 /* Do not enable the buffer if we are already capturing events. */1708 if (vcnl4010_is_in_periodic_mode(data))1709 return -EBUSY;1710 1711 ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL,1712 VCNL4010_INT_PROX_EN);1713 if (ret < 0)1714 return ret;1715 1716 cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;1717 return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd);1718}1719 1720static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev)1721{1722 struct vcnl4000_data *data = iio_priv(indio_dev);1723 int ret;1724 1725 ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0);1726 if (ret < 0)1727 return ret;1728 1729 return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0);1730}1731 1732static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = {1733 .postenable = &vcnl4010_buffer_postenable,1734 .predisable = &vcnl4010_buffer_predisable,1735};1736 1737static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = {1738 {1739 .name = "nearlevel",1740 .shared = IIO_SEPARATE,1741 .read = vcnl4000_read_near_level,1742 },1743 { /* sentinel */ }1744};1745 1746static const struct iio_event_spec vcnl4000_event_spec[] = {1747 {1748 .type = IIO_EV_TYPE_THRESH,1749 .dir = IIO_EV_DIR_RISING,1750 .mask_separate = BIT(IIO_EV_INFO_VALUE),1751 }, {1752 .type = IIO_EV_TYPE_THRESH,1753 .dir = IIO_EV_DIR_FALLING,1754 .mask_separate = BIT(IIO_EV_INFO_VALUE),1755 }, {1756 .type = IIO_EV_TYPE_THRESH,1757 .dir = IIO_EV_DIR_EITHER,1758 .mask_separate = BIT(IIO_EV_INFO_ENABLE),1759 }1760};1761 1762static const struct iio_event_spec vcnl4040_als_event_spec[] = {1763 {1764 .type = IIO_EV_TYPE_THRESH,1765 .dir = IIO_EV_DIR_RISING,1766 .mask_separate = BIT(IIO_EV_INFO_VALUE),1767 }, {1768 .type = IIO_EV_TYPE_THRESH,1769 .dir = IIO_EV_DIR_FALLING,1770 .mask_separate = BIT(IIO_EV_INFO_VALUE),1771 }, {1772 .type = IIO_EV_TYPE_THRESH,1773 .dir = IIO_EV_DIR_EITHER,1774 .mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_PERIOD),1775 },1776};1777 1778static const struct iio_event_spec vcnl4040_event_spec[] = {1779 {1780 .type = IIO_EV_TYPE_THRESH,1781 .dir = IIO_EV_DIR_RISING,1782 .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),1783 }, {1784 .type = IIO_EV_TYPE_THRESH,1785 .dir = IIO_EV_DIR_FALLING,1786 .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),1787 }, {1788 .type = IIO_EV_TYPE_THRESH,1789 .dir = IIO_EV_DIR_EITHER,1790 .mask_separate = BIT(IIO_EV_INFO_PERIOD),1791 },1792};1793 1794static const struct iio_chan_spec vcnl4000_channels[] = {1795 {1796 .type = IIO_LIGHT,1797 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |1798 BIT(IIO_CHAN_INFO_SCALE),1799 }, {1800 .type = IIO_PROXIMITY,1801 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),1802 .ext_info = vcnl4000_ext_info,1803 }1804};1805 1806static const struct iio_chan_spec vcnl4010_channels[] = {1807 {1808 .type = IIO_LIGHT,1809 .scan_index = -1,1810 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |1811 BIT(IIO_CHAN_INFO_SCALE),1812 }, {1813 .type = IIO_PROXIMITY,1814 .scan_index = 0,1815 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |1816 BIT(IIO_CHAN_INFO_SAMP_FREQ),1817 .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),1818 .event_spec = vcnl4000_event_spec,1819 .num_event_specs = ARRAY_SIZE(vcnl4000_event_spec),1820 .ext_info = vcnl4000_ext_info,1821 .scan_type = {1822 .sign = 'u',1823 .realbits = 16,1824 .storagebits = 16,1825 .endianness = IIO_CPU,1826 },1827 },1828 IIO_CHAN_SOFT_TIMESTAMP(1),1829};1830 1831static const struct iio_chan_spec vcnl4040_channels[] = {1832 {1833 .type = IIO_LIGHT,1834 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |1835 BIT(IIO_CHAN_INFO_SCALE) |1836 BIT(IIO_CHAN_INFO_INT_TIME),1837 .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME),1838 .event_spec = vcnl4040_als_event_spec,1839 .num_event_specs = ARRAY_SIZE(vcnl4040_als_event_spec),1840 }, {1841 .type = IIO_PROXIMITY,1842 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |1843 BIT(IIO_CHAN_INFO_INT_TIME) |1844 BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |1845 BIT(IIO_CHAN_INFO_CALIBBIAS),1846 .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) |1847 BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |1848 BIT(IIO_CHAN_INFO_CALIBBIAS),1849 .ext_info = vcnl4000_ext_info,1850 .event_spec = vcnl4040_event_spec,1851 .num_event_specs = ARRAY_SIZE(vcnl4040_event_spec),1852 }1853};1854 1855static const struct iio_info vcnl4000_info = {1856 .read_raw = vcnl4000_read_raw,1857};1858 1859static const struct iio_info vcnl4010_info = {1860 .read_raw = vcnl4010_read_raw,1861 .read_avail = vcnl4010_read_avail,1862 .write_raw = vcnl4010_write_raw,1863 .read_event_value = vcnl4010_read_event,1864 .write_event_value = vcnl4010_write_event,1865 .read_event_config = vcnl4010_read_event_config,1866 .write_event_config = vcnl4010_write_event_config,1867};1868 1869static const struct iio_info vcnl4040_info = {1870 .read_raw = vcnl4000_read_raw,1871 .write_raw = vcnl4040_write_raw,1872 .read_event_value = vcnl4040_read_event,1873 .write_event_value = vcnl4040_write_event,1874 .read_event_config = vcnl4040_read_event_config,1875 .write_event_config = vcnl4040_write_event_config,1876 .read_avail = vcnl4040_read_avail,1877};1878 1879static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {1880 [VCNL4000] = {1881 .prod = "VCNL4000",1882 .init = vcnl4000_init,1883 .measure_light = vcnl4000_measure_light,1884 .measure_proximity = vcnl4000_measure_proximity,1885 .set_power_state = vcnl4000_set_power_state,1886 .channels = vcnl4000_channels,1887 .num_channels = ARRAY_SIZE(vcnl4000_channels),1888 .info = &vcnl4000_info,1889 },1890 [VCNL4010] = {1891 .prod = "VCNL4010/4020",1892 .init = vcnl4000_init,1893 .measure_light = vcnl4000_measure_light,1894 .measure_proximity = vcnl4000_measure_proximity,1895 .set_power_state = vcnl4000_set_power_state,1896 .channels = vcnl4010_channels,1897 .num_channels = ARRAY_SIZE(vcnl4010_channels),1898 .info = &vcnl4010_info,1899 .irq_thread = vcnl4010_irq_thread,1900 .trig_buffer_func = vcnl4010_trigger_handler,1901 .buffer_setup_ops = &vcnl4010_buffer_ops,1902 },1903 [VCNL4040] = {1904 .prod = "VCNL4040",1905 .init = vcnl4200_init,1906 .measure_light = vcnl4200_measure_light,1907 .measure_proximity = vcnl4200_measure_proximity,1908 .set_power_state = vcnl4200_set_power_state,1909 .channels = vcnl4040_channels,1910 .num_channels = ARRAY_SIZE(vcnl4040_channels),1911 .info = &vcnl4040_info,1912 .irq_thread = vcnl4040_irq_thread,1913 .int_reg = VCNL4040_INT_FLAGS,1914 .ps_it_times = &vcnl4040_ps_it_times,1915 .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times),1916 .als_it_times = &vcnl4040_als_it_times,1917 .num_als_it_times = ARRAY_SIZE(vcnl4040_als_it_times),1918 .ulux_step = 100000,1919 },1920 [VCNL4200] = {1921 .prod = "VCNL4200",1922 .init = vcnl4200_init,1923 .measure_light = vcnl4200_measure_light,1924 .measure_proximity = vcnl4200_measure_proximity,1925 .set_power_state = vcnl4200_set_power_state,1926 .channels = vcnl4040_channels,1927 .num_channels = ARRAY_SIZE(vcnl4000_channels),1928 .info = &vcnl4040_info,1929 .irq_thread = vcnl4040_irq_thread,1930 .int_reg = VCNL4200_INT_FLAGS,1931 .ps_it_times = &vcnl4200_ps_it_times,1932 .num_ps_it_times = ARRAY_SIZE(vcnl4200_ps_it_times),1933 .als_it_times = &vcnl4200_als_it_times,1934 .num_als_it_times = ARRAY_SIZE(vcnl4200_als_it_times),1935 .ulux_step = 24000,1936 },1937};1938 1939static const struct iio_trigger_ops vcnl4010_trigger_ops = {1940 .validate_device = iio_trigger_validate_own_device,1941};1942 1943static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)1944{1945 struct vcnl4000_data *data = iio_priv(indio_dev);1946 struct i2c_client *client = data->client;1947 struct iio_trigger *trigger;1948 1949 trigger = devm_iio_trigger_alloc(&client->dev, "%s-dev%d",1950 indio_dev->name,1951 iio_device_id(indio_dev));1952 if (!trigger)1953 return -ENOMEM;1954 1955 trigger->ops = &vcnl4010_trigger_ops;1956 iio_trigger_set_drvdata(trigger, indio_dev);1957 1958 return devm_iio_trigger_register(&client->dev, trigger);1959}1960 1961static int vcnl4000_probe(struct i2c_client *client)1962{1963 const struct i2c_device_id *id = i2c_client_get_device_id(client);1964 struct vcnl4000_data *data;1965 struct iio_dev *indio_dev;1966 int ret;1967 1968 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));1969 if (!indio_dev)1970 return -ENOMEM;1971 1972 data = iio_priv(indio_dev);1973 i2c_set_clientdata(client, indio_dev);1974 data->client = client;1975 data->id = id->driver_data;1976 data->chip_spec = &vcnl4000_chip_spec_cfg[data->id];1977 1978 mutex_init(&data->vcnl4000_lock);1979 1980 ret = data->chip_spec->init(data);1981 if (ret < 0)1982 return ret;1983 1984 dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n",1985 data->chip_spec->prod, data->rev);1986 1987 if (device_property_read_u32(&client->dev, "proximity-near-level",1988 &data->near_level))1989 data->near_level = 0;1990 1991 indio_dev->info = data->chip_spec->info;1992 indio_dev->channels = data->chip_spec->channels;1993 indio_dev->num_channels = data->chip_spec->num_channels;1994 indio_dev->name = VCNL4000_DRV_NAME;1995 indio_dev->modes = INDIO_DIRECT_MODE;1996 1997 if (data->chip_spec->trig_buffer_func &&1998 data->chip_spec->buffer_setup_ops) {1999 ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,2000 NULL,2001 data->chip_spec->trig_buffer_func,2002 data->chip_spec->buffer_setup_ops);2003 if (ret < 0) {2004 dev_err(&client->dev,2005 "unable to setup iio triggered buffer\n");2006 return ret;2007 }2008 }2009 2010 if (client->irq && data->chip_spec->irq_thread) {2011 ret = devm_request_threaded_irq(&client->dev, client->irq,2012 NULL, data->chip_spec->irq_thread,2013 IRQF_TRIGGER_FALLING |2014 IRQF_ONESHOT,2015 "vcnl4000_irq",2016 indio_dev);2017 if (ret < 0) {2018 dev_err(&client->dev, "irq request failed\n");2019 return ret;2020 }2021 2022 ret = vcnl4010_probe_trigger(indio_dev);2023 if (ret < 0)2024 return ret;2025 }2026 2027 ret = pm_runtime_set_active(&client->dev);2028 if (ret < 0)2029 goto fail_poweroff;2030 2031 ret = iio_device_register(indio_dev);2032 if (ret < 0)2033 goto fail_poweroff;2034 2035 pm_runtime_enable(&client->dev);2036 pm_runtime_set_autosuspend_delay(&client->dev, VCNL4000_SLEEP_DELAY_MS);2037 pm_runtime_use_autosuspend(&client->dev);2038 2039 return 0;2040fail_poweroff:2041 data->chip_spec->set_power_state(data, false);2042 return ret;2043}2044 2045static const struct of_device_id vcnl_4000_of_match[] = {2046 {2047 .compatible = "vishay,vcnl4000",2048 .data = (void *)VCNL4000,2049 },2050 {2051 .compatible = "vishay,vcnl4010",2052 .data = (void *)VCNL4010,2053 },2054 {2055 .compatible = "vishay,vcnl4020",2056 .data = (void *)VCNL4010,2057 },2058 {2059 .compatible = "vishay,vcnl4040",2060 .data = (void *)VCNL4040,2061 },2062 {2063 .compatible = "vishay,vcnl4200",2064 .data = (void *)VCNL4200,2065 },2066 {},2067};2068MODULE_DEVICE_TABLE(of, vcnl_4000_of_match);2069 2070static void vcnl4000_remove(struct i2c_client *client)2071{2072 struct iio_dev *indio_dev = i2c_get_clientdata(client);2073 struct vcnl4000_data *data = iio_priv(indio_dev);2074 int ret;2075 2076 pm_runtime_dont_use_autosuspend(&client->dev);2077 pm_runtime_disable(&client->dev);2078 iio_device_unregister(indio_dev);2079 pm_runtime_set_suspended(&client->dev);2080 2081 ret = data->chip_spec->set_power_state(data, false);2082 if (ret)2083 dev_warn(&client->dev, "Failed to power down (%pe)\n",2084 ERR_PTR(ret));2085}2086 2087static int vcnl4000_runtime_suspend(struct device *dev)2088{2089 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));2090 struct vcnl4000_data *data = iio_priv(indio_dev);2091 2092 return data->chip_spec->set_power_state(data, false);2093}2094 2095static int vcnl4000_runtime_resume(struct device *dev)2096{2097 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));2098 struct vcnl4000_data *data = iio_priv(indio_dev);2099 2100 return data->chip_spec->set_power_state(data, true);2101}2102 2103static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4000_pm_ops, vcnl4000_runtime_suspend,2104 vcnl4000_runtime_resume, NULL);2105 2106static struct i2c_driver vcnl4000_driver = {2107 .driver = {2108 .name = VCNL4000_DRV_NAME,2109 .pm = pm_ptr(&vcnl4000_pm_ops),2110 .of_match_table = vcnl_4000_of_match,2111 },2112 .probe = vcnl4000_probe,2113 .id_table = vcnl4000_id,2114 .remove = vcnl4000_remove,2115};2116 2117module_i2c_driver(vcnl4000_driver);2118 2119MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");2120MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");2121MODULE_DESCRIPTION("Vishay VCNL4000 proximity/ambient light sensor driver");2122MODULE_LICENSE("GPL");2123