// SPDX-License-Identifier: GPL-2.0+
/*
* VEML6030, VMEL6035 and VEML7700 Ambient Light Sensors
*
* Copyright (c) 2019, Rishi Gupta <gupt21@gmail.com>
*
* VEML6030:
* Datasheet: https://www.vishay.com/docs/84366/veml6030.pdf
* Appnote-84367: https://www.vishay.com/docs/84367/designingveml6030.pdf
*
* VEML6035:
* Datasheet: https://www.vishay.com/docs/84889/veml6035.pdf
* Appnote-84944: https://www.vishay.com/docs/84944/designingveml6035.pdf
*
* VEML7700:
* Datasheet: https://www.vishay.com/docs/84286/veml7700.pdf
* Appnote-84323: https://www.vishay.com/docs/84323/designingveml7700.pdf
*/
#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/units.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/iio-gts-helper.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
/* Device registers */
#define VEML6030_REG_ALS_CONF 0x00
#define VEML6030_REG_ALS_WH 0x01
#define VEML6030_REG_ALS_WL 0x02
#define VEML6030_REG_ALS_PSM 0x03
#define VEML6030_REG_ALS_DATA 0x04
#define VEML6030_REG_WH_DATA 0x05
#define VEML6030_REG_ALS_INT 0x06
#define VEML6030_REG_DATA(ch) (VEML6030_REG_ALS_DATA + (ch))
/* Bit masks for specific functionality */
#define VEML6030_ALS_IT GENMASK(9, 6)
#define VEML6030_PSM GENMASK(2, 1)
#define VEML6030_ALS_PERS GENMASK(5, 4)
#define VEML6030_ALS_GAIN GENMASK(12, 11)
#define VEML6030_PSM_EN BIT(0)
#define VEML6030_INT_TH_LOW BIT(15)
#define VEML6030_INT_TH_HIGH BIT(14)
#define VEML6030_ALS_INT_EN BIT(1)
#define VEML6030_ALS_SD BIT(0)
#define VEML6035_GAIN_M GENMASK(12, 10)
#define VEML6035_GAIN BIT(10)
#define VEML6035_DG BIT(11)
#define VEML6035_SENS BIT(12)
#define VEML6035_INT_CHAN BIT(3)
#define VEML6035_CHAN_EN BIT(2)
/* Regfields */
#define VEML6030_GAIN_RF REG_FIELD(VEML6030_REG_ALS_CONF, 11, 12)
#define VEML6030_IT_RF REG_FIELD(VEML6030_REG_ALS_CONF, 6, 9)
#define VEML6035_GAIN_RF REG_FIELD(VEML6030_REG_ALS_CONF, 10, 12)
/* Maximum scales x 10000 to work with integers */
#define VEML6030_MAX_SCALE 21504
#define VEML6035_MAX_SCALE 4096
enum veml6030_scan {
VEML6030_SCAN_ALS,
VEML6030_SCAN_WH,
VEML6030_SCAN_TIMESTAMP,
};
struct veml6030_rf {
struct regmap_field *it;
struct regmap_field *gain;
};
struct veml603x_chip {
const char *name;
const struct iio_chan_spec *channels;
const int num_channels;
const struct reg_field gain_rf;
const struct reg_field it_rf;
const int max_scale;
int (*hw_init)(struct iio_dev *indio_dev, struct device *dev);
int (*set_info)(struct iio_dev *indio_dev);
};
/*
* The resolution depends on both gain and integration time. The
* cur_resolution stores one of the resolution mentioned in the
* table during startup and gets updated whenever integration time
* or gain is changed.
*
* Table 'resolution and maximum detection range' in the appnotes
* is visualized as a 2D array. The cur_gain stores index of gain
* in this table (0-3 for VEML6030, 0-5 for VEML6035) while the
* cur_integration_time holds index of integration time (0-5).
*/
struct veml6030_data {
struct i2c_client *client;
struct regmap *regmap;
struct veml6030_rf rf;
const struct veml603x_chip *chip;
struct iio_gts gts;
};
#define VEML6030_SEL_IT_25MS 0x0C
#define VEML6030_SEL_IT_50MS 0x08
#define VEML6030_SEL_IT_100MS 0x00
#define VEML6030_SEL_IT_200MS 0x01
#define VEML6030_SEL_IT_400MS 0x02
#define VEML6030_SEL_IT_800MS 0x03
static const struct iio_itime_sel_mul veml6030_it_sel[] = {
GAIN_SCALE_ITIME_US(25000, VEML6030_SEL_IT_25MS, 1),
GAIN_SCALE_ITIME_US(50000, VEML6030_SEL_IT_50MS, 2),
GAIN_SCALE_ITIME_US(100000, VEML6030_SEL_IT_100MS, 4),
GAIN_SCALE_ITIME_US(200000, VEML6030_SEL_IT_200MS, 8),
GAIN_SCALE_ITIME_US(400000, VEML6030_SEL_IT_400MS, 16),
GAIN_SCALE_ITIME_US(800000, VEML6030_SEL_IT_800MS, 32),
};
/* Gains are multiplied by 8 to work with integers. The values in the
* iio-gts tables don't need corrections because the maximum value of
* the scale refers to GAIN = x1, and the rest of the values are
* obtained from the resulting linear function.
*/
#define VEML6030_SEL_MILLI_GAIN_X125 2
#define VEML6030_SEL_MILLI_GAIN_X250 3
#define VEML60