linux/drivers/iio/light/vcnl4000.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4040/4200 combined ambient
 * light and proximity sensor
 *
 * Copyright 2012 Peter Meerwald <[email protected]>
 * Copyright 2019 Pursim SPC
 * Copyright 2020 Mathieu Othacehe <[email protected]>
 *
 * IIO driver for:
 *   VCNL4000/10/20 (7-bit I2C slave address 0x13)
 *   VCNL4040 (7-bit I2C slave address 0x60)
 *   VCNL4200 (7-bit I2C slave address 0x51)
 *
 * TODO:
 *   allow to adjust IR current
 *   interrupts (VCNL4040, VCNL4200)
 */

#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
#include <linux/units.h>

#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>

#define VCNL4000_DRV_NAME
#define VCNL4000_PROD_ID
#define VCNL4010_PROD_ID
#define VCNL4040_PROD_ID
#define VCNL4200_PROD_ID

#define VCNL4000_COMMAND
#define VCNL4000_PROD_REV
#define VCNL4010_PROX_RATE
#define VCNL4000_LED_CURRENT
#define VCNL4000_AL_PARAM
#define VCNL4010_ALS_PARAM
#define VCNL4000_AL_RESULT_HI
#define VCNL4000_AL_RESULT_LO
#define VCNL4000_PS_RESULT_HI
#define VCNL4000_PS_RESULT_LO
#define VCNL4000_PS_MEAS_FREQ
#define VCNL4010_INT_CTRL
#define VCNL4000_PS_MOD_ADJ
#define VCNL4010_LOW_THR_HI
#define VCNL4010_LOW_THR_LO
#define VCNL4010_HIGH_THR_HI
#define VCNL4010_HIGH_THR_LO
#define VCNL4010_ISR

#define VCNL4200_AL_CONF
#define VCNL4200_PS_CONF1
#define VCNL4200_PS_CONF3
#define VCNL4040_PS_THDL_LM
#define VCNL4040_PS_THDH_LM
#define VCNL4040_ALS_THDL_LM
#define VCNL4040_ALS_THDH_LM
#define VCNL4200_PS_DATA
#define VCNL4200_AL_DATA
#define VCNL4040_INT_FLAGS
#define VCNL4200_INT_FLAGS
#define VCNL4200_DEV_ID

#define VCNL4040_DEV_ID

/* Bit masks for COMMAND register */
#define VCNL4000_AL_RDY
#define VCNL4000_PS_RDY
#define VCNL4000_AL_OD
#define VCNL4000_PS_OD
#define VCNL4000_ALS_EN
#define VCNL4000_PROX_EN
#define VCNL4000_SELF_TIMED_EN

#define VCNL4040_ALS_CONF_ALS_SHUTDOWN
#define VCNL4040_ALS_CONF_IT
#define VCNL4040_ALS_CONF_INT_EN
#define VCNL4040_ALS_CONF_PERS
#define VCNL4040_PS_CONF1_PS_SHUTDOWN
#define VCNL4040_PS_CONF2_PS_IT
#define VCNL4040_CONF1_PS_PERS
#define VCNL4040_PS_CONF2_PS_HD
#define VCNL4040_PS_CONF2_PS_INT
#define VCNL4040_PS_CONF3_MPS
#define VCNL4040_PS_MS_LED_I
#define VCNL4040_PS_IF_AWAY
#define VCNL4040_PS_IF_CLOSE
#define VCNL4040_ALS_RISING
#define VCNL4040_ALS_FALLING

/* Bit masks for interrupt registers. */
#define VCNL4010_INT_THR_SEL
#define VCNL4010_INT_THR_EN
#define VCNL4010_INT_ALS_EN
#define VCNL4010_INT_PROX_EN

#define VCNL4010_INT_THR_HIGH
#define VCNL4010_INT_THR_LOW
#define VCNL4010_INT_ALS
#define VCNL4010_INT_PROXIMITY

