162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * adux1020.c - Support for Analog Devices ADUX1020 photometric sensor
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2019 Linaro Ltd.
662306a36Sopenharmony_ci * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * TODO: Triggered buffer support
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/bitfield.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/err.h>
1462306a36Sopenharmony_ci#include <linux/i2c.h>
1562306a36Sopenharmony_ci#include <linux/init.h>
1662306a36Sopenharmony_ci#include <linux/interrupt.h>
1762306a36Sopenharmony_ci#include <linux/irq.h>
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/mutex.h>
2062306a36Sopenharmony_ci#include <linux/regmap.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <linux/iio/iio.h>
2362306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
2462306a36Sopenharmony_ci#include <linux/iio/events.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define ADUX1020_REGMAP_NAME		"adux1020_regmap"
2762306a36Sopenharmony_ci#define ADUX1020_DRV_NAME		"adux1020"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* System registers */
3062306a36Sopenharmony_ci#define ADUX1020_REG_CHIP_ID		0x08
3162306a36Sopenharmony_ci#define ADUX1020_REG_SLAVE_ADDRESS	0x09
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define ADUX1020_REG_SW_RESET		0x0f
3462306a36Sopenharmony_ci#define ADUX1020_REG_INT_ENABLE		0x1c
3562306a36Sopenharmony_ci#define ADUX1020_REG_INT_POLARITY	0x1d
3662306a36Sopenharmony_ci#define ADUX1020_REG_PROX_TH_ON1	0x2a
3762306a36Sopenharmony_ci#define ADUX1020_REG_PROX_TH_OFF1	0x2b
3862306a36Sopenharmony_ci#define	ADUX1020_REG_PROX_TYPE		0x2f
3962306a36Sopenharmony_ci#define	ADUX1020_REG_TEST_MODES_3	0x32
4062306a36Sopenharmony_ci#define	ADUX1020_REG_FORCE_MODE		0x33
4162306a36Sopenharmony_ci#define	ADUX1020_REG_FREQUENCY		0x40
4262306a36Sopenharmony_ci#define ADUX1020_REG_LED_CURRENT	0x41
4362306a36Sopenharmony_ci#define	ADUX1020_REG_OP_MODE		0x45
4462306a36Sopenharmony_ci#define	ADUX1020_REG_INT_MASK		0x48
4562306a36Sopenharmony_ci#define	ADUX1020_REG_INT_STATUS		0x49
4662306a36Sopenharmony_ci#define	ADUX1020_REG_DATA_BUFFER	0x60
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* Chip ID bits */
4962306a36Sopenharmony_ci#define ADUX1020_CHIP_ID_MASK		GENMASK(11, 0)
5062306a36Sopenharmony_ci#define ADUX1020_CHIP_ID		0x03fc
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define ADUX1020_SW_RESET		BIT(1)
5362306a36Sopenharmony_ci#define ADUX1020_FIFO_FLUSH		BIT(15)
5462306a36Sopenharmony_ci#define ADUX1020_OP_MODE_MASK		GENMASK(3, 0)
5562306a36Sopenharmony_ci#define ADUX1020_DATA_OUT_MODE_MASK	GENMASK(7, 4)
5662306a36Sopenharmony_ci#define ADUX1020_DATA_OUT_PROX_I	FIELD_PREP(ADUX1020_DATA_OUT_MODE_MASK, 1)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define ADUX1020_MODE_INT_MASK		GENMASK(7, 0)
5962306a36Sopenharmony_ci#define ADUX1020_INT_ENABLE		0x2094
6062306a36Sopenharmony_ci#define ADUX1020_INT_DISABLE		0x2090
6162306a36Sopenharmony_ci#define ADUX1020_PROX_INT_ENABLE	0x00f0
6262306a36Sopenharmony_ci#define ADUX1020_PROX_ON1_INT		BIT(0)
6362306a36Sopenharmony_ci#define ADUX1020_PROX_OFF1_INT		BIT(1)
6462306a36Sopenharmony_ci#define ADUX1020_FIFO_INT_ENABLE	0x7f
6562306a36Sopenharmony_ci#define ADUX1020_MODE_INT_DISABLE	0xff
6662306a36Sopenharmony_ci#define ADUX1020_MODE_INT_STATUS_MASK	GENMASK(7, 0)
6762306a36Sopenharmony_ci#define ADUX1020_FIFO_STATUS_MASK	GENMASK(15, 8)
6862306a36Sopenharmony_ci#define ADUX1020_INT_CLEAR		0xff
6962306a36Sopenharmony_ci#define ADUX1020_PROX_TYPE		BIT(15)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define ADUX1020_INT_PROX_ON1		BIT(0)
7262306a36Sopenharmony_ci#define ADUX1020_INT_PROX_OFF1		BIT(1)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define ADUX1020_FORCE_CLOCK_ON		0x0f4f
7562306a36Sopenharmony_ci#define ADUX1020_FORCE_CLOCK_RESET	0x0040
7662306a36Sopenharmony_ci#define ADUX1020_ACTIVE_4_STATE		0x0008
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define ADUX1020_PROX_FREQ_MASK		GENMASK(7, 4)
7962306a36Sopenharmony_ci#define ADUX1020_PROX_FREQ(x)		FIELD_PREP(ADUX1020_PROX_FREQ_MASK, x)
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define ADUX1020_LED_CURRENT_MASK	GENMASK(3, 0)
8262306a36Sopenharmony_ci#define ADUX1020_LED_PIREF_EN		BIT(12)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/* Operating modes */
8562306a36Sopenharmony_cienum adux1020_op_modes {
8662306a36Sopenharmony_ci	ADUX1020_MODE_STANDBY,
8762306a36Sopenharmony_ci	ADUX1020_MODE_PROX_I,
8862306a36Sopenharmony_ci	ADUX1020_MODE_PROX_XY,
8962306a36Sopenharmony_ci	ADUX1020_MODE_GEST,
9062306a36Sopenharmony_ci	ADUX1020_MODE_SAMPLE,
9162306a36Sopenharmony_ci	ADUX1020_MODE_FORCE = 0x0e,
9262306a36Sopenharmony_ci	ADUX1020_MODE_IDLE = 0x0f,
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistruct adux1020_data {
9662306a36Sopenharmony_ci	struct i2c_client *client;
9762306a36Sopenharmony_ci	struct iio_dev *indio_dev;
9862306a36Sopenharmony_ci	struct mutex lock;
9962306a36Sopenharmony_ci	struct regmap *regmap;
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistruct adux1020_mode_data {
10362306a36Sopenharmony_ci	u8 bytes;
10462306a36Sopenharmony_ci	u8 buf_len;
10562306a36Sopenharmony_ci	u16 int_en;
10662306a36Sopenharmony_ci};
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic const struct adux1020_mode_data adux1020_modes[] = {
10962306a36Sopenharmony_ci	[ADUX1020_MODE_PROX_I] = {
11062306a36Sopenharmony_ci		.bytes = 2,
11162306a36Sopenharmony_ci		.buf_len = 1,
11262306a36Sopenharmony_ci		.int_en = ADUX1020_PROX_INT_ENABLE,
11362306a36Sopenharmony_ci	},
11462306a36Sopenharmony_ci};
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic const struct regmap_config adux1020_regmap_config = {
11762306a36Sopenharmony_ci	.name = ADUX1020_REGMAP_NAME,
11862306a36Sopenharmony_ci	.reg_bits = 8,
11962306a36Sopenharmony_ci	.val_bits = 16,
12062306a36Sopenharmony_ci	.max_register = 0x6F,
12162306a36Sopenharmony_ci	.cache_type = REGCACHE_NONE,
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic const struct reg_sequence adux1020_def_conf[] = {
12562306a36Sopenharmony_ci	{ 0x000c, 0x000f },
12662306a36Sopenharmony_ci	{ 0x0010, 0x1010 },
12762306a36Sopenharmony_ci	{ 0x0011, 0x004c },
12862306a36Sopenharmony_ci	{ 0x0012, 0x5f0c },
12962306a36Sopenharmony_ci	{ 0x0013, 0xada5 },
13062306a36Sopenharmony_ci	{ 0x0014, 0x0080 },
13162306a36Sopenharmony_ci	{ 0x0015, 0x0000 },
13262306a36Sopenharmony_ci	{ 0x0016, 0x0600 },
13362306a36Sopenharmony_ci	{ 0x0017, 0x0000 },
13462306a36Sopenharmony_ci	{ 0x0018, 0x2693 },
13562306a36Sopenharmony_ci	{ 0x0019, 0x0004 },
13662306a36Sopenharmony_ci	{ 0x001a, 0x4280 },
13762306a36Sopenharmony_ci	{ 0x001b, 0x0060 },
13862306a36Sopenharmony_ci	{ 0x001c, 0x2094 },
13962306a36Sopenharmony_ci	{ 0x001d, 0x0020 },
14062306a36Sopenharmony_ci	{ 0x001e, 0x0001 },
14162306a36Sopenharmony_ci	{ 0x001f, 0x0100 },
14262306a36Sopenharmony_ci	{ 0x0020, 0x0320 },
14362306a36Sopenharmony_ci	{ 0x0021, 0x0A13 },
14462306a36Sopenharmony_ci	{ 0x0022, 0x0320 },
14562306a36Sopenharmony_ci	{ 0x0023, 0x0113 },
14662306a36Sopenharmony_ci	{ 0x0024, 0x0000 },
14762306a36Sopenharmony_ci	{ 0x0025, 0x2412 },
14862306a36Sopenharmony_ci	{ 0x0026, 0x2412 },
14962306a36Sopenharmony_ci	{ 0x0027, 0x0022 },
15062306a36Sopenharmony_ci	{ 0x0028, 0x0000 },
15162306a36Sopenharmony_ci	{ 0x0029, 0x0300 },
15262306a36Sopenharmony_ci	{ 0x002a, 0x0700 },
15362306a36Sopenharmony_ci	{ 0x002b, 0x0600 },
15462306a36Sopenharmony_ci	{ 0x002c, 0x6000 },
15562306a36Sopenharmony_ci	{ 0x002d, 0x4000 },
15662306a36Sopenharmony_ci	{ 0x002e, 0x0000 },
15762306a36Sopenharmony_ci	{ 0x002f, 0x0000 },
15862306a36Sopenharmony_ci	{ 0x0030, 0x0000 },
15962306a36Sopenharmony_ci	{ 0x0031, 0x0000 },
16062306a36Sopenharmony_ci	{ 0x0032, 0x0040 },
16162306a36Sopenharmony_ci	{ 0x0033, 0x0008 },
16262306a36Sopenharmony_ci	{ 0x0034, 0xE400 },
16362306a36Sopenharmony_ci	{ 0x0038, 0x8080 },
16462306a36Sopenharmony_ci	{ 0x0039, 0x8080 },
16562306a36Sopenharmony_ci	{ 0x003a, 0x2000 },
16662306a36Sopenharmony_ci	{ 0x003b, 0x1f00 },
16762306a36Sopenharmony_ci	{ 0x003c, 0x2000 },
16862306a36Sopenharmony_ci	{ 0x003d, 0x2000 },
16962306a36Sopenharmony_ci	{ 0x003e, 0x0000 },
17062306a36Sopenharmony_ci	{ 0x0040, 0x8069 },
17162306a36Sopenharmony_ci	{ 0x0041, 0x1f2f },
17262306a36Sopenharmony_ci	{ 0x0042, 0x4000 },
17362306a36Sopenharmony_ci	{ 0x0043, 0x0000 },
17462306a36Sopenharmony_ci	{ 0x0044, 0x0008 },
17562306a36Sopenharmony_ci	{ 0x0046, 0x0000 },
17662306a36Sopenharmony_ci	{ 0x0048, 0x00ef },
17762306a36Sopenharmony_ci	{ 0x0049, 0x0000 },
17862306a36Sopenharmony_ci	{ 0x0045, 0x0000 },
17962306a36Sopenharmony_ci};
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic const int adux1020_rates[][2] = {
18262306a36Sopenharmony_ci	{ 0, 100000 },
18362306a36Sopenharmony_ci	{ 0, 200000 },
18462306a36Sopenharmony_ci	{ 0, 500000 },
18562306a36Sopenharmony_ci	{ 1, 0 },
18662306a36Sopenharmony_ci	{ 2, 0 },
18762306a36Sopenharmony_ci	{ 5, 0 },
18862306a36Sopenharmony_ci	{ 10, 0 },
18962306a36Sopenharmony_ci	{ 20, 0 },
19062306a36Sopenharmony_ci	{ 50, 0 },
19162306a36Sopenharmony_ci	{ 100, 0 },
19262306a36Sopenharmony_ci	{ 190, 0 },
19362306a36Sopenharmony_ci	{ 450, 0 },
19462306a36Sopenharmony_ci	{ 820, 0 },
19562306a36Sopenharmony_ci	{ 1400, 0 },
19662306a36Sopenharmony_ci};
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic const int adux1020_led_currents[][2] = {
19962306a36Sopenharmony_ci	{ 0, 25000 },
20062306a36Sopenharmony_ci	{ 0, 40000 },
20162306a36Sopenharmony_ci	{ 0, 55000 },
20262306a36Sopenharmony_ci	{ 0, 70000 },
20362306a36Sopenharmony_ci	{ 0, 85000 },
20462306a36Sopenharmony_ci	{ 0, 100000 },
20562306a36Sopenharmony_ci	{ 0, 115000 },
20662306a36Sopenharmony_ci	{ 0, 130000 },
20762306a36Sopenharmony_ci	{ 0, 145000 },
20862306a36Sopenharmony_ci	{ 0, 160000 },
20962306a36Sopenharmony_ci	{ 0, 175000 },
21062306a36Sopenharmony_ci	{ 0, 190000 },
21162306a36Sopenharmony_ci	{ 0, 205000 },
21262306a36Sopenharmony_ci	{ 0, 220000 },
21362306a36Sopenharmony_ci	{ 0, 235000 },
21462306a36Sopenharmony_ci	{ 0, 250000 },
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic int adux1020_flush_fifo(struct adux1020_data *data)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	int ret;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* Force Idle mode */
22262306a36Sopenharmony_ci	ret = regmap_write(data->regmap, ADUX1020_REG_FORCE_MODE,
22362306a36Sopenharmony_ci			   ADUX1020_ACTIVE_4_STATE);
22462306a36Sopenharmony_ci	if (ret < 0)
22562306a36Sopenharmony_ci		return ret;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
22862306a36Sopenharmony_ci				 ADUX1020_OP_MODE_MASK, ADUX1020_MODE_FORCE);
22962306a36Sopenharmony_ci	if (ret < 0)
23062306a36Sopenharmony_ci		return ret;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
23362306a36Sopenharmony_ci				 ADUX1020_OP_MODE_MASK, ADUX1020_MODE_IDLE);
23462306a36Sopenharmony_ci	if (ret < 0)
23562306a36Sopenharmony_ci		return ret;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* Flush FIFO */
23862306a36Sopenharmony_ci	ret = regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
23962306a36Sopenharmony_ci			   ADUX1020_FORCE_CLOCK_ON);
24062306a36Sopenharmony_ci	if (ret < 0)
24162306a36Sopenharmony_ci		return ret;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	ret = regmap_write(data->regmap, ADUX1020_REG_INT_STATUS,
24462306a36Sopenharmony_ci			   ADUX1020_FIFO_FLUSH);
24562306a36Sopenharmony_ci	if (ret < 0)
24662306a36Sopenharmony_ci		return ret;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
24962306a36Sopenharmony_ci			    ADUX1020_FORCE_CLOCK_RESET);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic int adux1020_read_fifo(struct adux1020_data *data, u16 *buf, u8 buf_len)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	unsigned int regval;
25562306a36Sopenharmony_ci	int i, ret;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* Enable 32MHz clock */
25862306a36Sopenharmony_ci	ret = regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
25962306a36Sopenharmony_ci			   ADUX1020_FORCE_CLOCK_ON);
26062306a36Sopenharmony_ci	if (ret < 0)
26162306a36Sopenharmony_ci		return ret;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	for (i = 0; i < buf_len; i++) {
26462306a36Sopenharmony_ci		ret = regmap_read(data->regmap, ADUX1020_REG_DATA_BUFFER,
26562306a36Sopenharmony_ci				  &regval);
26662306a36Sopenharmony_ci		if (ret < 0)
26762306a36Sopenharmony_ci			return ret;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		buf[i] = regval;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Set 32MHz clock to be controlled by internal state machine */
27362306a36Sopenharmony_ci	return regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
27462306a36Sopenharmony_ci			    ADUX1020_FORCE_CLOCK_RESET);
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic int adux1020_set_mode(struct adux1020_data *data,
27862306a36Sopenharmony_ci			     enum adux1020_op_modes mode)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	int ret;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	/* Switch to standby mode before changing the mode */
28362306a36Sopenharmony_ci	ret = regmap_write(data->regmap, ADUX1020_REG_OP_MODE,
28462306a36Sopenharmony_ci			   ADUX1020_MODE_STANDBY);
28562306a36Sopenharmony_ci	if (ret < 0)
28662306a36Sopenharmony_ci		return ret;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/* Set data out and switch to the desired mode */
28962306a36Sopenharmony_ci	switch (mode) {
29062306a36Sopenharmony_ci	case ADUX1020_MODE_PROX_I:
29162306a36Sopenharmony_ci		ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
29262306a36Sopenharmony_ci					 ADUX1020_DATA_OUT_MODE_MASK,
29362306a36Sopenharmony_ci					 ADUX1020_DATA_OUT_PROX_I);
29462306a36Sopenharmony_ci		if (ret < 0)
29562306a36Sopenharmony_ci			return ret;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci		ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
29862306a36Sopenharmony_ci					 ADUX1020_OP_MODE_MASK,
29962306a36Sopenharmony_ci					 ADUX1020_MODE_PROX_I);
30062306a36Sopenharmony_ci		if (ret < 0)
30162306a36Sopenharmony_ci			return ret;
30262306a36Sopenharmony_ci		break;
30362306a36Sopenharmony_ci	default:
30462306a36Sopenharmony_ci		return -EINVAL;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	return 0;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic int adux1020_measure(struct adux1020_data *data,
31162306a36Sopenharmony_ci			    enum adux1020_op_modes mode,
31262306a36Sopenharmony_ci			    u16 *val)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	unsigned int status;
31562306a36Sopenharmony_ci	int ret, tries = 50;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* Disable INT pin as polling is going to be used */
31862306a36Sopenharmony_ci	ret = regmap_write(data->regmap, ADUX1020_REG_INT_ENABLE,
31962306a36Sopenharmony_ci			   ADUX1020_INT_DISABLE);
32062306a36Sopenharmony_ci	if (ret < 0)
32162306a36Sopenharmony_ci		return ret;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* Enable mode interrupt */
32462306a36Sopenharmony_ci	ret = regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
32562306a36Sopenharmony_ci				 ADUX1020_MODE_INT_MASK,
32662306a36Sopenharmony_ci				 adux1020_modes[mode].int_en);
32762306a36Sopenharmony_ci	if (ret < 0)
32862306a36Sopenharmony_ci		return ret;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	while (tries--) {
33162306a36Sopenharmony_ci		ret = regmap_read(data->regmap, ADUX1020_REG_INT_STATUS,
33262306a36Sopenharmony_ci				  &status);
33362306a36Sopenharmony_ci		if (ret < 0)
33462306a36Sopenharmony_ci			return ret;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		status &= ADUX1020_FIFO_STATUS_MASK;
33762306a36Sopenharmony_ci		if (status >= adux1020_modes[mode].bytes)
33862306a36Sopenharmony_ci			break;
33962306a36Sopenharmony_ci		msleep(20);
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (tries < 0)
34362306a36Sopenharmony_ci		return -EIO;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	ret = adux1020_read_fifo(data, val, adux1020_modes[mode].buf_len);
34662306a36Sopenharmony_ci	if (ret < 0)
34762306a36Sopenharmony_ci		return ret;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/* Clear mode interrupt */
35062306a36Sopenharmony_ci	ret = regmap_write(data->regmap, ADUX1020_REG_INT_STATUS,
35162306a36Sopenharmony_ci			   (~adux1020_modes[mode].int_en));
35262306a36Sopenharmony_ci	if (ret < 0)
35362306a36Sopenharmony_ci		return ret;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* Disable mode interrupts */
35662306a36Sopenharmony_ci	return regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
35762306a36Sopenharmony_ci				  ADUX1020_MODE_INT_MASK,
35862306a36Sopenharmony_ci				  ADUX1020_MODE_INT_DISABLE);
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic int adux1020_read_raw(struct iio_dev *indio_dev,
36262306a36Sopenharmony_ci			     struct iio_chan_spec const *chan,
36362306a36Sopenharmony_ci			     int *val, int *val2, long mask)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct adux1020_data *data = iio_priv(indio_dev);
36662306a36Sopenharmony_ci	u16 buf[3];
36762306a36Sopenharmony_ci	int ret = -EINVAL;
36862306a36Sopenharmony_ci	unsigned int regval;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	mutex_lock(&data->lock);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	switch (mask) {
37362306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
37462306a36Sopenharmony_ci		switch (chan->type) {
37562306a36Sopenharmony_ci		case IIO_PROXIMITY:
37662306a36Sopenharmony_ci			ret = adux1020_set_mode(data, ADUX1020_MODE_PROX_I);
37762306a36Sopenharmony_ci			if (ret < 0)
37862306a36Sopenharmony_ci				goto fail;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci			ret = adux1020_measure(data, ADUX1020_MODE_PROX_I, buf);
38162306a36Sopenharmony_ci			if (ret < 0)
38262306a36Sopenharmony_ci				goto fail;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci			*val = buf[0];
38562306a36Sopenharmony_ci			ret = IIO_VAL_INT;
38662306a36Sopenharmony_ci			break;
38762306a36Sopenharmony_ci		default:
38862306a36Sopenharmony_ci			break;
38962306a36Sopenharmony_ci		}
39062306a36Sopenharmony_ci		break;
39162306a36Sopenharmony_ci	case IIO_CHAN_INFO_PROCESSED:
39262306a36Sopenharmony_ci		switch (chan->type) {
39362306a36Sopenharmony_ci		case IIO_CURRENT:
39462306a36Sopenharmony_ci			ret = regmap_read(data->regmap,
39562306a36Sopenharmony_ci					  ADUX1020_REG_LED_CURRENT, &regval);
39662306a36Sopenharmony_ci			if (ret < 0)
39762306a36Sopenharmony_ci				goto fail;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci			regval = regval & ADUX1020_LED_CURRENT_MASK;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci			*val = adux1020_led_currents[regval][0];
40262306a36Sopenharmony_ci			*val2 = adux1020_led_currents[regval][1];
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci			ret = IIO_VAL_INT_PLUS_MICRO;
40562306a36Sopenharmony_ci			break;
40662306a36Sopenharmony_ci		default:
40762306a36Sopenharmony_ci			break;
40862306a36Sopenharmony_ci		}
40962306a36Sopenharmony_ci		break;
41062306a36Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
41162306a36Sopenharmony_ci		switch (chan->type) {
41262306a36Sopenharmony_ci		case IIO_PROXIMITY:
41362306a36Sopenharmony_ci			ret = regmap_read(data->regmap, ADUX1020_REG_FREQUENCY,
41462306a36Sopenharmony_ci					  &regval);
41562306a36Sopenharmony_ci			if (ret < 0)
41662306a36Sopenharmony_ci				goto fail;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci			regval = FIELD_GET(ADUX1020_PROX_FREQ_MASK, regval);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci			*val = adux1020_rates[regval][0];
42162306a36Sopenharmony_ci			*val2 = adux1020_rates[regval][1];
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci			ret = IIO_VAL_INT_PLUS_MICRO;
42462306a36Sopenharmony_ci			break;
42562306a36Sopenharmony_ci		default:
42662306a36Sopenharmony_ci			break;
42762306a36Sopenharmony_ci		}
42862306a36Sopenharmony_ci		break;
42962306a36Sopenharmony_ci	default:
43062306a36Sopenharmony_ci		break;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cifail:
43462306a36Sopenharmony_ci	mutex_unlock(&data->lock);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return ret;
43762306a36Sopenharmony_ci};
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic inline int adux1020_find_index(const int array[][2], int count, int val,
44062306a36Sopenharmony_ci				      int val2)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	int i;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	for (i = 0; i < count; i++)
44562306a36Sopenharmony_ci		if (val == array[i][0] && val2 == array[i][1])
44662306a36Sopenharmony_ci			return i;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return -EINVAL;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic int adux1020_write_raw(struct iio_dev *indio_dev,
45262306a36Sopenharmony_ci			      struct iio_chan_spec const *chan,
45362306a36Sopenharmony_ci			      int val, int val2, long mask)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	struct adux1020_data *data = iio_priv(indio_dev);
45662306a36Sopenharmony_ci	int i, ret = -EINVAL;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	mutex_lock(&data->lock);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	switch (mask) {
46162306a36Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
46262306a36Sopenharmony_ci		if (chan->type == IIO_PROXIMITY) {
46362306a36Sopenharmony_ci			i = adux1020_find_index(adux1020_rates,
46462306a36Sopenharmony_ci						ARRAY_SIZE(adux1020_rates),
46562306a36Sopenharmony_ci						val, val2);
46662306a36Sopenharmony_ci			if (i < 0) {
46762306a36Sopenharmony_ci				ret = i;
46862306a36Sopenharmony_ci				goto fail;
46962306a36Sopenharmony_ci			}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci			ret = regmap_update_bits(data->regmap,
47262306a36Sopenharmony_ci						 ADUX1020_REG_FREQUENCY,
47362306a36Sopenharmony_ci						 ADUX1020_PROX_FREQ_MASK,
47462306a36Sopenharmony_ci						 ADUX1020_PROX_FREQ(i));
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci		break;
47762306a36Sopenharmony_ci	case IIO_CHAN_INFO_PROCESSED:
47862306a36Sopenharmony_ci		if (chan->type == IIO_CURRENT) {
47962306a36Sopenharmony_ci			i = adux1020_find_index(adux1020_led_currents,
48062306a36Sopenharmony_ci					ARRAY_SIZE(adux1020_led_currents),
48162306a36Sopenharmony_ci					val, val2);
48262306a36Sopenharmony_ci			if (i < 0) {
48362306a36Sopenharmony_ci				ret = i;
48462306a36Sopenharmony_ci				goto fail;
48562306a36Sopenharmony_ci			}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci			ret = regmap_update_bits(data->regmap,
48862306a36Sopenharmony_ci						 ADUX1020_REG_LED_CURRENT,
48962306a36Sopenharmony_ci						 ADUX1020_LED_CURRENT_MASK, i);
49062306a36Sopenharmony_ci		}
49162306a36Sopenharmony_ci		break;
49262306a36Sopenharmony_ci	default:
49362306a36Sopenharmony_ci		break;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cifail:
49762306a36Sopenharmony_ci	mutex_unlock(&data->lock);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	return ret;
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic int adux1020_write_event_config(struct iio_dev *indio_dev,
50362306a36Sopenharmony_ci				       const struct iio_chan_spec *chan,
50462306a36Sopenharmony_ci				       enum iio_event_type type,
50562306a36Sopenharmony_ci				       enum iio_event_direction dir, int state)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct adux1020_data *data = iio_priv(indio_dev);
50862306a36Sopenharmony_ci	int ret, mask;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	mutex_lock(&data->lock);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	ret = regmap_write(data->regmap, ADUX1020_REG_INT_ENABLE,
51362306a36Sopenharmony_ci			   ADUX1020_INT_ENABLE);
51462306a36Sopenharmony_ci	if (ret < 0)
51562306a36Sopenharmony_ci		goto fail;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	ret = regmap_write(data->regmap, ADUX1020_REG_INT_POLARITY, 0);
51862306a36Sopenharmony_ci	if (ret < 0)
51962306a36Sopenharmony_ci		goto fail;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	switch (chan->type) {
52262306a36Sopenharmony_ci	case IIO_PROXIMITY:
52362306a36Sopenharmony_ci		if (dir == IIO_EV_DIR_RISING)
52462306a36Sopenharmony_ci			mask = ADUX1020_PROX_ON1_INT;
52562306a36Sopenharmony_ci		else
52662306a36Sopenharmony_ci			mask = ADUX1020_PROX_OFF1_INT;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci		if (state)
52962306a36Sopenharmony_ci			state = 0;
53062306a36Sopenharmony_ci		else
53162306a36Sopenharmony_ci			state = mask;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		ret = regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
53462306a36Sopenharmony_ci					 mask, state);
53562306a36Sopenharmony_ci		if (ret < 0)
53662306a36Sopenharmony_ci			goto fail;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci		/*
53962306a36Sopenharmony_ci		 * Trigger proximity interrupt when the intensity is above
54062306a36Sopenharmony_ci		 * or below threshold
54162306a36Sopenharmony_ci		 */
54262306a36Sopenharmony_ci		ret = regmap_update_bits(data->regmap, ADUX1020_REG_PROX_TYPE,
54362306a36Sopenharmony_ci					 ADUX1020_PROX_TYPE,
54462306a36Sopenharmony_ci					 ADUX1020_PROX_TYPE);
54562306a36Sopenharmony_ci		if (ret < 0)
54662306a36Sopenharmony_ci			goto fail;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		/* Set proximity mode */
54962306a36Sopenharmony_ci		ret = adux1020_set_mode(data, ADUX1020_MODE_PROX_I);
55062306a36Sopenharmony_ci		break;
55162306a36Sopenharmony_ci	default:
55262306a36Sopenharmony_ci		ret = -EINVAL;
55362306a36Sopenharmony_ci		break;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cifail:
55762306a36Sopenharmony_ci	mutex_unlock(&data->lock);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return ret;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic int adux1020_read_event_config(struct iio_dev *indio_dev,
56362306a36Sopenharmony_ci				      const struct iio_chan_spec *chan,
56462306a36Sopenharmony_ci				      enum iio_event_type type,
56562306a36Sopenharmony_ci				      enum iio_event_direction dir)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct adux1020_data *data = iio_priv(indio_dev);
56862306a36Sopenharmony_ci	int ret, mask;
56962306a36Sopenharmony_ci	unsigned int regval;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	switch (chan->type) {
57262306a36Sopenharmony_ci	case IIO_PROXIMITY:
57362306a36Sopenharmony_ci		if (dir == IIO_EV_DIR_RISING)
57462306a36Sopenharmony_ci			mask = ADUX1020_PROX_ON1_INT;
57562306a36Sopenharmony_ci		else
57662306a36Sopenharmony_ci			mask = ADUX1020_PROX_OFF1_INT;
57762306a36Sopenharmony_ci		break;
57862306a36Sopenharmony_ci	default:
57962306a36Sopenharmony_ci		return -EINVAL;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	ret = regmap_read(data->regmap, ADUX1020_REG_INT_MASK, &regval);
58362306a36Sopenharmony_ci	if (ret < 0)
58462306a36Sopenharmony_ci		return ret;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	return !(regval & mask);
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_cistatic int adux1020_read_thresh(struct iio_dev *indio_dev,
59062306a36Sopenharmony_ci				const struct iio_chan_spec *chan,
59162306a36Sopenharmony_ci				enum iio_event_type type,
59262306a36Sopenharmony_ci				enum iio_event_direction dir,
59362306a36Sopenharmony_ci				enum iio_event_info info, int *val, int *val2)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	struct adux1020_data *data = iio_priv(indio_dev);
59662306a36Sopenharmony_ci	u8 reg;
59762306a36Sopenharmony_ci	int ret;
59862306a36Sopenharmony_ci	unsigned int regval;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	switch (chan->type) {
60162306a36Sopenharmony_ci	case IIO_PROXIMITY:
60262306a36Sopenharmony_ci		if (dir == IIO_EV_DIR_RISING)
60362306a36Sopenharmony_ci			reg = ADUX1020_REG_PROX_TH_ON1;
60462306a36Sopenharmony_ci		else
60562306a36Sopenharmony_ci			reg = ADUX1020_REG_PROX_TH_OFF1;
60662306a36Sopenharmony_ci		break;
60762306a36Sopenharmony_ci	default:
60862306a36Sopenharmony_ci		return -EINVAL;
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	ret = regmap_read(data->regmap, reg, &regval);
61262306a36Sopenharmony_ci	if (ret < 0)
61362306a36Sopenharmony_ci		return ret;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	*val = regval;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	return IIO_VAL_INT;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cistatic int adux1020_write_thresh(struct iio_dev *indio_dev,
62162306a36Sopenharmony_ci				 const struct iio_chan_spec *chan,
62262306a36Sopenharmony_ci				 enum iio_event_type type,
62362306a36Sopenharmony_ci				 enum iio_event_direction dir,
62462306a36Sopenharmony_ci				 enum iio_event_info info, int val, int val2)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	struct adux1020_data *data = iio_priv(indio_dev);
62762306a36Sopenharmony_ci	u8 reg;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	switch (chan->type) {
63062306a36Sopenharmony_ci	case IIO_PROXIMITY:
63162306a36Sopenharmony_ci		if (dir == IIO_EV_DIR_RISING)
63262306a36Sopenharmony_ci			reg = ADUX1020_REG_PROX_TH_ON1;
63362306a36Sopenharmony_ci		else
63462306a36Sopenharmony_ci			reg = ADUX1020_REG_PROX_TH_OFF1;
63562306a36Sopenharmony_ci		break;
63662306a36Sopenharmony_ci	default:
63762306a36Sopenharmony_ci		return -EINVAL;
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	/* Full scale threshold value is 0-65535  */
64162306a36Sopenharmony_ci	if (val < 0 || val > 65535)
64262306a36Sopenharmony_ci		return -EINVAL;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	return regmap_write(data->regmap, reg, val);
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic const struct iio_event_spec adux1020_proximity_event[] = {
64862306a36Sopenharmony_ci	{
64962306a36Sopenharmony_ci		.type = IIO_EV_TYPE_THRESH,
65062306a36Sopenharmony_ci		.dir = IIO_EV_DIR_RISING,
65162306a36Sopenharmony_ci		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
65262306a36Sopenharmony_ci			BIT(IIO_EV_INFO_ENABLE),
65362306a36Sopenharmony_ci	},
65462306a36Sopenharmony_ci	{
65562306a36Sopenharmony_ci		.type = IIO_EV_TYPE_THRESH,
65662306a36Sopenharmony_ci		.dir = IIO_EV_DIR_FALLING,
65762306a36Sopenharmony_ci		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
65862306a36Sopenharmony_ci			BIT(IIO_EV_INFO_ENABLE),
65962306a36Sopenharmony_ci	},
66062306a36Sopenharmony_ci};
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic const struct iio_chan_spec adux1020_channels[] = {
66362306a36Sopenharmony_ci	{
66462306a36Sopenharmony_ci		.type = IIO_PROXIMITY,
66562306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
66662306a36Sopenharmony_ci				      BIT(IIO_CHAN_INFO_SAMP_FREQ),
66762306a36Sopenharmony_ci		.event_spec = adux1020_proximity_event,
66862306a36Sopenharmony_ci		.num_event_specs = ARRAY_SIZE(adux1020_proximity_event),
66962306a36Sopenharmony_ci	},
67062306a36Sopenharmony_ci	{
67162306a36Sopenharmony_ci		.type = IIO_CURRENT,
67262306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
67362306a36Sopenharmony_ci		.extend_name = "led",
67462306a36Sopenharmony_ci		.output = 1,
67562306a36Sopenharmony_ci	},
67662306a36Sopenharmony_ci};
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
67962306a36Sopenharmony_ci		      "0.1 0.2 0.5 1 2 5 10 20 50 100 190 450 820 1400");
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic struct attribute *adux1020_attributes[] = {
68262306a36Sopenharmony_ci	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
68362306a36Sopenharmony_ci	NULL
68462306a36Sopenharmony_ci};
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cistatic const struct attribute_group adux1020_attribute_group = {
68762306a36Sopenharmony_ci	.attrs = adux1020_attributes,
68862306a36Sopenharmony_ci};
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic const struct iio_info adux1020_info = {
69162306a36Sopenharmony_ci	.attrs = &adux1020_attribute_group,
69262306a36Sopenharmony_ci	.read_raw = adux1020_read_raw,
69362306a36Sopenharmony_ci	.write_raw = adux1020_write_raw,
69462306a36Sopenharmony_ci	.read_event_config = adux1020_read_event_config,
69562306a36Sopenharmony_ci	.write_event_config = adux1020_write_event_config,
69662306a36Sopenharmony_ci	.read_event_value = adux1020_read_thresh,
69762306a36Sopenharmony_ci	.write_event_value = adux1020_write_thresh,
69862306a36Sopenharmony_ci};
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic irqreturn_t adux1020_interrupt_handler(int irq, void *private)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct iio_dev *indio_dev = private;
70362306a36Sopenharmony_ci	struct adux1020_data *data = iio_priv(indio_dev);
70462306a36Sopenharmony_ci	int ret, status;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	ret = regmap_read(data->regmap, ADUX1020_REG_INT_STATUS, &status);
70762306a36Sopenharmony_ci	if (ret < 0)
70862306a36Sopenharmony_ci		return IRQ_HANDLED;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	status &= ADUX1020_MODE_INT_STATUS_MASK;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	if (status & ADUX1020_INT_PROX_ON1) {
71362306a36Sopenharmony_ci		iio_push_event(indio_dev,
71462306a36Sopenharmony_ci			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
71562306a36Sopenharmony_ci						    IIO_EV_TYPE_THRESH,
71662306a36Sopenharmony_ci						    IIO_EV_DIR_RISING),
71762306a36Sopenharmony_ci			       iio_get_time_ns(indio_dev));
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (status & ADUX1020_INT_PROX_OFF1) {
72162306a36Sopenharmony_ci		iio_push_event(indio_dev,
72262306a36Sopenharmony_ci			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
72362306a36Sopenharmony_ci						    IIO_EV_TYPE_THRESH,
72462306a36Sopenharmony_ci						    IIO_EV_DIR_FALLING),
72562306a36Sopenharmony_ci			       iio_get_time_ns(indio_dev));
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	regmap_update_bits(data->regmap, ADUX1020_REG_INT_STATUS,
72962306a36Sopenharmony_ci			   ADUX1020_MODE_INT_MASK, ADUX1020_INT_CLEAR);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	return IRQ_HANDLED;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic int adux1020_chip_init(struct adux1020_data *data)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	struct i2c_client *client = data->client;
73762306a36Sopenharmony_ci	int ret;
73862306a36Sopenharmony_ci	unsigned int val;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	ret = regmap_read(data->regmap, ADUX1020_REG_CHIP_ID, &val);
74162306a36Sopenharmony_ci	if (ret < 0)
74262306a36Sopenharmony_ci		return ret;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	if ((val & ADUX1020_CHIP_ID_MASK) != ADUX1020_CHIP_ID) {
74562306a36Sopenharmony_ci		dev_err(&client->dev, "invalid chip id 0x%04x\n", val);
74662306a36Sopenharmony_ci		return -ENODEV;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	dev_dbg(&client->dev, "Detected ADUX1020 with chip id: 0x%04x\n", val);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	ret = regmap_update_bits(data->regmap, ADUX1020_REG_SW_RESET,
75262306a36Sopenharmony_ci				 ADUX1020_SW_RESET, ADUX1020_SW_RESET);
75362306a36Sopenharmony_ci	if (ret < 0)
75462306a36Sopenharmony_ci		return ret;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	/* Load default configuration */
75762306a36Sopenharmony_ci	ret = regmap_multi_reg_write(data->regmap, adux1020_def_conf,
75862306a36Sopenharmony_ci				     ARRAY_SIZE(adux1020_def_conf));
75962306a36Sopenharmony_ci	if (ret < 0)
76062306a36Sopenharmony_ci		return ret;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	ret = adux1020_flush_fifo(data);
76362306a36Sopenharmony_ci	if (ret < 0)
76462306a36Sopenharmony_ci		return ret;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	/* Use LED_IREF for proximity mode */
76762306a36Sopenharmony_ci	ret = regmap_update_bits(data->regmap, ADUX1020_REG_LED_CURRENT,
76862306a36Sopenharmony_ci				 ADUX1020_LED_PIREF_EN, 0);
76962306a36Sopenharmony_ci	if (ret < 0)
77062306a36Sopenharmony_ci		return ret;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	/* Mask all interrupts */
77362306a36Sopenharmony_ci	return regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
77462306a36Sopenharmony_ci			   ADUX1020_MODE_INT_MASK, ADUX1020_MODE_INT_DISABLE);
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic int adux1020_probe(struct i2c_client *client)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	struct adux1020_data *data;
78062306a36Sopenharmony_ci	struct iio_dev *indio_dev;
78162306a36Sopenharmony_ci	int ret;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
78462306a36Sopenharmony_ci	if (!indio_dev)
78562306a36Sopenharmony_ci		return -ENOMEM;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	indio_dev->info = &adux1020_info;
78862306a36Sopenharmony_ci	indio_dev->name = ADUX1020_DRV_NAME;
78962306a36Sopenharmony_ci	indio_dev->channels = adux1020_channels;
79062306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(adux1020_channels);
79162306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	data = iio_priv(indio_dev);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	data->regmap = devm_regmap_init_i2c(client, &adux1020_regmap_config);
79662306a36Sopenharmony_ci	if (IS_ERR(data->regmap)) {
79762306a36Sopenharmony_ci		dev_err(&client->dev, "regmap initialization failed.\n");
79862306a36Sopenharmony_ci		return PTR_ERR(data->regmap);
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	data->client = client;
80262306a36Sopenharmony_ci	data->indio_dev = indio_dev;
80362306a36Sopenharmony_ci	mutex_init(&data->lock);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	ret = adux1020_chip_init(data);
80662306a36Sopenharmony_ci	if (ret)
80762306a36Sopenharmony_ci		return ret;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (client->irq) {
81062306a36Sopenharmony_ci		ret = devm_request_threaded_irq(&client->dev, client->irq,
81162306a36Sopenharmony_ci					NULL, adux1020_interrupt_handler,
81262306a36Sopenharmony_ci					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
81362306a36Sopenharmony_ci					ADUX1020_DRV_NAME, indio_dev);
81462306a36Sopenharmony_ci		if (ret) {
81562306a36Sopenharmony_ci			dev_err(&client->dev, "irq request error %d\n", -ret);
81662306a36Sopenharmony_ci			return ret;
81762306a36Sopenharmony_ci		}
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	return devm_iio_device_register(&client->dev, indio_dev);
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic const struct i2c_device_id adux1020_id[] = {
82462306a36Sopenharmony_ci	{ "adux1020", 0 },
82562306a36Sopenharmony_ci	{}
82662306a36Sopenharmony_ci};
82762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adux1020_id);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic const struct of_device_id adux1020_of_match[] = {
83062306a36Sopenharmony_ci	{ .compatible = "adi,adux1020" },
83162306a36Sopenharmony_ci	{ }
83262306a36Sopenharmony_ci};
83362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, adux1020_of_match);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_cistatic struct i2c_driver adux1020_driver = {
83662306a36Sopenharmony_ci	.driver = {
83762306a36Sopenharmony_ci		.name	= ADUX1020_DRV_NAME,
83862306a36Sopenharmony_ci		.of_match_table = adux1020_of_match,
83962306a36Sopenharmony_ci	},
84062306a36Sopenharmony_ci	.probe		= adux1020_probe,
84162306a36Sopenharmony_ci	.id_table	= adux1020_id,
84262306a36Sopenharmony_ci};
84362306a36Sopenharmony_cimodule_i2c_driver(adux1020_driver);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ciMODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
84662306a36Sopenharmony_ciMODULE_DESCRIPTION("ADUX1020 photometric sensor");
84762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
848