cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vcnl4000.c (29077B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4040/4200 combined ambient
      4 * light and proximity sensor
      5 *
      6 * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
      7 * Copyright 2019 Pursim SPC
      8 * 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 current
     17 *   interrupts (VCNL4040, VCNL4200)
     18 */
     19
     20#include <linux/module.h>
     21#include <linux/i2c.h>
     22#include <linux/err.h>
     23#include <linux/delay.h>
     24#include <linux/pm_runtime.h>
     25#include <linux/interrupt.h>
     26
     27#include <linux/iio/buffer.h>
     28#include <linux/iio/events.h>
     29#include <linux/iio/iio.h>
     30#include <linux/iio/sysfs.h>
     31#include <linux/iio/trigger.h>
     32#include <linux/iio/trigger_consumer.h>
     33#include <linux/iio/triggered_buffer.h>
     34
     35#define VCNL4000_DRV_NAME "vcnl4000"
     36#define VCNL4000_PROD_ID	0x01
     37#define VCNL4010_PROD_ID	0x02 /* for VCNL4020, VCNL4010 */
     38#define VCNL4040_PROD_ID	0x86
     39#define VCNL4200_PROD_ID	0x58
     40
     41#define VCNL4000_COMMAND	0x80 /* Command register */
     42#define VCNL4000_PROD_REV	0x81 /* Product ID and Revision ID */
     43#define VCNL4010_PROX_RATE      0x82 /* Proximity rate */
     44#define VCNL4000_LED_CURRENT	0x83 /* IR LED current for proximity mode */
     45#define VCNL4000_AL_PARAM	0x84 /* Ambient light parameter register */
     46#define VCNL4010_ALS_PARAM      0x84 /* ALS rate */
     47#define VCNL4000_AL_RESULT_HI	0x85 /* Ambient light result register, MSB */
     48#define VCNL4000_AL_RESULT_LO	0x86 /* Ambient light result register, LSB */
     49#define VCNL4000_PS_RESULT_HI	0x87 /* Proximity result register, MSB */
     50#define VCNL4000_PS_RESULT_LO	0x88 /* Proximity result register, LSB */
     51#define VCNL4000_PS_MEAS_FREQ	0x89 /* Proximity test signal frequency */
     52#define VCNL4010_INT_CTRL	0x89 /* Interrupt control */
     53#define VCNL4000_PS_MOD_ADJ	0x8a /* Proximity modulator timing adjustment */
     54#define VCNL4010_LOW_THR_HI     0x8a /* Low threshold, MSB */
     55#define VCNL4010_LOW_THR_LO     0x8b /* Low threshold, LSB */
     56#define VCNL4010_HIGH_THR_HI    0x8c /* High threshold, MSB */
     57#define VCNL4010_HIGH_THR_LO    0x8d /* High threshold, LSB */
     58#define VCNL4010_ISR		0x8e /* Interrupt status */
     59
     60#define VCNL4200_AL_CONF	0x00 /* Ambient light configuration */
     61#define VCNL4200_PS_CONF1	0x03 /* Proximity configuration */
     62#define VCNL4200_PS_DATA	0x08 /* Proximity data */
     63#define VCNL4200_AL_DATA	0x09 /* Ambient light data */
     64#define VCNL4200_DEV_ID		0x0e /* Device ID, slave address and version */
     65
     66#define VCNL4040_DEV_ID		0x0c /* Device ID and version */
     67
     68/* Bit masks for COMMAND register */
     69#define VCNL4000_AL_RDY		BIT(6) /* ALS data ready? */
     70#define VCNL4000_PS_RDY		BIT(5) /* proximity data ready? */
     71#define VCNL4000_AL_OD		BIT(4) /* start on-demand ALS measurement */
     72#define VCNL4000_PS_OD		BIT(3) /* start on-demand proximity measurement */
     73#define VCNL4000_ALS_EN		BIT(2) /* start ALS measurement */
     74#define VCNL4000_PROX_EN	BIT(1) /* start proximity measurement */
     75#define VCNL4000_SELF_TIMED_EN	BIT(0) /* start self-timed measurement */
     76
     77/* Bit masks for interrupt registers. */
     78#define VCNL4010_INT_THR_SEL	BIT(0) /* Select threshold interrupt source */
     79#define VCNL4010_INT_THR_EN	BIT(1) /* Threshold interrupt type */
     80#define VCNL4010_INT_ALS_EN	BIT(2) /* Enable on ALS data ready */
     81#define VCNL4010_INT_PROX_EN	BIT(3) /* Enable on proximity data ready */
     82
     83#define VCNL4010_INT_THR_HIGH	0 /* High threshold exceeded */
     84#define VCNL4010_INT_THR_LOW	1 /* Low threshold exceeded */
     85#define VCNL4010_INT_ALS	2 /* ALS data ready */
     86#define VCNL4010_INT_PROXIMITY	3 /* Proximity data ready */
     87
     88#define VCNL4010_INT_THR \
     89	(BIT(VCNL4010_INT_THR_LOW) | BIT(VCNL4010_INT_THR_HIGH))
     90#define VCNL4010_INT_DRDY \
     91	(BIT(VCNL4010_INT_PROXIMITY) | BIT(VCNL4010_INT_ALS))
     92
     93static const int vcnl4010_prox_sampling_frequency[][2] = {
     94	{1, 950000},
     95	{3, 906250},
     96	{7, 812500},
     97	{16, 625000},
     98	{31, 250000},
     99	{62, 500000},
    100	{125, 0},
    101	{250, 0},
    102};
    103
    104#define VCNL4000_SLEEP_DELAY_MS	2000 /* before we enter pm_runtime_suspend */
    105
    106enum vcnl4000_device_ids {
    107	VCNL4000,
    108	VCNL4010,
    109	VCNL4040,
    110	VCNL4200,
    111};
    112
    113struct vcnl4200_channel {
    114	u8 reg;
    115	ktime_t last_measurement;
    116	ktime_t sampling_rate;
    117	struct mutex lock;
    118};
    119
    120struct vcnl4000_data {
    121	struct i2c_client *client;
    122	enum vcnl4000_device_ids id;
    123	int rev;
    124	int al_scale;
    125	const struct vcnl4000_chip_spec *chip_spec;
    126	struct mutex vcnl4000_lock;
    127	struct vcnl4200_channel vcnl4200_al;
    128	struct vcnl4200_channel vcnl4200_ps;
    129	uint32_t near_level;
    130};
    131
    132struct vcnl4000_chip_spec {
    133	const char *prod;
    134	struct iio_chan_spec const *channels;
    135	const int num_channels;
    136	const struct iio_info *info;
    137	bool irq_support;
    138	int (*init)(struct vcnl4000_data *data);
    139	int (*measure_light)(struct vcnl4000_data *data, int *val);
    140	int (*measure_proximity)(struct vcnl4000_data *data, int *val);
    141	int (*set_power_state)(struct vcnl4000_data *data, bool on);
    142};
    143
    144static const struct i2c_device_id vcnl4000_id[] = {
    145	{ "vcnl4000", VCNL4000 },
    146	{ "vcnl4010", VCNL4010 },
    147	{ "vcnl4020", VCNL4010 },
    148	{ "vcnl4040", VCNL4040 },
    149	{ "vcnl4200", VCNL4200 },
    150	{ }
    151};
    152MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
    153
    154static int vcnl4000_set_power_state(struct vcnl4000_data *data, bool on)
    155{
    156	/* no suspend op */
    157	return 0;
    158}
    159
    160static int vcnl4000_init(struct vcnl4000_data *data)
    161{
    162	int ret, prod_id;
    163
    164	ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
    165	if (ret < 0)
    166		return ret;
    167
    168	prod_id = ret >> 4;
    169	switch (prod_id) {
    170	case VCNL4000_PROD_ID:
    171		if (data->id != VCNL4000)
    172			dev_warn(&data->client->dev,
    173					"wrong device id, use vcnl4000");
    174		break;
    175	case VCNL4010_PROD_ID:
    176		if (data->id != VCNL4010)
    177			dev_warn(&data->client->dev,
    178					"wrong device id, use vcnl4010/4020");
    179		break;
    180	default:
    181		return -ENODEV;
    182	}
    183
    184	data->rev = ret & 0xf;
    185	data->al_scale = 250000;
    186	mutex_init(&data->vcnl4000_lock);
    187
    188	return data->chip_spec->set_power_state(data, true);
    189};
    190
    191static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
    192{
    193	u16 val = on ? 0 /* power on */ : 1 /* shut down */;
    194	int ret;
    195
    196	ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, val);
    197	if (ret < 0)
    198		return ret;
    199
    200	ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val);
    201	if (ret < 0)
    202		return ret;
    203
    204	if (on) {
    205		/* Wait at least one integration cycle before fetching data */
    206		data->vcnl4200_al.last_measurement = ktime_get();
    207		data->vcnl4200_ps.last_measurement = ktime_get();
    208	}
    209
    210	return 0;
    211}
    212
    213static int vcnl4200_init(struct vcnl4000_data *data)
    214{
    215	int ret, id;
    216
    217	ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
    218	if (ret < 0)
    219		return ret;
    220
    221	id = ret & 0xff;
    222
    223	if (id != VCNL4200_PROD_ID) {
    224		ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID);
    225		if (ret < 0)
    226			return ret;
    227
    228		id = ret & 0xff;
    229
    230		if (id != VCNL4040_PROD_ID)
    231			return -ENODEV;
    232	}
    233
    234	dev_dbg(&data->client->dev, "device id 0x%x", id);
    235
    236	data->rev = (ret >> 8) & 0xf;
    237
    238	data->vcnl4200_al.reg = VCNL4200_AL_DATA;
    239	data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
    240	switch (id) {
    241	case VCNL4200_PROD_ID:
    242		/* Default wait time is 50ms, add 20% tolerance. */
    243		data->vcnl4200_al.sampling_rate = ktime_set(0, 60000 * 1000);
    244		/* Default wait time is 4.8ms, add 20% tolerance. */
    245		data->vcnl4200_ps.sampling_rate = ktime_set(0, 5760 * 1000);
    246		data->al_scale = 24000;
    247		break;
    248	case VCNL4040_PROD_ID:
    249		/* Default wait time is 80ms, add 20% tolerance. */
    250		data->vcnl4200_al.sampling_rate = ktime_set(0, 96000 * 1000);
    251		/* Default wait time is 5ms, add 20% tolerance. */
    252		data->vcnl4200_ps.sampling_rate = ktime_set(0, 6000 * 1000);
    253		data->al_scale = 120000;
    254		break;
    255	}
    256	mutex_init(&data->vcnl4200_al.lock);
    257	mutex_init(&data->vcnl4200_ps.lock);
    258
    259	ret = data->chip_spec->set_power_state(data, true);
    260	if (ret < 0)
    261		return ret;
    262
    263	return 0;
    264};
    265
    266static int vcnl4000_read_data(struct vcnl4000_data *data, u8 data_reg, int *val)
    267{
    268	s32 ret;
    269
    270	ret = i2c_smbus_read_word_swapped(data->client, data_reg);
    271	if (ret < 0)
    272		return ret;
    273
    274	*val = ret;
    275	return 0;
    276}
    277
    278static int vcnl4000_write_data(struct vcnl4000_data *data, u8 data_reg, int val)
    279{
    280	if (val > U16_MAX)
    281		return -ERANGE;
    282
    283	return i2c_smbus_write_word_swapped(data->client, data_reg, val);
    284}
    285
    286
    287static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
    288				u8 rdy_mask, u8 data_reg, int *val)
    289{
    290	int tries = 20;
    291	int ret;
    292
    293	mutex_lock(&data->vcnl4000_lock);
    294
    295	ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
    296					req_mask);
    297	if (ret < 0)
    298		goto fail;
    299
    300	/* wait for data to become ready */
    301	while (tries--) {
    302		ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
    303		if (ret < 0)
    304			goto fail;
    305		if (ret & rdy_mask)
    306			break;
    307		msleep(20); /* measurement takes up to 100 ms */
    308	}
    309
    310	if (tries < 0) {
    311		dev_err(&data->client->dev,
    312			"vcnl4000_measure() failed, data not ready\n");
    313		ret = -EIO;
    314		goto fail;
    315	}
    316
    317	ret = vcnl4000_read_data(data, data_reg, val);
    318	if (ret < 0)
    319		goto fail;
    320
    321	mutex_unlock(&data->vcnl4000_lock);
    322
    323	return 0;
    324
    325fail:
    326	mutex_unlock(&data->vcnl4000_lock);
    327	return ret;
    328}
    329
    330static int vcnl4200_measure(struct vcnl4000_data *data,
    331		struct vcnl4200_channel *chan, int *val)
    332{
    333	int ret;
    334	s64 delta;
    335	ktime_t next_measurement;
    336
    337	mutex_lock(&chan->lock);
    338
    339	next_measurement = ktime_add(chan->last_measurement,
    340			chan->sampling_rate);
    341	delta = ktime_us_delta(next_measurement, ktime_get());
    342	if (delta > 0)
    343		usleep_range(delta, delta + 500);
    344	chan->last_measurement = ktime_get();
    345
    346	mutex_unlock(&chan->lock);
    347
    348	ret = i2c_smbus_read_word_data(data->client, chan->reg);
    349	if (ret < 0)
    350		return ret;
    351
    352	*val = ret;
    353
    354	return 0;
    355}
    356
    357static int vcnl4000_measure_light(struct vcnl4000_data *data, int *val)
    358{
    359	return vcnl4000_measure(data,
    360			VCNL4000_AL_OD, VCNL4000_AL_RDY,
    361			VCNL4000_AL_RESULT_HI, val);
    362}
    363
    364static int vcnl4200_measure_light(struct vcnl4000_data *data, int *val)
    365{
    366	return vcnl4200_measure(data, &data->vcnl4200_al, val);
    367}
    368
    369static int vcnl4000_measure_proximity(struct vcnl4000_data *data, int *val)
    370{
    371	return vcnl4000_measure(data,
    372			VCNL4000_PS_OD, VCNL4000_PS_RDY,
    373			VCNL4000_PS_RESULT_HI, val);
    374}
    375
    376static int vcnl4200_measure_proximity(struct vcnl4000_data *data, int *val)
    377{
    378	return vcnl4200_measure(data, &data->vcnl4200_ps, val);
    379}
    380
    381static int vcnl4010_read_proxy_samp_freq(struct vcnl4000_data *data, int *val,
    382					 int *val2)
    383{
    384	int ret;
    385
    386	ret = i2c_smbus_read_byte_data(data->client, VCNL4010_PROX_RATE);
    387	if (ret < 0)
    388		return ret;
    389
    390	if (ret >= ARRAY_SIZE(vcnl4010_prox_sampling_frequency))
    391		return -EINVAL;
    392
    393	*val = vcnl4010_prox_sampling_frequency[ret][0];
    394	*val2 = vcnl4010_prox_sampling_frequency[ret][1];
    395
    396	return 0;
    397}
    398
    399static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data)
    400{
    401	int ret;
    402
    403	ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
    404	if (ret < 0)
    405		return false;
    406
    407	return !!(ret & VCNL4000_SELF_TIMED_EN);
    408}
    409
    410static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
    411{
    412	struct device *dev = &data->client->dev;
    413	int ret;
    414
    415	if (on) {
    416		ret = pm_runtime_resume_and_get(dev);
    417	} else {
    418		pm_runtime_mark_last_busy(dev);
    419		ret = pm_runtime_put_autosuspend(dev);
    420	}
    421
    422	return ret;
    423}
    424
    425static int vcnl4000_read_raw(struct iio_dev *indio_dev,
    426				struct iio_chan_spec const *chan,
    427				int *val, int *val2, long mask)
    428{
    429	int ret;
    430	struct vcnl4000_data *data = iio_priv(indio_dev);
    431
    432	switch (mask) {
    433	case IIO_CHAN_INFO_RAW:
    434		ret = vcnl4000_set_pm_runtime_state(data, true);
    435		if  (ret < 0)
    436			return ret;
    437
    438		switch (chan->type) {
    439		case IIO_LIGHT:
    440			ret = data->chip_spec->measure_light(data, val);
    441			if (!ret)
    442				ret = IIO_VAL_INT;
    443			break;
    444		case IIO_PROXIMITY:
    445			ret = data->chip_spec->measure_proximity(data, val);
    446			if (!ret)
    447				ret = IIO_VAL_INT;
    448			break;
    449		default:
    450			ret = -EINVAL;
    451		}
    452		vcnl4000_set_pm_runtime_state(data, false);
    453		return ret;
    454	case IIO_CHAN_INFO_SCALE:
    455		if (chan->type != IIO_LIGHT)
    456			return -EINVAL;
    457
    458		*val = 0;
    459		*val2 = data->al_scale;
    460		return IIO_VAL_INT_PLUS_MICRO;
    461	default:
    462		return -EINVAL;
    463	}
    464}
    465
    466static int vcnl4010_read_raw(struct iio_dev *indio_dev,
    467			     struct iio_chan_spec const *chan,
    468			     int *val, int *val2, long mask)
    469{
    470	int ret;
    471	struct vcnl4000_data *data = iio_priv(indio_dev);
    472
    473	switch (mask) {
    474	case IIO_CHAN_INFO_RAW:
    475	case IIO_CHAN_INFO_SCALE:
    476		ret = iio_device_claim_direct_mode(indio_dev);
    477		if (ret)
    478			return ret;
    479
    480		/* Protect against event capture. */
    481		if (vcnl4010_is_in_periodic_mode(data)) {
    482			ret = -EBUSY;
    483		} else {
    484			ret = vcnl4000_read_raw(indio_dev, chan, val, val2,
    485						mask);
    486		}
    487
    488		iio_device_release_direct_mode(indio_dev);
    489		return ret;
    490	case IIO_CHAN_INFO_SAMP_FREQ:
    491		switch (chan->type) {
    492		case IIO_PROXIMITY:
    493			ret = vcnl4010_read_proxy_samp_freq(data, val, val2);
    494			if (ret < 0)
    495				return ret;
    496			return IIO_VAL_INT_PLUS_MICRO;
    497		default:
    498			return -EINVAL;
    499		}
    500	default:
    501		return -EINVAL;
    502	}
    503}
    504
    505static int vcnl4010_read_avail(struct iio_dev *indio_dev,
    506			       struct iio_chan_spec const *chan,
    507			       const int **vals, int *type, int *length,
    508			       long mask)
    509{
    510	switch (mask) {
    511	case IIO_CHAN_INFO_SAMP_FREQ:
    512		*vals = (int *)vcnl4010_prox_sampling_frequency;
    513		*type = IIO_VAL_INT_PLUS_MICRO;
    514		*length = 2 * ARRAY_SIZE(vcnl4010_prox_sampling_frequency);
    515		return IIO_AVAIL_LIST;
    516	default:
    517		return -EINVAL;
    518	}
    519}
    520
    521static int vcnl4010_write_proxy_samp_freq(struct vcnl4000_data *data, int val,
    522					  int val2)
    523{
    524	unsigned int i;
    525	int index = -1;
    526
    527	for (i = 0; i < ARRAY_SIZE(vcnl4010_prox_sampling_frequency); i++) {
    528		if (val == vcnl4010_prox_sampling_frequency[i][0] &&
    529		    val2 == vcnl4010_prox_sampling_frequency[i][1]) {
    530			index = i;
    531			break;
    532		}
    533	}
    534
    535	if (index < 0)
    536		return -EINVAL;
    537
    538	return i2c_smbus_write_byte_data(data->client, VCNL4010_PROX_RATE,
    539					 index);
    540}
    541
    542static int vcnl4010_write_raw(struct iio_dev *indio_dev,
    543			      struct iio_chan_spec const *chan,
    544			      int val, int val2, long mask)
    545{
    546	int ret;
    547	struct vcnl4000_data *data = iio_priv(indio_dev);
    548
    549	ret = iio_device_claim_direct_mode(indio_dev);
    550	if (ret)
    551		return ret;
    552
    553	/* Protect against event capture. */
    554	if (vcnl4010_is_in_periodic_mode(data)) {
    555		ret = -EBUSY;
    556		goto end;
    557	}
    558
    559	switch (mask) {
    560	case IIO_CHAN_INFO_SAMP_FREQ:
    561		switch (chan->type) {
    562		case IIO_PROXIMITY:
    563			ret = vcnl4010_write_proxy_samp_freq(data, val, val2);
    564			goto end;
    565		default:
    566			ret = -EINVAL;
    567			goto end;
    568		}
    569	default:
    570		ret = -EINVAL;
    571		goto end;
    572	}
    573
    574end:
    575	iio_device_release_direct_mode(indio_dev);
    576	return ret;
    577}
    578
    579static int vcnl4010_read_event(struct iio_dev *indio_dev,
    580			       const struct iio_chan_spec *chan,
    581			       enum iio_event_type type,
    582			       enum iio_event_direction dir,
    583			       enum iio_event_info info,
    584			       int *val, int *val2)
    585{
    586	int ret;
    587	struct vcnl4000_data *data = iio_priv(indio_dev);
    588
    589	switch (info) {
    590	case IIO_EV_INFO_VALUE:
    591		switch (dir) {
    592		case IIO_EV_DIR_RISING:
    593			ret = vcnl4000_read_data(data, VCNL4010_HIGH_THR_HI,
    594						 val);
    595			if (ret < 0)
    596				return ret;
    597			return IIO_VAL_INT;
    598		case IIO_EV_DIR_FALLING:
    599			ret = vcnl4000_read_data(data, VCNL4010_LOW_THR_HI,
    600						 val);
    601			if (ret < 0)
    602				return ret;
    603			return IIO_VAL_INT;
    604		default:
    605			return -EINVAL;
    606		}
    607	default:
    608		return -EINVAL;
    609	}
    610}
    611
    612static int vcnl4010_write_event(struct iio_dev *indio_dev,
    613				const struct iio_chan_spec *chan,
    614				enum iio_event_type type,
    615				enum iio_event_direction dir,
    616				enum iio_event_info info,
    617				int val, int val2)
    618{
    619	int ret;
    620	struct vcnl4000_data *data = iio_priv(indio_dev);
    621
    622	switch (info) {
    623	case IIO_EV_INFO_VALUE:
    624		switch (dir) {
    625		case IIO_EV_DIR_RISING:
    626			ret = vcnl4000_write_data(data, VCNL4010_HIGH_THR_HI,
    627						  val);
    628			if (ret < 0)
    629				return ret;
    630			return IIO_VAL_INT;
    631		case IIO_EV_DIR_FALLING:
    632			ret = vcnl4000_write_data(data, VCNL4010_LOW_THR_HI,
    633						  val);
    634			if (ret < 0)
    635				return ret;
    636			return IIO_VAL_INT;
    637		default:
    638			return -EINVAL;
    639		}
    640	default:
    641		return -EINVAL;
    642	}
    643}
    644
    645static bool vcnl4010_is_thr_enabled(struct vcnl4000_data *data)
    646{
    647	int ret;
    648
    649	ret = i2c_smbus_read_byte_data(data->client, VCNL4010_INT_CTRL);
    650	if (ret < 0)
    651		return false;
    652
    653	return !!(ret & VCNL4010_INT_THR_EN);
    654}
    655
    656static int vcnl4010_read_event_config(struct iio_dev *indio_dev,
    657				      const struct iio_chan_spec *chan,
    658				      enum iio_event_type type,
    659				      enum iio_event_direction dir)
    660{
    661	struct vcnl4000_data *data = iio_priv(indio_dev);
    662
    663	switch (chan->type) {
    664	case IIO_PROXIMITY:
    665		return vcnl4010_is_thr_enabled(data);
    666	default:
    667		return -EINVAL;
    668	}
    669}
    670
    671static int vcnl4010_config_threshold(struct iio_dev *indio_dev, bool state)
    672{
    673	struct vcnl4000_data *data = iio_priv(indio_dev);
    674	int ret;
    675	int icr;
    676	int command;
    677
    678	if (state) {
    679		ret = iio_device_claim_direct_mode(indio_dev);
    680		if (ret)
    681			return ret;
    682
    683		/* Enable periodic measurement of proximity data. */
    684		command = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
    685
    686		/*
    687		 * Enable interrupts on threshold, for proximity data by
    688		 * default.
    689		 */
    690		icr = VCNL4010_INT_THR_EN;
    691	} else {
    692		if (!vcnl4010_is_thr_enabled(data))
    693			return 0;
    694
    695		command = 0;
    696		icr = 0;
    697	}
    698
    699	ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
    700					command);
    701	if (ret < 0)
    702		goto end;
    703
    704	ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, icr);
    705
    706end:
    707	if (state)
    708		iio_device_release_direct_mode(indio_dev);
    709
    710	return ret;
    711}
    712
    713static int vcnl4010_write_event_config(struct iio_dev *indio_dev,
    714				       const struct iio_chan_spec *chan,
    715				       enum iio_event_type type,
    716				       enum iio_event_direction dir,
    717				       int state)
    718{
    719	switch (chan->type) {
    720	case IIO_PROXIMITY:
    721		return vcnl4010_config_threshold(indio_dev, state);
    722	default:
    723		return -EINVAL;
    724	}
    725}
    726
    727static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,
    728					uintptr_t priv,
    729					const struct iio_chan_spec *chan,
    730					char *buf)
    731{
    732	struct vcnl4000_data *data = iio_priv(indio_dev);
    733
    734	return sprintf(buf, "%u\n", data->near_level);
    735}
    736
    737static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = {
    738	{
    739		.name = "nearlevel",
    740		.shared = IIO_SEPARATE,
    741		.read = vcnl4000_read_near_level,
    742	},
    743	{ /* sentinel */ }
    744};
    745
    746static const struct iio_event_spec vcnl4000_event_spec[] = {
    747	{
    748		.type = IIO_EV_TYPE_THRESH,
    749		.dir = IIO_EV_DIR_RISING,
    750		.mask_separate = BIT(IIO_EV_INFO_VALUE),
    751	}, {
    752		.type = IIO_EV_TYPE_THRESH,
    753		.dir = IIO_EV_DIR_FALLING,
    754		.mask_separate = BIT(IIO_EV_INFO_VALUE),
    755	}, {
    756		.type = IIO_EV_TYPE_THRESH,
    757		.dir = IIO_EV_DIR_EITHER,
    758		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
    759	}
    760};
    761
    762static const struct iio_chan_spec vcnl4000_channels[] = {
    763	{
    764		.type = IIO_LIGHT,
    765		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
    766			BIT(IIO_CHAN_INFO_SCALE),
    767	}, {
    768		.type = IIO_PROXIMITY,
    769		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
    770		.ext_info = vcnl4000_ext_info,
    771	}
    772};
    773
    774static const struct iio_chan_spec vcnl4010_channels[] = {
    775	{
    776		.type = IIO_LIGHT,
    777		.scan_index = -1,
    778		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
    779			BIT(IIO_CHAN_INFO_SCALE),
    780	}, {
    781		.type = IIO_PROXIMITY,
    782		.scan_index = 0,
    783		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
    784			BIT(IIO_CHAN_INFO_SAMP_FREQ),
    785		.info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
    786		.event_spec = vcnl4000_event_spec,
    787		.num_event_specs = ARRAY_SIZE(vcnl4000_event_spec),
    788		.ext_info = vcnl4000_ext_info,
    789		.scan_type = {
    790			.sign = 'u',
    791			.realbits = 16,
    792			.storagebits = 16,
    793			.endianness = IIO_CPU,
    794		},
    795	},
    796	IIO_CHAN_SOFT_TIMESTAMP(1),
    797};
    798
    799static const struct iio_info vcnl4000_info = {
    800	.read_raw = vcnl4000_read_raw,
    801};
    802
    803static const struct iio_info vcnl4010_info = {
    804	.read_raw = vcnl4010_read_raw,
    805	.read_avail = vcnl4010_read_avail,
    806	.write_raw = vcnl4010_write_raw,
    807	.read_event_value = vcnl4010_read_event,
    808	.write_event_value = vcnl4010_write_event,
    809	.read_event_config = vcnl4010_read_event_config,
    810	.write_event_config = vcnl4010_write_event_config,
    811};
    812
    813static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
    814	[VCNL4000] = {
    815		.prod = "VCNL4000",
    816		.init = vcnl4000_init,
    817		.measure_light = vcnl4000_measure_light,
    818		.measure_proximity = vcnl4000_measure_proximity,
    819		.set_power_state = vcnl4000_set_power_state,
    820		.channels = vcnl4000_channels,
    821		.num_channels = ARRAY_SIZE(vcnl4000_channels),
    822		.info = &vcnl4000_info,
    823		.irq_support = false,
    824	},
    825	[VCNL4010] = {
    826		.prod = "VCNL4010/4020",
    827		.init = vcnl4000_init,
    828		.measure_light = vcnl4000_measure_light,
    829		.measure_proximity = vcnl4000_measure_proximity,
    830		.set_power_state = vcnl4000_set_power_state,
    831		.channels = vcnl4010_channels,
    832		.num_channels = ARRAY_SIZE(vcnl4010_channels),
    833		.info = &vcnl4010_info,
    834		.irq_support = true,
    835	},
    836	[VCNL4040] = {
    837		.prod = "VCNL4040",
    838		.init = vcnl4200_init,
    839		.measure_light = vcnl4200_measure_light,
    840		.measure_proximity = vcnl4200_measure_proximity,
    841		.set_power_state = vcnl4200_set_power_state,
    842		.channels = vcnl4000_channels,
    843		.num_channels = ARRAY_SIZE(vcnl4000_channels),
    844		.info = &vcnl4000_info,
    845		.irq_support = false,
    846	},
    847	[VCNL4200] = {
    848		.prod = "VCNL4200",
    849		.init = vcnl4200_init,
    850		.measure_light = vcnl4200_measure_light,
    851		.measure_proximity = vcnl4200_measure_proximity,
    852		.set_power_state = vcnl4200_set_power_state,
    853		.channels = vcnl4000_channels,
    854		.num_channels = ARRAY_SIZE(vcnl4000_channels),
    855		.info = &vcnl4000_info,
    856		.irq_support = false,
    857	},
    858};
    859
    860static irqreturn_t vcnl4010_irq_thread(int irq, void *p)
    861{
    862	struct iio_dev *indio_dev = p;
    863	struct vcnl4000_data *data = iio_priv(indio_dev);
    864	unsigned long isr;
    865	int ret;
    866
    867	ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
    868	if (ret < 0)
    869		goto end;
    870
    871	isr = ret;
    872
    873	if (isr & VCNL4010_INT_THR) {
    874		if (test_bit(VCNL4010_INT_THR_LOW, &isr)) {
    875			iio_push_event(indio_dev,
    876				       IIO_UNMOD_EVENT_CODE(
    877					       IIO_PROXIMITY,
    878					       1,
    879					       IIO_EV_TYPE_THRESH,
    880					       IIO_EV_DIR_FALLING),
    881				       iio_get_time_ns(indio_dev));
    882		}
    883
    884		if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) {
    885			iio_push_event(indio_dev,
    886				       IIO_UNMOD_EVENT_CODE(
    887					       IIO_PROXIMITY,
    888					       1,
    889					       IIO_EV_TYPE_THRESH,
    890					       IIO_EV_DIR_RISING),
    891				       iio_get_time_ns(indio_dev));
    892		}
    893
    894		i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
    895					  isr & VCNL4010_INT_THR);
    896	}
    897
    898	if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev))
    899		iio_trigger_poll_chained(indio_dev->trig);
    900
    901end:
    902	return IRQ_HANDLED;
    903}
    904
    905static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)
    906{
    907	struct iio_poll_func *pf = p;
    908	struct iio_dev *indio_dev = pf->indio_dev;
    909	struct vcnl4000_data *data = iio_priv(indio_dev);
    910	const unsigned long *active_scan_mask = indio_dev->active_scan_mask;
    911	u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */
    912	bool data_read = false;
    913	unsigned long isr;
    914	int val = 0;
    915	int ret;
    916
    917	ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
    918	if (ret < 0)
    919		goto end;
    920
    921	isr = ret;
    922
    923	if (test_bit(0, active_scan_mask)) {
    924		if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) {
    925			ret = vcnl4000_read_data(data,
    926						 VCNL4000_PS_RESULT_HI,
    927						 &val);
    928			if (ret < 0)
    929				goto end;
    930
    931			buffer[0] = val;
    932			data_read = true;
    933		}
    934	}
    935
    936	ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
    937					isr & VCNL4010_INT_DRDY);
    938	if (ret < 0)
    939		goto end;
    940
    941	if (!data_read)
    942		goto end;
    943
    944	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
    945					   iio_get_time_ns(indio_dev));
    946
    947end:
    948	iio_trigger_notify_done(indio_dev->trig);
    949	return IRQ_HANDLED;
    950}
    951
    952static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev)
    953{
    954	struct vcnl4000_data *data = iio_priv(indio_dev);
    955	int ret;
    956	int cmd;
    957
    958	/* Do not enable the buffer if we are already capturing events. */
    959	if (vcnl4010_is_in_periodic_mode(data))
    960		return -EBUSY;
    961
    962	ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL,
    963					VCNL4010_INT_PROX_EN);
    964	if (ret < 0)
    965		return ret;
    966
    967	cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
    968	return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd);
    969}
    970
    971static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev)
    972{
    973	struct vcnl4000_data *data = iio_priv(indio_dev);
    974	int ret;
    975
    976	ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0);
    977	if (ret < 0)
    978		return ret;
    979
    980	return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0);
    981}
    982
    983static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = {
    984	.postenable = &vcnl4010_buffer_postenable,
    985	.predisable = &vcnl4010_buffer_predisable,
    986};
    987
    988static const struct iio_trigger_ops vcnl4010_trigger_ops = {
    989	.validate_device = iio_trigger_validate_own_device,
    990};
    991
    992static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)
    993{
    994	struct vcnl4000_data *data = iio_priv(indio_dev);
    995	struct i2c_client *client = data->client;
    996	struct iio_trigger *trigger;
    997
    998	trigger = devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
    999					 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
   1010static 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;
   1084fail_poweroff:
   1085	data->chip_spec->set_power_state(data, false);
   1086	return ret;
   1087}
   1088
   1089static 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};
   1112MODULE_DEVICE_TABLE(of, vcnl_4000_of_match);
   1113
   1114static 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
   1119	pm_runtime_dont_use_autosuspend(&client->dev);
   1120	pm_runtime_disable(&client->dev);
   1121	iio_device_unregister(indio_dev);
   1122	pm_runtime_set_suspended(&client->dev);
   1123
   1124	return data->chip_spec->set_power_state(data, false);
   1125}
   1126
   1127static int __maybe_unused vcnl4000_runtime_suspend(struct device *dev)
   1128{
   1129	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
   1130	struct vcnl4000_data *data = iio_priv(indio_dev);
   1131
   1132	return data->chip_spec->set_power_state(data, false);
   1133}
   1134
   1135static int __maybe_unused vcnl4000_runtime_resume(struct device *dev)
   1136{
   1137	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
   1138	struct vcnl4000_data *data = iio_priv(indio_dev);
   1139
   1140	return data->chip_spec->set_power_state(data, true);
   1141}
   1142
   1143static const struct dev_pm_ops vcnl4000_pm_ops = {
   1144	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
   1145				pm_runtime_force_resume)
   1146	SET_RUNTIME_PM_OPS(vcnl4000_runtime_suspend,
   1147			   vcnl4000_runtime_resume, NULL)
   1148};
   1149
   1150static struct i2c_driver vcnl4000_driver = {
   1151	.driver = {
   1152		.name   = VCNL4000_DRV_NAME,
   1153		.pm	= &vcnl4000_pm_ops,
   1154		.of_match_table = vcnl_4000_of_match,
   1155	},
   1156	.probe  = vcnl4000_probe,
   1157	.id_table = vcnl4000_id,
   1158	.remove	= vcnl4000_remove,
   1159};
   1160
   1161module_i2c_driver(vcnl4000_driver);
   1162
   1163MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
   1164MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
   1165MODULE_DESCRIPTION("Vishay VCNL4000 proximity/ambient light sensor driver");
   1166MODULE_LICENSE("GPL");