#define VCNL4010_INT_THR
#define VCNL4010_INT_DRDY

#define VCNL4040_CONF3_PS_MPS_16BITS
#define VCNL4040_CONF3_PS_LED_I_16BITS

#define VCNL4040_CONF3_PS_SAMPLE_16BITS

static const int vcnl4010_prox_sampling_frequency[][2] =;

static const int vcnl4040_ps_it_times[][2] =;

static const int vcnl4200_ps_it_times[][2] =;

static const int vcnl4040_als_it_times[][2] =;

static const int vcnl4200_als_it_times[][2] =;

static const int vcnl4040_ps_calibbias_ua[][2] =;

static const int vcnl4040_als_persistence[] =;
static const int vcnl4040_ps_persistence[] =;
static const int vcnl4040_ps_oversampling_ratio[] =;

#define VCNL4000_SLEEP_DELAY_MS

enum vcnl4000_device_ids {};

struct vcnl4200_channel {};

struct vcnl4000_data {};

struct vcnl4000_chip_spec {};

static const struct i2c_device_id vcnl4000_id[] =;
MODULE_DEVICE_TABLE(i2c, vcnl4000_id);

static int vcnl4000_set_power_state(struct vcnl4000_data *data, bool on)
{}

static int vcnl4000_init(struct vcnl4000_data *data)
{
	int ret, prod_id;

	ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
	if (ret < 0)
		return ret;

	prod_id = ret >> 4;
	switch (prod_id) {
	case VCNL4000_PROD_ID:
		if (data->id != VCNL4000)
			dev_warn(&data->client->dev,
					"wrong device id, use vcnl4000");
		break;
	case VCNL4010_PROD_ID:
		if (data->id != VCNL4010)
			dev_warn(&data->client->dev,
					"wrong device id, use vcnl4010/4020");
		break;
	default:
		return -ENODEV;
	}

	data->rev = ret & 0xf;
	data->al_scale = 250000;

	return data->chip_spec->set_power_state(data, true);
};

static ssize_t vcnl4000_write_als_enable(struct vcnl4000_data *data, bool en)
{}

static ssize_t vcnl4000_write_ps_enable(struct vcnl4000_data *data, bool en)
{}

static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
{}

static int vcnl4200_init(struct vcnl4000_data *data)
{
	int ret, id;
	u16 regval;

	ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
	if (ret < 0)
		return ret;

	id = ret & 0xff;

	if (id != VCNL4200_PROD_ID) {
		ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID);
		if (ret < 0)
			return ret;

		id = ret & 0xff;

		if (id != VCNL4040_PROD_ID)
			return -ENODEV;
	}

	dev_dbg(&data->client->dev, "device id 0x%x", id);

	data->rev = (ret >> 8) & 0xf;
	data->ps_int = 0;
	data->als_int = 0;

	data->vcnl4200_al.reg = VCNL4200_AL_DATA;
	data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
	switch (id) {
	case VCNL4200_PROD_ID:
		/* Default wait time is 50ms, add 20% tolerance. */
		data->vcnl4200_al.sampling_rate = ktime_set(0, 60000 * 1000);
		/* Default wait time is 4.8ms, add 20% tolerance. */
		data->vcnl4200_ps.sampling_rate = ktime_set(0, 5760 * 1000);
		break;
	case VCNL4040_PROD_ID:
		/* Default wait time is 80ms, add 20% tolerance. */
		data->vcnl4200_al.sampling_rate = ktime_set(0, 96000 * 1000);
		/* Default wait time is 5ms, add 20% tolerance. */
		data->vcnl4200_ps.sampling_rate = ktime_set(0, 6000 * 1000);
		break;
	}
	data->al_scale = data->chip_spec->ulux_step;
	data->ps_scale = 16;
	mutex_init(&data->vcnl4200_al.lock);
	mutex_init(&data->vcnl4200_ps.lock);

	/* Use 16 bits proximity sensor readings */
	ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
	if (ret < 0)
		return ret;

	regval = ret | VCNL4040_PS_CONF2_PS_HD;
	ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
					regval);
	if (ret < 0)
		return ret;

	/* Align proximity sensor sample rate to 16 bits data width */
	ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
	if (ret < 0)
		return ret;

	regval = ret | VCNL4040_CONF3_PS_SAMPLE_16BITS;
	ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,
					regval);
	if (ret < 0)
		return ret;

	ret = data->chip_spec->set_power_state(data, true);
	if (ret < 0)
		return ret;

	return 0;
};

