162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2023 Axis Communications AB
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Datasheet: https://www.ti.com/lit/gpn/opt4001
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Device driver for the Texas Instruments OPT4001.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/bitfield.h>
1162306a36Sopenharmony_ci#include <linux/i2c.h>
1262306a36Sopenharmony_ci#include <linux/iio/iio.h>
1362306a36Sopenharmony_ci#include <linux/math64.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/property.h>
1662306a36Sopenharmony_ci#include <linux/regmap.h>
1762306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* OPT4001 register set */
2062306a36Sopenharmony_ci#define OPT4001_LIGHT1_MSB    0x00
2162306a36Sopenharmony_ci#define OPT4001_LIGHT1_LSB    0x01
2262306a36Sopenharmony_ci#define OPT4001_CTRL          0x0A
2362306a36Sopenharmony_ci#define OPT4001_DEVICE_ID     0x11
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* OPT4001 register mask */
2662306a36Sopenharmony_ci#define OPT4001_EXPONENT_MASK    GENMASK(15, 12)
2762306a36Sopenharmony_ci#define OPT4001_MSB_MASK         GENMASK(11, 0)
2862306a36Sopenharmony_ci#define OPT4001_LSB_MASK         GENMASK(15, 8)
2962306a36Sopenharmony_ci#define OPT4001_COUNTER_MASK     GENMASK(7, 4)
3062306a36Sopenharmony_ci#define OPT4001_CRC_MASK         GENMASK(3, 0)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* OPT4001 device id mask */
3362306a36Sopenharmony_ci#define OPT4001_DEVICE_ID_MASK   GENMASK(11, 0)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* OPT4001 control registers mask */
3662306a36Sopenharmony_ci#define OPT4001_CTRL_QWAKE_MASK          GENMASK(15, 15)
3762306a36Sopenharmony_ci#define OPT4001_CTRL_RANGE_MASK          GENMASK(13, 10)
3862306a36Sopenharmony_ci#define OPT4001_CTRL_CONV_TIME_MASK      GENMASK(9, 6)
3962306a36Sopenharmony_ci#define OPT4001_CTRL_OPER_MODE_MASK      GENMASK(5, 4)
4062306a36Sopenharmony_ci#define OPT4001_CTRL_LATCH_MASK          GENMASK(3, 3)
4162306a36Sopenharmony_ci#define OPT4001_CTRL_INT_POL_MASK        GENMASK(2, 2)
4262306a36Sopenharmony_ci#define OPT4001_CTRL_FAULT_COUNT         GENMASK(0, 1)
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* OPT4001 constants */
4562306a36Sopenharmony_ci#define OPT4001_DEVICE_ID_VAL            0x121
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* OPT4001 operating modes */
4862306a36Sopenharmony_ci#define OPT4001_CTRL_OPER_MODE_OFF        0x0
4962306a36Sopenharmony_ci#define OPT4001_CTRL_OPER_MODE_FORCED     0x1
5062306a36Sopenharmony_ci#define OPT4001_CTRL_OPER_MODE_ONE_SHOT   0x2
5162306a36Sopenharmony_ci#define OPT4001_CTRL_OPER_MODE_CONTINUOUS 0x3
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* OPT4001 conversion control register definitions */
5462306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_0_6MS   0x0
5562306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_1MS     0x1
5662306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_1_8MS   0x2
5762306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_3_4MS   0x3
5862306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_6_5MS   0x4
5962306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_12_7MS  0x5
6062306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_25MS    0x6
6162306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_50MS    0x7
6262306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_100MS   0x8
6362306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_200MS   0x9
6462306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_400MS   0xa
6562306a36Sopenharmony_ci#define OPT4001_CTRL_CONVERSION_800MS   0xb
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* OPT4001 scale light level range definitions */
6862306a36Sopenharmony_ci#define OPT4001_CTRL_LIGHT_SCALE_AUTO   12
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* OPT4001 default values */
7162306a36Sopenharmony_ci#define OPT4001_DEFAULT_CONVERSION_TIME OPT4001_CTRL_CONVERSION_800MS
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/*
7462306a36Sopenharmony_ci * The different packaging of OPT4001 has different constants used when calculating
7562306a36Sopenharmony_ci * lux values.
7662306a36Sopenharmony_ci */
7762306a36Sopenharmony_cistruct opt4001_chip_info {
7862306a36Sopenharmony_ci	int mul;
7962306a36Sopenharmony_ci	int div;
8062306a36Sopenharmony_ci	const char *name;
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct opt4001_chip {
8462306a36Sopenharmony_ci	struct regmap *regmap;
8562306a36Sopenharmony_ci	struct i2c_client *client;
8662306a36Sopenharmony_ci	u8 int_time;
8762306a36Sopenharmony_ci	const struct opt4001_chip_info *chip_info;
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic const struct opt4001_chip_info opt4001_sot_5x3_info = {
9162306a36Sopenharmony_ci	.mul = 4375,
9262306a36Sopenharmony_ci	.div = 10000000,
9362306a36Sopenharmony_ci	.name = "opt4001-sot-5x3"
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic const struct opt4001_chip_info opt4001_picostar_info = {
9762306a36Sopenharmony_ci	.mul = 3125,
9862306a36Sopenharmony_ci	.div = 10000000,
9962306a36Sopenharmony_ci	.name = "opt4001-picostar"
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic const int opt4001_int_time_available[][2] = {
10362306a36Sopenharmony_ci	{ 0,    600 },
10462306a36Sopenharmony_ci	{ 0,   1000 },
10562306a36Sopenharmony_ci	{ 0,   1800 },
10662306a36Sopenharmony_ci	{ 0,   3400 },
10762306a36Sopenharmony_ci	{ 0,   6500 },
10862306a36Sopenharmony_ci	{ 0,  12700 },
10962306a36Sopenharmony_ci	{ 0,  25000 },
11062306a36Sopenharmony_ci	{ 0,  50000 },
11162306a36Sopenharmony_ci	{ 0, 100000 },
11262306a36Sopenharmony_ci	{ 0, 200000 },
11362306a36Sopenharmony_ci	{ 0, 400000 },
11462306a36Sopenharmony_ci	{ 0, 800000 },
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/*
11862306a36Sopenharmony_ci * Conversion time is integration time + time to set register
11962306a36Sopenharmony_ci * this is used as integration time.
12062306a36Sopenharmony_ci */
12162306a36Sopenharmony_cistatic const int opt4001_int_time_reg[][2] = {
12262306a36Sopenharmony_ci	{    600,  OPT4001_CTRL_CONVERSION_0_6MS  },
12362306a36Sopenharmony_ci	{   1000,  OPT4001_CTRL_CONVERSION_1MS    },
12462306a36Sopenharmony_ci	{   1800,  OPT4001_CTRL_CONVERSION_1_8MS  },
12562306a36Sopenharmony_ci	{   3400,  OPT4001_CTRL_CONVERSION_3_4MS  },
12662306a36Sopenharmony_ci	{   6500,  OPT4001_CTRL_CONVERSION_6_5MS  },
12762306a36Sopenharmony_ci	{  12700,  OPT4001_CTRL_CONVERSION_12_7MS },
12862306a36Sopenharmony_ci	{  25000,  OPT4001_CTRL_CONVERSION_25MS   },
12962306a36Sopenharmony_ci	{  50000,  OPT4001_CTRL_CONVERSION_50MS   },
13062306a36Sopenharmony_ci	{ 100000,  OPT4001_CTRL_CONVERSION_100MS  },
13162306a36Sopenharmony_ci	{ 200000,  OPT4001_CTRL_CONVERSION_200MS  },
13262306a36Sopenharmony_ci	{ 400000,  OPT4001_CTRL_CONVERSION_400MS  },
13362306a36Sopenharmony_ci	{ 800000,  OPT4001_CTRL_CONVERSION_800MS  },
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic int opt4001_als_time_to_index(const u32 als_integration_time)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	int i;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(opt4001_int_time_available); i++) {
14162306a36Sopenharmony_ci		if (als_integration_time == opt4001_int_time_available[i][1])
14262306a36Sopenharmony_ci			return i;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return -EINVAL;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic u8 opt4001_calculate_crc(u8 exp, u32 mantissa, u8 count)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	u8 crc;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	crc = (hweight32(mantissa) + hweight32(exp) + hweight32(count)) % 2;
15362306a36Sopenharmony_ci	crc |= ((hweight32(mantissa & 0xAAAAA) + hweight32(exp & 0xA)
15462306a36Sopenharmony_ci		 + hweight32(count & 0xA)) % 2) << 1;
15562306a36Sopenharmony_ci	crc |= ((hweight32(mantissa & 0x88888) + hweight32(exp & 0x8)
15662306a36Sopenharmony_ci		 + hweight32(count & 0x8)) % 2) << 2;
15762306a36Sopenharmony_ci	crc |= (hweight32(mantissa & 0x80808) % 2) << 3;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	return crc;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int opt4001_read_lux_value(struct iio_dev *indio_dev,
16362306a36Sopenharmony_ci				  int *val, int *val2)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	struct opt4001_chip *chip = iio_priv(indio_dev);
16662306a36Sopenharmony_ci	struct device *dev = &chip->client->dev;
16762306a36Sopenharmony_ci	unsigned int light1;
16862306a36Sopenharmony_ci	unsigned int light2;
16962306a36Sopenharmony_ci	u16 msb;
17062306a36Sopenharmony_ci	u16 lsb;
17162306a36Sopenharmony_ci	u8 exp;
17262306a36Sopenharmony_ci	u8 count;
17362306a36Sopenharmony_ci	u8 crc;
17462306a36Sopenharmony_ci	u8 calc_crc;
17562306a36Sopenharmony_ci	u64 lux_raw;
17662306a36Sopenharmony_ci	int ret;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	ret = regmap_read(chip->regmap, OPT4001_LIGHT1_MSB, &light1);
17962306a36Sopenharmony_ci	if (ret < 0) {
18062306a36Sopenharmony_ci		dev_err(dev, "Failed to read data bytes");
18162306a36Sopenharmony_ci		return ret;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	ret = regmap_read(chip->regmap, OPT4001_LIGHT1_LSB, &light2);
18562306a36Sopenharmony_ci	if (ret < 0) {
18662306a36Sopenharmony_ci		dev_err(dev, "Failed to read data bytes");
18762306a36Sopenharmony_ci		return ret;
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	count = FIELD_GET(OPT4001_COUNTER_MASK, light2);
19162306a36Sopenharmony_ci	exp = FIELD_GET(OPT4001_EXPONENT_MASK, light1);
19262306a36Sopenharmony_ci	crc = FIELD_GET(OPT4001_CRC_MASK, light2);
19362306a36Sopenharmony_ci	msb = FIELD_GET(OPT4001_MSB_MASK, light1);
19462306a36Sopenharmony_ci	lsb = FIELD_GET(OPT4001_LSB_MASK, light2);
19562306a36Sopenharmony_ci	lux_raw = (msb << 8) + lsb;
19662306a36Sopenharmony_ci	calc_crc = opt4001_calculate_crc(exp, lux_raw, count);
19762306a36Sopenharmony_ci	if (calc_crc != crc)
19862306a36Sopenharmony_ci		return -EIO;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	lux_raw = lux_raw << exp;
20162306a36Sopenharmony_ci	lux_raw = lux_raw * chip->chip_info->mul;
20262306a36Sopenharmony_ci	*val = div_u64_rem(lux_raw, chip->chip_info->div, val2);
20362306a36Sopenharmony_ci	*val2 = *val2 * 100;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	return IIO_VAL_INT_PLUS_NANO;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic int opt4001_set_conf(struct opt4001_chip *chip)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct device *dev = &chip->client->dev;
21162306a36Sopenharmony_ci	u16 reg;
21262306a36Sopenharmony_ci	int ret;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	reg = FIELD_PREP(OPT4001_CTRL_RANGE_MASK, OPT4001_CTRL_LIGHT_SCALE_AUTO);
21562306a36Sopenharmony_ci	reg |= FIELD_PREP(OPT4001_CTRL_CONV_TIME_MASK, chip->int_time);
21662306a36Sopenharmony_ci	reg |= FIELD_PREP(OPT4001_CTRL_OPER_MODE_MASK, OPT4001_CTRL_OPER_MODE_CONTINUOUS);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	ret = regmap_write(chip->regmap, OPT4001_CTRL, reg);
21962306a36Sopenharmony_ci	if (ret)
22062306a36Sopenharmony_ci		dev_err(dev, "Failed to set configuration\n");
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return ret;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic int opt4001_power_down(struct opt4001_chip *chip)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct device *dev = &chip->client->dev;
22862306a36Sopenharmony_ci	int ret;
22962306a36Sopenharmony_ci	unsigned int reg;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	ret = regmap_read(chip->regmap, OPT4001_DEVICE_ID, &reg);
23262306a36Sopenharmony_ci	if (ret) {
23362306a36Sopenharmony_ci		dev_err(dev, "Failed to read configuration\n");
23462306a36Sopenharmony_ci		return ret;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* MODE_OFF is 0x0 so just set bits to 0 */
23862306a36Sopenharmony_ci	reg &= ~OPT4001_CTRL_OPER_MODE_MASK;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	ret = regmap_write(chip->regmap, OPT4001_CTRL, reg);
24162306a36Sopenharmony_ci	if (ret)
24262306a36Sopenharmony_ci		dev_err(dev, "Failed to set configuration to power down\n");
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return ret;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic void opt4001_chip_off_action(void *data)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	struct opt4001_chip *chip = data;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	opt4001_power_down(chip);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic const struct iio_chan_spec opt4001_channels[] = {
25562306a36Sopenharmony_ci	{
25662306a36Sopenharmony_ci		.type = IIO_LIGHT,
25762306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
25862306a36Sopenharmony_ci		.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
25962306a36Sopenharmony_ci		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME)
26062306a36Sopenharmony_ci	},
26162306a36Sopenharmony_ci};
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic int opt4001_read_raw(struct iio_dev *indio_dev,
26462306a36Sopenharmony_ci			    struct iio_chan_spec const *chan,
26562306a36Sopenharmony_ci			    int *val, int *val2, long mask)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct opt4001_chip *chip = iio_priv(indio_dev);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	switch (mask) {
27062306a36Sopenharmony_ci	case IIO_CHAN_INFO_PROCESSED:
27162306a36Sopenharmony_ci		return opt4001_read_lux_value(indio_dev, val, val2);
27262306a36Sopenharmony_ci	case IIO_CHAN_INFO_INT_TIME:
27362306a36Sopenharmony_ci		*val = 0;
27462306a36Sopenharmony_ci		*val2 = opt4001_int_time_reg[chip->int_time][0];
27562306a36Sopenharmony_ci		return IIO_VAL_INT_PLUS_MICRO;
27662306a36Sopenharmony_ci	default:
27762306a36Sopenharmony_ci		return -EINVAL;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic int opt4001_write_raw(struct iio_dev *indio_dev,
28262306a36Sopenharmony_ci			     struct iio_chan_spec const *chan,
28362306a36Sopenharmony_ci			     int val, int val2, long mask)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	struct opt4001_chip *chip = iio_priv(indio_dev);
28662306a36Sopenharmony_ci	int int_time;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	switch (mask) {
28962306a36Sopenharmony_ci	case IIO_CHAN_INFO_INT_TIME:
29062306a36Sopenharmony_ci		int_time = opt4001_als_time_to_index(val2);
29162306a36Sopenharmony_ci		if (int_time < 0)
29262306a36Sopenharmony_ci			return int_time;
29362306a36Sopenharmony_ci		chip->int_time = int_time;
29462306a36Sopenharmony_ci		return opt4001_set_conf(chip);
29562306a36Sopenharmony_ci	default:
29662306a36Sopenharmony_ci		return -EINVAL;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic int opt4001_read_available(struct iio_dev *indio_dev,
30162306a36Sopenharmony_ci				  struct iio_chan_spec const *chan,
30262306a36Sopenharmony_ci				  const int **vals, int *type, int *length,
30362306a36Sopenharmony_ci				  long mask)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	switch (mask) {
30662306a36Sopenharmony_ci	case IIO_CHAN_INFO_INT_TIME:
30762306a36Sopenharmony_ci		*length = ARRAY_SIZE(opt4001_int_time_available) * 2;
30862306a36Sopenharmony_ci		*vals = (const int *)opt4001_int_time_available;
30962306a36Sopenharmony_ci		*type = IIO_VAL_INT_PLUS_MICRO;
31062306a36Sopenharmony_ci		return IIO_AVAIL_LIST;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	default:
31362306a36Sopenharmony_ci		return -EINVAL;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic const struct iio_info opt4001_info_no_irq = {
31862306a36Sopenharmony_ci	.read_raw = opt4001_read_raw,
31962306a36Sopenharmony_ci	.write_raw = opt4001_write_raw,
32062306a36Sopenharmony_ci	.read_avail = opt4001_read_available,
32162306a36Sopenharmony_ci};
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int opt4001_load_defaults(struct opt4001_chip *chip)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	chip->int_time = OPT4001_DEFAULT_CONVERSION_TIME;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return opt4001_set_conf(chip);
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic bool opt4001_readable_reg(struct device *dev, unsigned int reg)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	switch (reg) {
33362306a36Sopenharmony_ci	case OPT4001_LIGHT1_MSB:
33462306a36Sopenharmony_ci	case OPT4001_LIGHT1_LSB:
33562306a36Sopenharmony_ci	case OPT4001_CTRL:
33662306a36Sopenharmony_ci	case OPT4001_DEVICE_ID:
33762306a36Sopenharmony_ci		return true;
33862306a36Sopenharmony_ci	default:
33962306a36Sopenharmony_ci		return false;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic bool opt4001_writable_reg(struct device *dev, unsigned int reg)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	switch (reg) {
34662306a36Sopenharmony_ci	case OPT4001_CTRL:
34762306a36Sopenharmony_ci		return true;
34862306a36Sopenharmony_ci	default:
34962306a36Sopenharmony_ci		return false;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic bool opt4001_volatile_reg(struct device *dev, unsigned int reg)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	switch (reg) {
35662306a36Sopenharmony_ci	case OPT4001_LIGHT1_MSB:
35762306a36Sopenharmony_ci	case OPT4001_LIGHT1_LSB:
35862306a36Sopenharmony_ci		return true;
35962306a36Sopenharmony_ci	default:
36062306a36Sopenharmony_ci		return false;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic const struct regmap_config opt4001_regmap_config = {
36562306a36Sopenharmony_ci	.name = "opt4001",
36662306a36Sopenharmony_ci	.reg_bits = 8,
36762306a36Sopenharmony_ci	.val_bits = 16,
36862306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
36962306a36Sopenharmony_ci	.max_register = OPT4001_DEVICE_ID,
37062306a36Sopenharmony_ci	.readable_reg = opt4001_readable_reg,
37162306a36Sopenharmony_ci	.writeable_reg = opt4001_writable_reg,
37262306a36Sopenharmony_ci	.volatile_reg = opt4001_volatile_reg,
37362306a36Sopenharmony_ci	.val_format_endian = REGMAP_ENDIAN_BIG,
37462306a36Sopenharmony_ci};
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic int opt4001_probe(struct i2c_client *client)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct opt4001_chip *chip;
37962306a36Sopenharmony_ci	struct iio_dev *indio_dev;
38062306a36Sopenharmony_ci	int ret;
38162306a36Sopenharmony_ci	uint dev_id;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
38462306a36Sopenharmony_ci	if (!indio_dev)
38562306a36Sopenharmony_ci		return -ENOMEM;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	chip = iio_priv(indio_dev);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	ret = devm_regulator_get_enable(&client->dev, "vdd");
39062306a36Sopenharmony_ci	if (ret)
39162306a36Sopenharmony_ci		return dev_err_probe(&client->dev, ret, "Failed to enable vdd supply\n");
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	chip->regmap = devm_regmap_init_i2c(client, &opt4001_regmap_config);
39462306a36Sopenharmony_ci	if (IS_ERR(chip->regmap))
39562306a36Sopenharmony_ci		return dev_err_probe(&client->dev, PTR_ERR(chip->regmap),
39662306a36Sopenharmony_ci				     "regmap initialization failed\n");
39762306a36Sopenharmony_ci	chip->client = client;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	indio_dev->info = &opt4001_info_no_irq;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	ret = regmap_reinit_cache(chip->regmap, &opt4001_regmap_config);
40262306a36Sopenharmony_ci	if (ret)
40362306a36Sopenharmony_ci		return dev_err_probe(&client->dev, ret,
40462306a36Sopenharmony_ci				     "failed to reinit regmap cache\n");
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	ret = regmap_read(chip->regmap, OPT4001_DEVICE_ID, &dev_id);
40762306a36Sopenharmony_ci	if (ret < 0)
40862306a36Sopenharmony_ci		return dev_err_probe(&client->dev, ret,
40962306a36Sopenharmony_ci			"Failed to read the device ID register\n");
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	dev_id = FIELD_GET(OPT4001_DEVICE_ID_MASK, dev_id);
41262306a36Sopenharmony_ci	if (dev_id != OPT4001_DEVICE_ID_VAL)
41362306a36Sopenharmony_ci		dev_warn(&client->dev, "Device ID: %#04x unknown\n", dev_id);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	chip->chip_info = device_get_match_data(&client->dev);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	indio_dev->channels = opt4001_channels;
41862306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(opt4001_channels);
41962306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
42062306a36Sopenharmony_ci	indio_dev->name = chip->chip_info->name;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	ret = opt4001_load_defaults(chip);
42362306a36Sopenharmony_ci	if (ret < 0)
42462306a36Sopenharmony_ci		return dev_err_probe(&client->dev, ret,
42562306a36Sopenharmony_ci				     "Failed to set sensor defaults\n");
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	ret = devm_add_action_or_reset(&client->dev,
42862306a36Sopenharmony_ci					opt4001_chip_off_action,
42962306a36Sopenharmony_ci					chip);
43062306a36Sopenharmony_ci	if (ret < 0)
43162306a36Sopenharmony_ci		return dev_err_probe(&client->dev, ret,
43262306a36Sopenharmony_ci				     "Failed to setup power off action\n");
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	return devm_iio_device_register(&client->dev, indio_dev);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci/*
43862306a36Sopenharmony_ci * The compatible string determines which constants to use depending on
43962306a36Sopenharmony_ci * opt4001 packaging
44062306a36Sopenharmony_ci */
44162306a36Sopenharmony_cistatic const struct i2c_device_id opt4001_id[] = {
44262306a36Sopenharmony_ci	{ "opt4001-sot-5x3", (kernel_ulong_t)&opt4001_sot_5x3_info },
44362306a36Sopenharmony_ci	{ "opt4001-picostar", (kernel_ulong_t)&opt4001_picostar_info },
44462306a36Sopenharmony_ci	{ }
44562306a36Sopenharmony_ci};
44662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, opt4001_id);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic const struct of_device_id opt4001_of_match[] = {
44962306a36Sopenharmony_ci	{ .compatible = "ti,opt4001-sot-5x3", .data = &opt4001_sot_5x3_info},
45062306a36Sopenharmony_ci	{ .compatible = "ti,opt4001-picostar", .data = &opt4001_picostar_info},
45162306a36Sopenharmony_ci	{}
45262306a36Sopenharmony_ci};
45362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, opt4001_of_match);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic struct i2c_driver opt4001_driver = {
45662306a36Sopenharmony_ci	.driver = {
45762306a36Sopenharmony_ci		.name = "opt4001",
45862306a36Sopenharmony_ci		.of_match_table = opt4001_of_match,
45962306a36Sopenharmony_ci	},
46062306a36Sopenharmony_ci	.probe = opt4001_probe,
46162306a36Sopenharmony_ci	.id_table = opt4001_id,
46262306a36Sopenharmony_ci};
46362306a36Sopenharmony_cimodule_i2c_driver(opt4001_driver);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ciMODULE_AUTHOR("Stefan Windfeldt-Prytz <stefan.windfeldt-prytz@axis.com>");
46662306a36Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments opt4001 ambient light sensor driver");
46762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
468