Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4040/4200 combined ambient
0004  * light and proximity sensor
0005  *
0006  * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
0007  * Copyright 2019 Pursim SPC
0008  * Copyright 2020 Mathieu Othacehe <m.othacehe@gmail.com>
0009  *
0010  * IIO driver for:
0011  *   VCNL4000/10/20 (7-bit I2C slave address 0x13)
0012  *   VCNL4040 (7-bit I2C slave address 0x60)
0013  *   VCNL4200 (7-bit I2C slave address 0x51)
0014  *
0015  * TODO:
0016  *   allow to adjust IR current
0017  *   interrupts (VCNL4040, VCNL4200)
0018  */
0019 
0020 #include <linux/module.h>
0021 #include <linux/i2c.h>
0022 #include <linux/err.h>
0023 #include <linux/delay.h>
0024 #include <linux/pm_runtime.h>
0025 #include <linux/interrupt.h>
0026 
0027 #include <linux/iio/buffer.h>
0028 #include <linux/iio/events.h>
0029 #include <linux/iio/iio.h>
0030 #include <linux/iio/sysfs.h>
0031 #include <linux/iio/trigger.h>
0032 #include <linux/iio/trigger_consumer.h>
0033 #include <linux/iio/triggered_buffer.h>
0034 
0035 #define VCNL4000_DRV_NAME "vcnl4000"
0036 #define VCNL4000_PROD_ID    0x01
0037 #define VCNL4010_PROD_ID    0x02 /* for VCNL4020, VCNL4010 */
0038 #define VCNL4040_PROD_ID    0x86
0039 #define VCNL4200_PROD_ID    0x58
0040 
0041 #define VCNL4000_COMMAND    0x80 /* Command register */
0042 #define VCNL4000_PROD_REV   0x81 /* Product ID and Revision ID */
0043 #define VCNL4010_PROX_RATE      0x82 /* Proximity rate */
0044 #define VCNL4000_LED_CURRENT    0x83 /* IR LED current for proximity mode */
0045 #define VCNL4000_AL_PARAM   0x84 /* Ambient light parameter register */
0046 #define VCNL4010_ALS_PARAM      0x84 /* ALS rate */
0047 #define VCNL4000_AL_RESULT_HI   0x85 /* Ambient light result register, MSB */
0048 #define VCNL4000_AL_RESULT_LO   0x86 /* Ambient light result register, LSB */
0049 #define VCNL4000_PS_RESULT_HI   0x87 /* Proximity result register, MSB */
0050 #define VCNL4000_PS_RESULT_LO   0x88 /* Proximity result register, LSB */
0051 #define VCNL4000_PS_MEAS_FREQ   0x89 /* Proximity test signal frequency */
0052 #define VCNL4010_INT_CTRL   0x89 /* Interrupt control */
0053 #define VCNL4000_PS_MOD_ADJ 0x8a /* Proximity modulator timing adjustment */
0054 #define VCNL4010_LOW_THR_HI     0x8a /* Low threshold, MSB */
0055 #define VCNL4010_LOW_THR_LO     0x8b /* Low threshold, LSB */
0056 #define VCNL4010_HIGH_THR_HI    0x8c /* High threshold, MSB */
0057 #define VCNL4010_HIGH_THR_LO    0x8d /* High threshold, LSB */
0058 #define VCNL4010_ISR        0x8e /* Interrupt status */
0059 
0060 #define VCNL4200_AL_CONF    0x00 /* Ambient light configuration */
0061 #define VCNL4200_PS_CONF1   0x03 /* Proximity configuration */
0062 #define VCNL4200_PS_DATA    0x08 /* Proximity data */
0063 #define VCNL4200_AL_DATA    0x09 /* Ambient light data */
0064 #define VCNL4200_DEV_ID     0x0e /* Device ID, slave address and version */
0065 
0066 #define VCNL4040_DEV_ID     0x0c /* Device ID and version */
0067 
0068 /* Bit masks for COMMAND register */
0069 #define VCNL4000_AL_RDY     BIT(6) /* ALS data ready? */
0070 #define VCNL4000_PS_RDY     BIT(5) /* proximity data ready? */
0071 #define VCNL4000_AL_OD      BIT(4) /* start on-demand ALS measurement */
0072 #define VCNL4000_PS_OD      BIT(3) /* start on-demand proximity measurement */
0073 #define VCNL4000_ALS_EN     BIT(2) /* start ALS measurement */
0074 #define VCNL4000_PROX_EN    BIT(1) /* start proximity measurement */
0075 #define VCNL4000_SELF_TIMED_EN  BIT(0) /* start self-timed measurement */
0076 
0077 /* Bit masks for interrupt registers. */
0078 #define VCNL4010_INT_THR_SEL    BIT(0) /* Select threshold interrupt source */
0079 #define VCNL4010_INT_THR_EN BIT(1) /* Threshold interrupt type */
0080 #define VCNL4010_INT_ALS_EN BIT(2) /* Enable on ALS data ready */
0081 #define VCNL4010_INT_PROX_EN    BIT(3) /* Enable on proximity data ready */
0082 
0083 #define VCNL4010_INT_THR_HIGH   0 /* High threshold exceeded */
0084 #define VCNL4010_INT_THR_LOW    1 /* Low threshold exceeded */
0085 #define VCNL4010_INT_ALS    2 /* ALS data ready */
0086 #define VCNL4010_INT_PROXIMITY  3 /* Proximity data ready */
0087 
0088 #define VCNL4010_INT_THR \
0089     (BIT(VCNL4010_INT_THR_LOW) | BIT(VCNL4010_INT_THR_HIGH))
0090 #define VCNL4010_INT_DRDY \
0091     (BIT(VCNL4010_INT_PROXIMITY) | BIT(VCNL4010_INT_ALS))
0092 
0093 static const int vcnl4010_prox_sampling_frequency[][2] = {
0094     {1, 950000},
0095     {3, 906250},
0096     {7, 812500},
0097     {16, 625000},
0098     {31, 250000},
0099     {62, 500000},
0100     {125, 0},
0101     {250, 0},
0102 };
0103 
0104 #define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */
0105 
0106 enum vcnl4000_device_ids {
0107     VCNL4000,
0108     VCNL4010,
0109     VCNL4040,
0110     VCNL4200,
0111 };
0112 
0113 struct vcnl4200_channel {
0114     u8 reg;
0115     ktime_t last_measurement;
0116     ktime_t sampling_rate;
0117     struct mutex lock;
0118 };
0119 
0120 struct vcnl4000_data {
0121     struct i2c_client *client;
0122     enum vcnl4000_device_ids id;
0123     int rev;
0124     int al_scale;
0125     const struct vcnl4000_chip_spec *chip_spec;
0126     struct mutex vcnl4000_lock;
0127     struct vcnl4200_channel vcnl4200_al;
0128     struct vcnl4200_channel vcnl4200_ps;
0129     uint32_t near_level;
0130 };
0131 
0132 struct vcnl4000_chip_spec {
0133     const char *prod;
0134     struct iio_chan_spec const *channels;
0135     const int num_channels;
0136     const struct iio_info *info;
0137     bool irq_support;
0138     int (*init)(struct vcnl4000_data *data);
0139     int (*measure_light)(struct vcnl4000_data *data, int *val);
0140     int (*measure_proximity)(struct vcnl4000_data *data, int *val);
0141     int (*set_power_state)(struct vcnl4000_data *data, bool on);
0142 };
0143 
0144 static const struct i2c_device_id vcnl4000_id[] = {
0145     { "vcnl4000", VCNL4000 },
0146     { "vcnl4010", VCNL4010 },
0147     { "vcnl4020", VCNL4010 },
0148     { "vcnl4040", VCNL4040 },
0149     { "vcnl4200", VCNL4200 },
0150     { }
0151 };
0152 MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
0153 
0154 static int vcnl4000_set_power_state(struct vcnl4000_data *data, bool on)
0155 {
0156     /* no suspend op */
0157     return 0;
0158 }
0159 
0160 static int vcnl4000_init(struct vcnl4000_data *data)
0161 {
0162     int ret, prod_id;
0163 
0164     ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
0165     if (ret < 0)
0166         return ret;
0167 
0168     prod_id = ret >> 4;
0169     switch (prod_id) {
0170     case VCNL4000_PROD_ID:
0171         if (data->id != VCNL4000)
0172             dev_warn(&data->client->dev,
0173                     "wrong device id, use vcnl4000");
0174         break;
0175     case VCNL4010_PROD_ID:
0176         if (data->id != VCNL4010)
0177             dev_warn(&data->client->dev,
0178                     "wrong device id, use vcnl4010/4020");
0179         break;
0180     default:
0181         return -ENODEV;
0182     }
0183 
0184     data->rev = ret & 0xf;
0185     data->al_scale = 250000;
0186     mutex_init(&data->vcnl4000_lock);
0187 
0188     return data->chip_spec->set_power_state(data, true);
0189 };
0190 
0191 static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
0192 {
0193     u16 val = on ? 0 /* power on */ : 1 /* shut down */;
0194     int ret;
0195 
0196     ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, val);
0197     if (ret < 0)
0198         return ret;
0199 
0200     ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val);
0201     if (ret < 0)
0202         return ret;
0203 
0204     if (on) {
0205         /* Wait at least one integration cycle before fetching data */
0206         data->vcnl4200_al.last_measurement = ktime_get();
0207         data->vcnl4200_ps.last_measurement = ktime_get();
0208     }
0209 
0210     return 0;
0211 }
0212 
0213 static int vcnl4200_init(struct vcnl4000_data *data)
0214 {
0215     int ret, id;
0216 
0217     ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
0218     if (ret < 0)
0219         return ret;
0220 
0221     id = ret & 0xff;
0222 
0223     if (id != VCNL4200_PROD_ID) {
0224         ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID);
0225         if (ret < 0)
0226             return ret;
0227 
0228         id = ret & 0xff;
0229 
0230         if (id != VCNL4040_PROD_ID)
0231             return -ENODEV;
0232     }
0233 
0234     dev_dbg(&data->client->dev, "device id 0x%x", id);
0235 
0236     data->rev = (ret >> 8) & 0xf;
0237 
0238     data->vcnl4200_al.reg = VCNL4200_AL_DATA;
0239     data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
0240     switch (id) {
0241     case VCNL4200_PROD_ID:
0242         /* Default wait time is 50ms, add 20% tolerance. */
0243         data->vcnl4200_al.sampling_rate = ktime_set(0, 60000 * 1000);
0244         /* Default wait time is 4.8ms, add 20% tolerance. */
0245         data->vcnl4200_ps.sampling_rate = ktime_set(0, 5760 * 1000);
0246         data->al_scale = 24000;
0247         break;
0248     case VCNL4040_PROD_ID:
0249         /* Default wait time is 80ms, add 20% tolerance. */
0250         data->vcnl4200_al.sampling_rate = ktime_set(0, 96000 * 1000);
0251         /* Default wait time is 5ms, add 20% tolerance. */
0252         data->vcnl4200_ps.sampling_rate = ktime_set(0, 6000 * 1000);
0253         data->al_scale = 120000;
0254         break;
0255     }
0256     mutex_init(&data->vcnl4200_al.lock);
0257     mutex_init(&data->vcnl4200_ps.lock);
0258 
0259     ret = data->chip_spec->set_power_state(data, true);
0260     if (ret < 0)
0261         return ret;
0262 
0263     return 0;
0264 };
0265 
0266 static int vcnl4000_read_data(struct vcnl4000_data *data, u8 data_reg, int *val)
0267 {
0268     s32 ret;
0269 
0270     ret = i2c_smbus_read_word_swapped(data->client, data_reg);
0271     if (ret < 0)
0272         return ret;
0273 
0274     *val = ret;
0275     return 0;
0276 }
0277 
0278 static int vcnl4000_write_data(struct vcnl4000_data *data, u8 data_reg, int val)
0279 {
0280     if (val > U16_MAX)
0281         return -ERANGE;
0282 
0283     return i2c_smbus_write_word_swapped(data->client, data_reg, val);
0284 }
0285 
0286 
0287 static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
0288                 u8 rdy_mask, u8 data_reg, int *val)
0289 {
0290     int tries = 20;
0291     int ret;
0292 
0293     mutex_lock(&data->vcnl4000_lock);
0294 
0295     ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
0296                     req_mask);
0297     if (ret < 0)
0298         goto fail;
0299 
0300     /* wait for data to become ready */
0301     while (tries--) {
0302         ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
0303         if (ret < 0)
0304             goto fail;
0305         if (ret & rdy_mask)
0306             break;
0307         msleep(20); /* measurement takes up to 100 ms */
0308     }
0309 
0310     if (tries < 0) {
0311         dev_err(&data->client->dev,
0312             "vcnl4000_measure() failed, data not ready\n");
0313         ret = -EIO;
0314         goto fail;
0315     }
0316 
0317     ret = vcnl4000_read_data(data, data_reg, val);
0318     if (ret < 0)
0319         goto fail;
0320 
0321     mutex_unlock(&data->vcnl4000_lock);
0322 
0323     return 0;
0324 
0325 fail:
0326     mutex_unlock(&data->vcnl4000_lock);
0327     return ret;
0328 }
0329 
0330 static int vcnl4200_measure(struct vcnl4000_data *data,
0331         struct vcnl4200_channel *chan, int *val)
0332 {
0333     int ret;
0334     s64 delta;
0335     ktime_t next_measurement;
0336 
0337     mutex_lock(&chan->lock);
0338 
0339     next_measurement = ktime_add(chan->last_measurement,
0340             chan->sampling_rate);
0341     delta = ktime_us_delta(next_measurement, ktime_get());
0342     if (delta > 0)
0343         usleep_range(delta, delta + 500);
0344     chan->last_measurement = ktime_get();
0345 
0346     mutex_unlock(&chan->lock);
0347 
0348     ret = i2c_smbus_read_word_data(data->client, chan->reg);
0349     if (ret < 0)
0350         return ret;
0351 
0352     *val = ret;
0353 
0354     return 0;
0355 }
0356 
0357 static int vcnl4000_measure_light(struct vcnl4000_data *data, int *val)
0358 {
0359     return vcnl4000_measure(data,
0360             VCNL4000_AL_OD, VCNL4000_AL_RDY,
0361             VCNL4000_AL_RESULT_HI, val);
0362 }
0363 
0364 static int vcnl4200_measure_light(struct vcnl4000_data *data, int *val)
0365 {
0366     return vcnl4200_measure(data, &data->vcnl4200_al, val);
0367 }
0368 
0369 static int vcnl4000_measure_proximity(struct vcnl4000_data *data, int *val)
0370 {
0371     return vcnl4000_measure(data,
0372             VCNL4000_PS_OD, VCNL4000_PS_RDY,
0373             VCNL4000_PS_RESULT_HI, val);
0374 }
0375 
0376 static int vcnl4200_measure_proximity(struct vcnl4000_data *data, int *val)
0377 {
0378     return vcnl4200_measure(data, &data->vcnl4200_ps, val);
0379 }
0380 
0381 static int vcnl4010_read_proxy_samp_freq(struct vcnl4000_data *data, int *val,
0382                      int *val2)
0383 {
0384     int ret;
0385 
0386     ret = i2c_smbus_read_byte_data(data->client, VCNL4010_PROX_RATE);
0387     if (ret < 0)
0388         return ret;
0389 
0390     if (ret >= ARRAY_SIZE(vcnl4010_prox_sampling_frequency))
0391         return -EINVAL;
0392 
0393     *val = vcnl4010_prox_sampling_frequency[ret][0];
0394     *val2 = vcnl4010_prox_sampling_frequency[ret][1];
0395 
0396     return 0;
0397 }
0398 
0399 static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data)
0400 {
0401     int ret;
0402 
0403     ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
0404     if (ret < 0)
0405         return false;
0406 
0407     return !!(ret & VCNL4000_SELF_TIMED_EN);
0408 }
0409 
0410 static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
0411 {
0412     struct device *dev = &data->client->dev;
0413     int ret;
0414 
0415     if (on) {
0416         ret = pm_runtime_resume_and_get(dev);
0417     } else {
0418         pm_runtime_mark_last_busy(dev);
0419         ret = pm_runtime_put_autosuspend(dev);
0420     }
0421 
0422     return ret;
0423 }
0424 
0425 static int vcnl4000_read_raw(struct iio_dev *indio_dev,
0426                 struct iio_chan_spec const *chan,
0427                 int *val, int *val2, long mask)
0428 {
0429     int ret;
0430     struct vcnl4000_data *data = iio_priv(indio_dev);
0431 
0432     switch (mask) {
0433     case IIO_CHAN_INFO_RAW:
0434         ret = vcnl4000_set_pm_runtime_state(data, true);
0435         if  (ret < 0)
0436             return ret;
0437 
0438         switch (chan->type) {
0439         case IIO_LIGHT:
0440             ret = data->chip_spec->measure_light(data, val);
0441             if (!ret)
0442                 ret = IIO_VAL_INT;
0443             break;
0444         case IIO_PROXIMITY:
0445             ret = data->chip_spec->measure_proximity(data, val);
0446             if (!ret)
0447                 ret = IIO_VAL_INT;
0448             break;
0449         default:
0450             ret = -EINVAL;
0451         }
0452         vcnl4000_set_pm_runtime_state(data, false);
0453         return ret;
0454     case IIO_CHAN_INFO_SCALE:
0455         if (chan->type != IIO_LIGHT)
0456             return -EINVAL;
0457 
0458         *val = 0;
0459         *val2 = data->al_scale;
0460         return IIO_VAL_INT_PLUS_MICRO;
0461     default:
0462         return -EINVAL;
0463     }
0464 }
0465 
0466 static int vcnl4010_read_raw(struct iio_dev *indio_dev,
0467                  struct iio_chan_spec const *chan,
0468                  int *val, int *val2, long mask)
0469 {
0470     int ret;
0471     struct vcnl4000_data *data = iio_priv(indio_dev);
0472 
0473     switch (mask) {
0474     case IIO_CHAN_INFO_RAW:
0475     case IIO_CHAN_INFO_SCALE:
0476         ret = iio_device_claim_direct_mode(indio_dev);
0477         if (ret)
0478             return ret;
0479 
0480         /* Protect against event capture. */
0481         if (vcnl4010_is_in_periodic_mode(data)) {
0482             ret = -EBUSY;
0483         } else {
0484             ret = vcnl4000_read_raw(indio_dev, chan, val, val2,
0485                         mask);
0486         }
0487 
0488         iio_device_release_direct_mode(indio_dev);
0489         return ret;
0490     case IIO_CHAN_INFO_SAMP_FREQ:
0491         switch (chan->type) {
0492         case IIO_PROXIMITY:
0493             ret = vcnl4010_read_proxy_samp_freq(data, val, val2);
0494             if (ret < 0)
0495                 return ret;
0496             return IIO_VAL_INT_PLUS_MICRO;
0497         default:
0498             return -EINVAL;
0499         }
0500     default:
0501         return -EINVAL;
0502     }
0503 }
0504 
0505 static int vcnl4010_read_avail(struct iio_dev *indio_dev,
0506                    struct iio_chan_spec const *chan,
0507                    const int **vals, int *type, int *length,
0508                    long mask)
0509 {
0510     switch (mask) {
0511     case IIO_CHAN_INFO_SAMP_FREQ:
0512         *vals = (int *)vcnl4010_prox_sampling_frequency;
0513         *type = IIO_VAL_INT_PLUS_MICRO;
0514         *length = 2 * ARRAY_SIZE(vcnl4010_prox_sampling_frequency);
0515         return IIO_AVAIL_LIST;
0516     default:
0517         return -EINVAL;
0518     }
0519 }
0520 
0521 static int vcnl4010_write_proxy_samp_freq(struct vcnl4000_data *data, int val,
0522                       int val2)
0523 {
0524     unsigned int i;
0525     int index = -1;
0526 
0527     for (i = 0; i < ARRAY_SIZE(vcnl4010_prox_sampling_frequency); i++) {
0528         if (val == vcnl4010_prox_sampling_frequency[i][0] &&
0529             val2 == vcnl4010_prox_sampling_frequency[i][1]) {
0530             index = i;
0531             break;
0532         }
0533     }
0534 
0535     if (index < 0)
0536         return -EINVAL;
0537 
0538     return i2c_smbus_write_byte_data(data->client, VCNL4010_PROX_RATE,
0539                      index);
0540 }
0541 
0542 static int vcnl4010_write_raw(struct iio_dev *indio_dev,
0543                   struct iio_chan_spec const *chan,
0544                   int val, int val2, long mask)
0545 {
0546     int ret;
0547     struct vcnl4000_data *data = iio_priv(indio_dev);
0548 
0549     ret = iio_device_claim_direct_mode(indio_dev);
0550     if (ret)
0551         return ret;
0552 
0553     /* Protect against event capture. */
0554     if (vcnl4010_is_in_periodic_mode(data)) {
0555         ret = -EBUSY;
0556         goto end;
0557     }
0558 
0559     switch (mask) {
0560     case IIO_CHAN_INFO_SAMP_FREQ:
0561         switch (chan->type) {
0562         case IIO_PROXIMITY:
0563             ret = vcnl4010_write_proxy_samp_freq(data, val, val2);
0564             goto end;
0565         default:
0566             ret = -EINVAL;
0567             goto end;
0568         }
0569     default:
0570         ret = -EINVAL;
0571         goto end;
0572     }
0573 
0574 end:
0575     iio_device_release_direct_mode(indio_dev);
0576     return ret;
0577 }
0578 
0579 static int vcnl4010_read_event(struct iio_dev *indio_dev,
0580                    const struct iio_chan_spec *chan,
0581                    enum iio_event_type type,
0582                    enum iio_event_direction dir,
0583                    enum iio_event_info info,
0584                    int *val, int *val2)
0585 {
0586     int ret;
0587     struct vcnl4000_data *data = iio_priv(indio_dev);
0588 
0589     switch (info) {
0590     case IIO_EV_INFO_VALUE:
0591         switch (dir) {
0592         case IIO_EV_DIR_RISING:
0593             ret = vcnl4000_read_data(data, VCNL4010_HIGH_THR_HI,
0594                          val);
0595             if (ret < 0)
0596                 return ret;
0597             return IIO_VAL_INT;
0598         case IIO_EV_DIR_FALLING:
0599             ret = vcnl4000_read_data(data, VCNL4010_LOW_THR_HI,
0600                          val);
0601             if (ret < 0)
0602                 return ret;
0603             return IIO_VAL_INT;
0604         default:
0605             return -EINVAL;
0606         }
0607     default:
0608         return -EINVAL;
0609     }
0610 }
0611 
0612 static int vcnl4010_write_event(struct iio_dev *indio_dev,
0613                 const struct iio_chan_spec *chan,
0614                 enum iio_event_type type,
0615                 enum iio_event_direction dir,
0616                 enum iio_event_info info,
0617                 int val, int val2)
0618 {
0619     int ret;
0620     struct vcnl4000_data *data = iio_priv(indio_dev);
0621 
0622     switch (info) {
0623     case IIO_EV_INFO_VALUE:
0624         switch (dir) {
0625         case IIO_EV_DIR_RISING:
0626             ret = vcnl4000_write_data(data, VCNL4010_HIGH_THR_HI,
0627                           val);
0628             if (ret < 0)
0629                 return ret;
0630             return IIO_VAL_INT;
0631         case IIO_EV_DIR_FALLING:
0632             ret = vcnl4000_write_data(data, VCNL4010_LOW_THR_HI,
0633                           val);
0634             if (ret < 0)
0635                 return ret;
0636             return IIO_VAL_INT;
0637         default:
0638             return -EINVAL;
0639         }
0640     default:
0641         return -EINVAL;
0642     }
0643 }
0644 
0645 static bool vcnl4010_is_thr_enabled(struct vcnl4000_data *data)
0646 {
0647     int ret;
0648 
0649     ret = i2c_smbus_read_byte_data(data->client, VCNL4010_INT_CTRL);
0650     if (ret < 0)
0651         return false;
0652 
0653     return !!(ret & VCNL4010_INT_THR_EN);
0654 }
0655 
0656 static int vcnl4010_read_event_config(struct iio_dev *indio_dev,
0657                       const struct iio_chan_spec *chan,
0658                       enum iio_event_type type,
0659                       enum iio_event_direction dir)
0660 {
0661     struct vcnl4000_data *data = iio_priv(indio_dev);
0662 
0663     switch (chan->type) {
0664     case IIO_PROXIMITY:
0665         return vcnl4010_is_thr_enabled(data);
0666     default:
0667         return -EINVAL;
0668     }
0669 }
0670 
0671 static int vcnl4010_config_threshold(struct iio_dev *indio_dev, bool state)
0672 {
0673     struct vcnl4000_data *data = iio_priv(indio_dev);
0674     int ret;
0675     int icr;
0676     int command;
0677 
0678     if (state) {
0679         ret = iio_device_claim_direct_mode(indio_dev);
0680         if (ret)
0681             return ret;
0682 
0683         /* Enable periodic measurement of proximity data. */
0684         command = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
0685 
0686         /*
0687          * Enable interrupts on threshold, for proximity data by
0688          * default.
0689          */
0690         icr = VCNL4010_INT_THR_EN;
0691     } else {
0692         if (!vcnl4010_is_thr_enabled(data))
0693             return 0;
0694 
0695         command = 0;
0696         icr = 0;
0697     }
0698 
0699     ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
0700                     command);
0701     if (ret < 0)
0702         goto end;
0703 
0704     ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, icr);
0705 
0706 end:
0707     if (state)
0708         iio_device_release_direct_mode(indio_dev);
0709 
0710     return ret;
0711 }
0712 
0713 static int vcnl4010_write_event_config(struct iio_dev *indio_dev,
0714                        const struct iio_chan_spec *chan,
0715                        enum iio_event_type type,
0716                        enum iio_event_direction dir,
0717                        int state)
0718 {
0719     switch (chan->type) {
0720     case IIO_PROXIMITY:
0721         return vcnl4010_config_threshold(indio_dev, state);
0722     default:
0723         return -EINVAL;
0724     }
0725 }
0726 
0727 static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,
0728                     uintptr_t priv,
0729                     const struct iio_chan_spec *chan,
0730                     char *buf)
0731 {
0732     struct vcnl4000_data *data = iio_priv(indio_dev);
0733 
0734     return sprintf(buf, "%u\n", data->near_level);
0735 }
0736 
0737 static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = {
0738     {
0739         .name = "nearlevel",
0740         .shared = IIO_SEPARATE,
0741         .read = vcnl4000_read_near_level,
0742     },
0743     { /* sentinel */ }
0744 };
0745 
0746 static const struct iio_event_spec vcnl4000_event_spec[] = {
0747     {
0748         .type = IIO_EV_TYPE_THRESH,
0749         .dir = IIO_EV_DIR_RISING,
0750         .mask_separate = BIT(IIO_EV_INFO_VALUE),
0751     }, {
0752         .type = IIO_EV_TYPE_THRESH,
0753         .dir = IIO_EV_DIR_FALLING,
0754         .mask_separate = BIT(IIO_EV_INFO_VALUE),
0755     }, {
0756         .type = IIO_EV_TYPE_THRESH,
0757         .dir = IIO_EV_DIR_EITHER,
0758         .mask_separate = BIT(IIO_EV_INFO_ENABLE),
0759     }
0760 };
0761 
0762 static const struct iio_chan_spec vcnl4000_channels[] = {
0763     {
0764         .type = IIO_LIGHT,
0765         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0766             BIT(IIO_CHAN_INFO_SCALE),
0767     }, {
0768         .type = IIO_PROXIMITY,
0769         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0770         .ext_info = vcnl4000_ext_info,
0771     }
0772 };
0773 
0774 static const struct iio_chan_spec vcnl4010_channels[] = {
0775     {
0776         .type = IIO_LIGHT,
0777         .scan_index = -1,
0778         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0779             BIT(IIO_CHAN_INFO_SCALE),
0780     }, {
0781         .type = IIO_PROXIMITY,
0782         .scan_index = 0,
0783         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0784             BIT(IIO_CHAN_INFO_SAMP_FREQ),
0785         .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
0786         .event_spec = vcnl4000_event_spec,
0787         .num_event_specs = ARRAY_SIZE(vcnl4000_event_spec),
0788         .ext_info = vcnl4000_ext_info,
0789         .scan_type = {
0790             .sign = 'u',
0791             .realbits = 16,
0792             .storagebits = 16,
0793             .endianness = IIO_CPU,
0794         },
0795     },
0796     IIO_CHAN_SOFT_TIMESTAMP(1),
0797 };
0798 
0799 static const struct iio_info vcnl4000_info = {
0800     .read_raw = vcnl4000_read_raw,
0801 };
0802 
0803 static const struct iio_info vcnl4010_info = {
0804     .read_raw = vcnl4010_read_raw,
0805     .read_avail = vcnl4010_read_avail,
0806     .write_raw = vcnl4010_write_raw,
0807     .read_event_value = vcnl4010_read_event,
0808     .write_event_value = vcnl4010_write_event,
0809     .read_event_config = vcnl4010_read_event_config,
0810     .write_event_config = vcnl4010_write_event_config,
0811 };
0812 
0813 static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
0814     [VCNL4000] = {
0815         .prod = "VCNL4000",
0816         .init = vcnl4000_init,
0817         .measure_light = vcnl4000_measure_light,
0818         .measure_proximity = vcnl4000_measure_proximity,
0819         .set_power_state = vcnl4000_set_power_state,
0820         .channels = vcnl4000_channels,
0821         .num_channels = ARRAY_SIZE(vcnl4000_channels),
0822         .info = &vcnl4000_info,
0823         .irq_support = false,
0824     },
0825     [VCNL4010] = {
0826         .prod = "VCNL4010/4020",
0827         .init = vcnl4000_init,
0828         .measure_light = vcnl4000_measure_light,
0829         .measure_proximity = vcnl4000_measure_proximity,
0830         .set_power_state = vcnl4000_set_power_state,
0831         .channels = vcnl4010_channels,
0832         .num_channels = ARRAY_SIZE(vcnl4010_channels),
0833         .info = &vcnl4010_info,
0834         .irq_support = true,
0835     },
0836     [VCNL4040] = {
0837         .prod = "VCNL4040",
0838         .init = vcnl4200_init,
0839         .measure_light = vcnl4200_measure_light,
0840         .measure_proximity = vcnl4200_measure_proximity,
0841         .set_power_state = vcnl4200_set_power_state,
0842         .channels = vcnl4000_channels,
0843         .num_channels = ARRAY_SIZE(vcnl4000_channels),
0844         .info = &vcnl4000_info,
0845         .irq_support = false,
0846     },
0847     [VCNL4200] = {
0848         .prod = "VCNL4200",
0849         .init = vcnl4200_init,
0850         .measure_light = vcnl4200_measure_light,
0851         .measure_proximity = vcnl4200_measure_proximity,
0852         .set_power_state = vcnl4200_set_power_state,
0853         .channels = vcnl4000_channels,
0854         .num_channels = ARRAY_SIZE(vcnl4000_channels),
0855         .info = &vcnl4000_info,
0856         .irq_support = false,
0857     },
0858 };
0859 
0860 static irqreturn_t vcnl4010_irq_thread(int irq, void *p)
0861 {
0862     struct iio_dev *indio_dev = p;
0863     struct vcnl4000_data *data = iio_priv(indio_dev);
0864     unsigned long isr;
0865     int ret;
0866 
0867     ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
0868     if (ret < 0)
0869         goto end;
0870 
0871     isr = ret;
0872 
0873     if (isr & VCNL4010_INT_THR) {
0874         if (test_bit(VCNL4010_INT_THR_LOW, &isr)) {
0875             iio_push_event(indio_dev,
0876                        IIO_UNMOD_EVENT_CODE(
0877                            IIO_PROXIMITY,
0878                            1,
0879                            IIO_EV_TYPE_THRESH,
0880                            IIO_EV_DIR_FALLING),
0881                        iio_get_time_ns(indio_dev));
0882         }
0883 
0884         if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) {
0885             iio_push_event(indio_dev,
0886                        IIO_UNMOD_EVENT_CODE(
0887                            IIO_PROXIMITY,
0888                            1,
0889                            IIO_EV_TYPE_THRESH,
0890                            IIO_EV_DIR_RISING),
0891                        iio_get_time_ns(indio_dev));
0892         }
0893 
0894         i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
0895                       isr & VCNL4010_INT_THR);
0896     }
0897 
0898     if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev))
0899         iio_trigger_poll_chained(indio_dev->trig);
0900 
0901 end:
0902     return IRQ_HANDLED;
0903 }
0904 
0905 static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)
0906 {
0907     struct iio_poll_func *pf = p;
0908     struct iio_dev *indio_dev = pf->indio_dev;
0909     struct vcnl4000_data *data = iio_priv(indio_dev);
0910     const unsigned long *active_scan_mask = indio_dev->active_scan_mask;
0911     u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */
0912     bool data_read = false;
0913     unsigned long isr;
0914     int val = 0;
0915     int ret;
0916 
0917     ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
0918     if (ret < 0)
0919         goto end;
0920 
0921     isr = ret;
0922 
0923     if (test_bit(0, active_scan_mask)) {
0924         if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) {
0925             ret = vcnl4000_read_data(data,
0926                          VCNL4000_PS_RESULT_HI,
0927                          &val);
0928             if (ret < 0)
0929                 goto end;
0930 
0931             buffer[0] = val;
0932             data_read = true;
0933         }
0934     }
0935 
0936     ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
0937                     isr & VCNL4010_INT_DRDY);
0938     if (ret < 0)
0939         goto end;
0940 
0941     if (!data_read)
0942         goto end;
0943 
0944     iio_push_to_buffers_with_timestamp(indio_dev, buffer,
0945                        iio_get_time_ns(indio_dev));
0946 
0947 end:
0948     iio_trigger_notify_done(indio_dev->trig);
0949     return IRQ_HANDLED;
0950 }
0951 
0952 static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev)
0953 {
0954     struct vcnl4000_data *data = iio_priv(indio_dev);
0955     int ret;
0956     int cmd;
0957 
0958     /* Do not enable the buffer if we are already capturing events. */
0959     if (vcnl4010_is_in_periodic_mode(data))
0960         return -EBUSY;
0961 
0962     ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL,
0963                     VCNL4010_INT_PROX_EN);
0964     if (ret < 0)
0965         return ret;
0966 
0967     cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
0968     return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd);
0969 }
0970 
0971 static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev)
0972 {
0973     struct vcnl4000_data *data = iio_priv(indio_dev);
0974     int ret;
0975 
0976     ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0);
0977     if (ret < 0)
0978         return ret;
0979 
0980     return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0);
0981 }
0982 
0983 static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = {
0984     .postenable = &vcnl4010_buffer_postenable,
0985     .predisable = &vcnl4010_buffer_predisable,
0986 };
0987 
0988 static const struct iio_trigger_ops vcnl4010_trigger_ops = {
0989     .validate_device = iio_trigger_validate_own_device,
0990 };
0991 
0992 static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)
0993 {
0994     struct vcnl4000_data *data = iio_priv(indio_dev);
0995     struct i2c_client *client = data->client;
0996     struct iio_trigger *trigger;
0997 
0998     trigger = devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
0999                      indio_dev->name,
1000                      iio_device_id(indio_dev));
1001     if (!trigger)
1002         return -ENOMEM;
1003 
1004     trigger->ops = &vcnl4010_trigger_ops;
1005     iio_trigger_set_drvdata(trigger, indio_dev);
1006 
1007     return devm_iio_trigger_register(&client->dev, trigger);
1008 }
1009 
1010 static int vcnl4000_probe(struct i2c_client *client,
1011               const struct i2c_device_id *id)
1012 {
1013     struct vcnl4000_data *data;
1014     struct iio_dev *indio_dev;
1015     int ret;
1016 
1017     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
1018     if (!indio_dev)
1019         return -ENOMEM;
1020 
1021     data = iio_priv(indio_dev);
1022     i2c_set_clientdata(client, indio_dev);
1023     data->client = client;
1024     data->id = id->driver_data;
1025     data->chip_spec = &vcnl4000_chip_spec_cfg[data->id];
1026 
1027     ret = data->chip_spec->init(data);
1028     if (ret < 0)
1029         return ret;
1030 
1031     dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n",
1032         data->chip_spec->prod, data->rev);
1033 
1034     if (device_property_read_u32(&client->dev, "proximity-near-level",
1035                      &data->near_level))
1036         data->near_level = 0;
1037 
1038     indio_dev->info = data->chip_spec->info;
1039     indio_dev->channels = data->chip_spec->channels;
1040     indio_dev->num_channels = data->chip_spec->num_channels;
1041     indio_dev->name = VCNL4000_DRV_NAME;
1042     indio_dev->modes = INDIO_DIRECT_MODE;
1043 
1044     if (client->irq && data->chip_spec->irq_support) {
1045         ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
1046                               NULL,
1047                               vcnl4010_trigger_handler,
1048                               &vcnl4010_buffer_ops);
1049         if (ret < 0) {
1050             dev_err(&client->dev,
1051                 "unable to setup iio triggered buffer\n");
1052             return ret;
1053         }
1054 
1055         ret = devm_request_threaded_irq(&client->dev, client->irq,
1056                         NULL, vcnl4010_irq_thread,
1057                         IRQF_TRIGGER_FALLING |
1058                         IRQF_ONESHOT,
1059                         "vcnl4010_irq",
1060                         indio_dev);
1061         if (ret < 0) {
1062             dev_err(&client->dev, "irq request failed\n");
1063             return ret;
1064         }
1065 
1066         ret = vcnl4010_probe_trigger(indio_dev);
1067         if (ret < 0)
1068             return ret;
1069     }
1070 
1071     ret = pm_runtime_set_active(&client->dev);
1072     if (ret < 0)
1073         goto fail_poweroff;
1074 
1075     ret = iio_device_register(indio_dev);
1076     if (ret < 0)
1077         goto fail_poweroff;
1078 
1079     pm_runtime_enable(&client->dev);
1080     pm_runtime_set_autosuspend_delay(&client->dev, VCNL4000_SLEEP_DELAY_MS);
1081     pm_runtime_use_autosuspend(&client->dev);
1082 
1083     return 0;
1084 fail_poweroff:
1085     data->chip_spec->set_power_state(data, false);
1086     return ret;
1087 }
1088 
1089 static const struct of_device_id vcnl_4000_of_match[] = {
1090     {
1091         .compatible = "vishay,vcnl4000",
1092         .data = (void *)VCNL4000,
1093     },
1094     {
1095         .compatible = "vishay,vcnl4010",
1096         .data = (void *)VCNL4010,
1097     },
1098     {
1099         .compatible = "vishay,vcnl4020",
1100         .data = (void *)VCNL4010,
1101     },
1102     {
1103         .compatible = "vishay,vcnl4040",
1104         .data = (void *)VCNL4040,
1105     },
1106     {
1107         .compatible = "vishay,vcnl4200",
1108         .data = (void *)VCNL4200,
1109     },
1110     {},
1111 };
1112 MODULE_DEVICE_TABLE(of, vcnl_4000_of_match);
1113 
1114 static int vcnl4000_remove(struct i2c_client *client)
1115 {
1116     struct iio_dev *indio_dev = i2c_get_clientdata(client);
1117     struct vcnl4000_data *data = iio_priv(indio_dev);
1118     int ret;
1119 
1120     pm_runtime_dont_use_autosuspend(&client->dev);
1121     pm_runtime_disable(&client->dev);
1122     iio_device_unregister(indio_dev);
1123     pm_runtime_set_suspended(&client->dev);
1124 
1125     ret = data->chip_spec->set_power_state(data, false);
1126     if (ret)
1127         dev_warn(&client->dev, "Failed to power down (%pe)\n",
1128              ERR_PTR(ret));
1129 
1130     return 0;
1131 }
1132 
1133 static int vcnl4000_runtime_suspend(struct device *dev)
1134 {
1135     struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
1136     struct vcnl4000_data *data = iio_priv(indio_dev);
1137 
1138     return data->chip_spec->set_power_state(data, false);
1139 }
1140 
1141 static int vcnl4000_runtime_resume(struct device *dev)
1142 {
1143     struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
1144     struct vcnl4000_data *data = iio_priv(indio_dev);
1145 
1146     return data->chip_spec->set_power_state(data, true);
1147 }
1148 
1149 static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4000_pm_ops, vcnl4000_runtime_suspend,
1150                  vcnl4000_runtime_resume, NULL);
1151 
1152 static struct i2c_driver vcnl4000_driver = {
1153     .driver = {
1154         .name   = VCNL4000_DRV_NAME,
1155         .pm = pm_ptr(&vcnl4000_pm_ops),
1156         .of_match_table = vcnl_4000_of_match,
1157     },
1158     .probe  = vcnl4000_probe,
1159     .id_table = vcnl4000_id,
1160     .remove = vcnl4000_remove,
1161 };
1162 
1163 module_i2c_driver(vcnl4000_driver);
1164 
1165 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
1166 MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
1167 MODULE_DESCRIPTION("Vishay VCNL4000 proximity/ambient light sensor driver");
1168 MODULE_LICENSE("GPL");