static int vcnl4000_read_data(struct vcnl4000_data *data, u8 data_reg, int *val)
{}

static int vcnl4000_write_data(struct vcnl4000_data *data, u8 data_reg, int val)
{}


static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
				u8 rdy_mask, u8 data_reg, int *val)
{}

static int vcnl4200_measure(struct vcnl4000_data *data,
		struct vcnl4200_channel *chan, int *val)
{}

static int vcnl4000_measure_light(struct vcnl4000_data *data, int *val)
{}

static int vcnl4200_measure_light(struct vcnl4000_data *data, int *val)
{}

static int vcnl4000_measure_proximity(struct vcnl4000_data *data, int *val)
{}

static int vcnl4200_measure_proximity(struct vcnl4000_data *data, int *val)
{}

static int vcnl4010_read_proxy_samp_freq(struct vcnl4000_data *data, int *val,
					 int *val2)
{}

static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data)
{}

static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
{}

static int vcnl4040_read_als_it(struct vcnl4000_data *data, int *val, int *val2)
{}

static ssize_t vcnl4040_write_als_it(struct vcnl4000_data *data, int val)
{}

static int vcnl4040_read_ps_it(struct vcnl4000_data *data, int *val, int *val2)
{}

static ssize_t vcnl4040_write_ps_it(struct vcnl4000_data *data, int val)
{}

static ssize_t vcnl4040_read_als_period(struct vcnl4000_data *data, int *val, int *val2)
{}

static ssize_t vcnl4040_write_als_period(struct vcnl4000_data *data, int val, int val2)
{}

static ssize_t vcnl4040_read_ps_period(struct vcnl4000_data *data, int *val, int *val2)
{}

static ssize_t vcnl4040_write_ps_period(struct vcnl4000_data *data, int val, int val2)
{}

static ssize_t vcnl4040_read_ps_oversampling_ratio(struct vcnl4000_data *data, int *val)
{}

static ssize_t vcnl4040_write_ps_oversampling_ratio(struct vcnl4000_data *data, int val)
{}

static ssize_t vcnl4040_read_ps_calibbias(struct vcnl4000_data *data, int *val, int *val2)
{}

static ssize_t vcnl4040_write_ps_calibbias(struct vcnl4000_data *data, int val)
{}

static int vcnl4000_read_raw(struct iio_dev *indio_dev,
				struct iio_chan_spec const *chan,
				int *val, int *val2, long mask)
{}

static int vcnl4040_write_raw(struct iio_dev *indio_dev,
			      struct iio_chan_spec const *chan,
			      int val, int val2, long mask)
{}

static int vcnl4040_read_avail(struct iio_dev *indio_dev,
			       struct iio_chan_spec const *chan,
			       const int **vals, int *type, int *length,
			       long mask)
{}

static int vcnl4010_read_raw(struct iio_dev *indio_dev,
			     struct iio_chan_spec const *chan,
			     int *val, int *val2, long mask)
{}

static int vcnl4010_read_avail(struct iio_dev *indio_dev,
			       struct iio_chan_spec const *chan,
			       const int **vals, int *type, int *length,
			       long mask)
{}

static int vcnl4010_write_proxy_samp_freq(struct vcnl4000_data *data, int val,
					  int val2)
{}

