linux/drivers/iio/light/apds9960.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * apds9960.c - Support for Avago APDS9960 gesture/RGB/ALS/proximity sensor
 *
 * Copyright (C) 2015, 2018
 * Author: Matt Ranostay <[email protected]>
 *
 * TODO: gesture + proximity calib offsets
 */

#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/sysfs.h>

#define APDS9960_REGMAP_NAME
#define APDS9960_DRV_NAME

#define APDS9960_REG_RAM_START
#define APDS9960_REG_RAM_END

#define APDS9960_REG_ENABLE
#define APDS9960_REG_ATIME
#define APDS9960_REG_WTIME

#define APDS9960_REG_AILTL
#define APDS9960_REG_AILTH
#define APDS9960_REG_AIHTL
#define APDS9960_REG_AIHTH

#define APDS9960_REG_PILT
#define APDS9960_REG_PIHT
#define APDS9960_REG_PERS

#define APDS9960_REG_CONFIG_1
#define APDS9960_REG_PPULSE

#define APDS9960_REG_CONTROL
#define APDS9960_REG_CONTROL_AGAIN_MASK
#define APDS9960_REG_CONTROL_PGAIN_MASK
#define APDS9960_REG_CONTROL_AGAIN_MASK_SHIFT
#define APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT

#define APDS9960_REG_CONFIG_2
#define APDS9960_REG_ID

#define APDS9960_REG_STATUS
#define APDS9960_REG_STATUS_PS_INT
#define APDS9960_REG_STATUS_ALS_INT
#define APDS9960_REG_STATUS_GINT

#define APDS9960_REG_PDATA
#define APDS9960_REG_POFFSET_UR
#define APDS9960_REG_POFFSET_DL
#define APDS9960_REG_CONFIG_3

#define APDS9960_REG_GPENTH
#define APDS9960_REG_GEXTH

#define APDS9960_REG_GCONF_1
#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK
#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT

#define APDS9960_REG_GCONF_2
#define APDS9960_REG_GCONF_2_GGAIN_MASK
#define APDS9960_REG_GCONF_2_GGAIN_MASK_SHIFT

#define APDS9960_REG_GOFFSET_U
#define APDS9960_REG_GOFFSET_D
#define APDS9960_REG_GPULSE
#define APDS9960_REG_GOFFSET_L
#define APDS9960_REG_GOFFSET_R
#define APDS9960_REG_GCONF_3

#define APDS9960_REG_GCONF_4
#define APDS9960_REG_GFLVL
#define APDS9960_REG_GSTATUS

#define APDS9960_REG_IFORCE
#define APDS9960_REG_PICLEAR
#define APDS9960_REG_CICLEAR
#define APDS9960_REG_AICLEAR

#define APDS9960_DEFAULT_PERS
#define APDS9960_DEFAULT_GPENTH
#define APDS9960_DEFAULT_GEXTH

#define APDS9960_MAX_PXS_THRES_VAL
#define APDS9960_MAX_ALS_THRES_VAL
#define APDS9960_MAX_INT_TIME_IN_US

enum apds9960_als_channel_idx {};

#define APDS9960_REG_ALS_BASE
#define APDS9960_REG_ALS_CHANNEL(_colour)

enum apds9960_gesture_channel_idx {};

#define APDS9960_REG_GFIFO_BASE
#define APDS9960_REG_GFIFO_DIR(_dir)

struct apds9960_data {};

enum {};

static const unsigned int apds9960_offset_regs[][2] =;

static const struct reg_default apds9960_reg_defaults[] =;

static const struct regmap_range apds9960_volatile_ranges[] =;

static const struct regmap_access_table apds9960_volatile_table =;

static const struct regmap_range apds9960_precious_ranges[] =;

static const struct regmap_access_table apds9960_precious_table =;

static const struct regmap_range apds9960_readable_ranges[] =;

static const struct regmap_access_table apds9960_readable_table =;

static const struct regmap_range apds9960_writeable_ranges[] =;

static const struct regmap_access_table apds9960_writeable_table =;

static const struct regmap_config apds9960_regmap_config =;

static const struct iio_event_spec apds9960_pxs_event_spec[] =;

static const struct iio_event_spec apds9960_als_event_spec[] =;

#define APDS9960_GESTURE_CHANNEL(_dir, _si)

#define APDS9960_INTENSITY_CHANNEL(_colour)

static const unsigned long apds9960_scan_masks[] =;

static const struct iio_chan_spec apds9960_channels[] =;

static int apds9960_set_calibbias(struct apds9960_data *data,
		struct iio_chan_spec const *chan, int calibbias)
{}

/* integration time in us */
static const int apds9960_int_time[][2] =;

/* gain mapping */
static const int apds9960_pxs_gain_map[] =;
static const int apds9960_als_gain_map[] =;