static int vcnl4010_write_raw(struct iio_dev *indio_dev,
			      struct iio_chan_spec const *chan,
			      int val, int val2, long mask)
{}

static int vcnl4010_read_event(struct iio_dev *indio_dev,
			       const struct iio_chan_spec *chan,
			       enum iio_event_type type,
			       enum iio_event_direction dir,
			       enum iio_event_info info,
			       int *val, int *val2)
{}

static int vcnl4010_write_event(struct iio_dev *indio_dev,
				const struct iio_chan_spec *chan,
				enum iio_event_type type,
				enum iio_event_direction dir,
				enum iio_event_info info,
				int val, int val2)
{}

static int vcnl4040_read_event(struct iio_dev *indio_dev,
			       const struct iio_chan_spec *chan,
			       enum iio_event_type type,
			       enum iio_event_direction dir,
			       enum iio_event_info info,
			       int *val, int *val2)
{}

static int vcnl4040_write_event(struct iio_dev *indio_dev,
				const struct iio_chan_spec *chan,
				enum iio_event_type type,
				enum iio_event_direction dir,
				enum iio_event_info info,
				int val, int val2)
{}

static bool vcnl4010_is_thr_enabled(struct vcnl4000_data *data)
{}

static int vcnl4010_read_event_config(struct iio_dev *indio_dev,
				      const struct iio_chan_spec *chan,
				      enum iio_event_type type,
				      enum iio_event_direction dir)
{}

static int vcnl4010_config_threshold(struct iio_dev *indio_dev, bool state)
{}

static int vcnl4010_write_event_config(struct iio_dev *indio_dev,
				       const struct iio_chan_spec *chan,
				       enum iio_event_type type,
				       enum iio_event_direction dir,
				       int state)
{}

static int vcnl4040_read_event_config(struct iio_dev *indio_dev,
				      const struct iio_chan_spec *chan,
				      enum iio_event_type type,
				      enum iio_event_direction dir)
{}

static int vcnl4040_write_event_config(struct iio_dev *indio_dev,
				       const struct iio_chan_spec *chan,
				       enum iio_event_type type,
				       enum iio_event_direction dir, int state)
{}

static irqreturn_t vcnl4040_irq_thread(int irq, void *p)
{}

static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,
					uintptr_t priv,
					const struct iio_chan_spec *chan,
					char *buf)
{}

static irqreturn_t vcnl4010_irq_thread(int irq, void *p)
{}

static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)
{}

static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev)
{}

static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev)
{}

static const struct iio_buffer_setup_ops vcnl4010_buffer_ops =;

static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] =;

static const struct iio_event_spec vcnl4000_event_spec[] =;

static const struct iio_event_spec vcnl4040_als_event_spec[] =;

static const struct iio_event_spec vcnl4040_event_spec[] =;

static const struct iio_chan_spec vcnl4000_channels[] =;

static const struct iio_chan_spec vcnl4010_channels[] =;

static const struct iio_chan_spec vcnl4040_channels[] =;

static const struct iio_info vcnl4000_info =;

static const struct iio_info vcnl4010_info =;

static const struct iio_info vcnl4040_info =;

static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] =;

static const struct iio_trigger_ops vcnl4010_trigger_ops =;

static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)
{}

static int vcnl4000_probe(struct i2c_client *client)
{}

static const struct of_device_id vcnl_4000_of_match[] =;
MODULE_DEVICE_TABLE(of, vcnl_4000_of_match);

static void vcnl4000_remove(struct i2c_client *client)
{}

static int vcnl4000_runtime_suspend(struct device *dev)
{}

static int vcnl4000_runtime_resume(struct device *dev)
{}

static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4000_pm_ops, vcnl4000_runtime_suspend,
				 vcnl4000_runtime_resume, NULL);

static struct i2c_driver vcnl4000_driver =;

module_i2c_driver();

MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();