static IIO_CONST_ATTR(proximity_scale_available, "1 2 4 8");
static IIO_CONST_ATTR(intensity_scale_available, "1 4 16 64");
static IIO_CONST_ATTR_INT_TIME_AVAIL("0.028 0.1 0.2 0.7");

static struct attribute *apds9960_attributes[] =;

static const struct attribute_group apds9960_attribute_group =;

static const struct reg_field apds9960_reg_field_int_als =;

static const struct reg_field apds9960_reg_field_int_ges =;

static const struct reg_field apds9960_reg_field_int_pxs =;

static const struct reg_field apds9960_reg_field_enable_als =;

static const struct reg_field apds9960_reg_field_enable_ges =;

static const struct reg_field apds9960_reg_field_enable_pxs =;

static int apds9960_set_it_time(struct apds9960_data *data, int val2)
{}

static int apds9960_set_pxs_gain(struct apds9960_data *data, int val)
{}

static int apds9960_set_als_gain(struct apds9960_data *data, int val)
{}

#ifdef CONFIG_PM
static int apds9960_set_power_state(struct apds9960_data *data, bool on)
{}
#else
static int apds9960_set_power_state(struct apds9960_data *data, bool on)
{
	return 0;
}
#endif

static int apds9960_read_raw(struct iio_dev *indio_dev,
			     struct iio_chan_spec const *chan,
			     int *val, int *val2, long mask)
{
	struct apds9960_data *data = iio_priv(indio_dev);
	__le16 buf;
	int ret = -EINVAL;

	if (data->gesture_mode_running)
		return -EBUSY;

	switch (mask) {
	case IIO_CHAN_INFO_RAW:
		apds9960_set_power_state(data, true);
		switch (chan->type) {
		case IIO_PROXIMITY:
			ret = regmap_read(data->regmap, chan->address, val);
			if (!ret)
				ret = IIO_VAL_INT;
			break;
		case IIO_INTENSITY:
			ret = regmap_bulk_read(data->regmap, chan->address,
					       &buf, 2);
			if (!ret) {
				ret = IIO_VAL_INT;
				*val = le16_to_cpu(buf);
			}
			break;
		default:
			ret = -EINVAL;
		}
		apds9960_set_power_state(data, false);
		break;
	case IIO_CHAN_INFO_INT_TIME:
		/* RGB + ALS sensors only have integration time */
		mutex_lock(&data->lock);
		switch (chan->type) {
		case IIO_INTENSITY:
			*val = 0;
			*val2 = data->als_adc_int_us;
			ret = IIO_VAL_INT_PLUS_MICRO;
			break;
		default:
			ret = -EINVAL;
		}
		mutex_unlock(&data->lock);
		break;
	case IIO_CHAN_INFO_SCALE:
		mutex_lock(&data->lock);
		switch (chan->type) {
		case IIO_PROXIMITY:
			*val = apds9960_pxs_gain_map[data->pxs_gain];
			ret = IIO_VAL_INT;
			break;
		case IIO_INTENSITY:
			*val = apds9960_als_gain_map[data->als_gain];
			ret = IIO_VAL_INT;
			break;
		default:
			ret = -EINVAL;
		}
		mutex_unlock(&data->lock);
		break;
	case IIO_CHAN_INFO_CALIBBIAS:
		mutex_lock(&data->lock);
		*val = data->calibbias[chan->channel];
		ret = IIO_VAL_INT;
		mutex_unlock(&data->lock);
		break;
	}

	return ret;
};

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

static inline int apds9960_get_thres_reg(const struct iio_chan_spec *chan,
					 enum iio_event_direction dir,
					 u8 *reg)
{}

static int apds9960_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 apds9960_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 apds9960_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 apds9960_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 const struct iio_info apds9960_info =;

static inline int apds9660_fifo_is_empty(struct apds9960_data *data)
{}

static void apds9960_read_gesture_fifo(struct apds9960_data *data)
{}

static irqreturn_t apds9960_interrupt_handler(int irq, void *private)
{}

static int apds9960_set_powermode(struct apds9960_data *data, bool state)
{}

static int apds9960_buffer_postenable(struct iio_dev *indio_dev)
{}

static int apds9960_buffer_predisable(struct iio_dev *indio_dev)
{}

static const struct iio_buffer_setup_ops apds9960_buffer_setup_ops =;

static int apds9960_regfield_init(struct apds9960_data *data)
{}

static int apds9960_chip_init(struct apds9960_data *data)
{}

static int apds9960_probe(struct i2c_client *client)
{}

static void apds9960_remove(struct i2c_client *client)
{}

#ifdef CONFIG_PM
static int apds9960_runtime_suspend(struct device *dev)
{}

static int apds9960_runtime_resume(struct device *dev)
{}
#endif

static const struct dev_pm_ops apds9960_pm_ops =;

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

static const struct acpi_device_id apds9960_acpi_match[] =;
MODULE_DEVICE_TABLE(acpi, apds9960_acpi_match);

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

static struct i2c_driver apds9960_driver =;
module_i2c_driver();

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