xref: /openbmc/linux/drivers/iio/light/adux1020.c (revision 7cf15f42)
135654354SManivannan Sadhasivam // SPDX-License-Identifier: GPL-2.0+
235654354SManivannan Sadhasivam /*
335654354SManivannan Sadhasivam  * adux1020.c - Support for Analog Devices ADUX1020 photometric sensor
435654354SManivannan Sadhasivam  *
535654354SManivannan Sadhasivam  * Copyright (C) 2019 Linaro Ltd.
635654354SManivannan Sadhasivam  * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
735654354SManivannan Sadhasivam  *
835654354SManivannan Sadhasivam  * TODO: Triggered buffer support
935654354SManivannan Sadhasivam  */
1035654354SManivannan Sadhasivam 
1135654354SManivannan Sadhasivam #include <linux/bitfield.h>
1235654354SManivannan Sadhasivam #include <linux/delay.h>
1335654354SManivannan Sadhasivam #include <linux/err.h>
1435654354SManivannan Sadhasivam #include <linux/i2c.h>
1535654354SManivannan Sadhasivam #include <linux/init.h>
1635654354SManivannan Sadhasivam #include <linux/interrupt.h>
1735654354SManivannan Sadhasivam #include <linux/irq.h>
1835654354SManivannan Sadhasivam #include <linux/module.h>
1935654354SManivannan Sadhasivam #include <linux/mutex.h>
2035654354SManivannan Sadhasivam #include <linux/regmap.h>
2135654354SManivannan Sadhasivam 
2235654354SManivannan Sadhasivam #include <linux/iio/iio.h>
2335654354SManivannan Sadhasivam #include <linux/iio/sysfs.h>
2435654354SManivannan Sadhasivam #include <linux/iio/events.h>
2535654354SManivannan Sadhasivam 
2635654354SManivannan Sadhasivam #define ADUX1020_REGMAP_NAME		"adux1020_regmap"
2735654354SManivannan Sadhasivam #define ADUX1020_DRV_NAME		"adux1020"
2835654354SManivannan Sadhasivam 
2935654354SManivannan Sadhasivam /* System registers */
3035654354SManivannan Sadhasivam #define ADUX1020_REG_CHIP_ID		0x08
3135654354SManivannan Sadhasivam #define ADUX1020_REG_SLAVE_ADDRESS	0x09
3235654354SManivannan Sadhasivam 
3335654354SManivannan Sadhasivam #define ADUX1020_REG_SW_RESET		0x0f
3435654354SManivannan Sadhasivam #define ADUX1020_REG_INT_ENABLE		0x1c
3535654354SManivannan Sadhasivam #define ADUX1020_REG_INT_POLARITY	0x1d
3635654354SManivannan Sadhasivam #define ADUX1020_REG_PROX_TH_ON1	0x2a
3735654354SManivannan Sadhasivam #define ADUX1020_REG_PROX_TH_OFF1	0x2b
3835654354SManivannan Sadhasivam #define	ADUX1020_REG_PROX_TYPE		0x2f
3935654354SManivannan Sadhasivam #define	ADUX1020_REG_TEST_MODES_3	0x32
4035654354SManivannan Sadhasivam #define	ADUX1020_REG_FORCE_MODE		0x33
4135654354SManivannan Sadhasivam #define	ADUX1020_REG_FREQUENCY		0x40
4235654354SManivannan Sadhasivam #define ADUX1020_REG_LED_CURRENT	0x41
4335654354SManivannan Sadhasivam #define	ADUX1020_REG_OP_MODE		0x45
4435654354SManivannan Sadhasivam #define	ADUX1020_REG_INT_MASK		0x48
4535654354SManivannan Sadhasivam #define	ADUX1020_REG_INT_STATUS		0x49
4635654354SManivannan Sadhasivam #define	ADUX1020_REG_DATA_BUFFER	0x60
4735654354SManivannan Sadhasivam 
4835654354SManivannan Sadhasivam /* Chip ID bits */
4935654354SManivannan Sadhasivam #define ADUX1020_CHIP_ID_MASK		GENMASK(11, 0)
5035654354SManivannan Sadhasivam #define ADUX1020_CHIP_ID		0x03fc
5135654354SManivannan Sadhasivam 
5235654354SManivannan Sadhasivam #define ADUX1020_SW_RESET		BIT(1)
5335654354SManivannan Sadhasivam #define ADUX1020_FIFO_FLUSH		BIT(15)
5435654354SManivannan Sadhasivam #define ADUX1020_OP_MODE_MASK		GENMASK(3, 0)
5535654354SManivannan Sadhasivam #define ADUX1020_DATA_OUT_MODE_MASK	GENMASK(7, 4)
5635654354SManivannan Sadhasivam #define ADUX1020_DATA_OUT_PROX_I	FIELD_PREP(ADUX1020_DATA_OUT_MODE_MASK, 1)
5735654354SManivannan Sadhasivam 
5835654354SManivannan Sadhasivam #define ADUX1020_MODE_INT_MASK		GENMASK(7, 0)
5935654354SManivannan Sadhasivam #define ADUX1020_INT_ENABLE		0x2094
6035654354SManivannan Sadhasivam #define ADUX1020_INT_DISABLE		0x2090
6135654354SManivannan Sadhasivam #define ADUX1020_PROX_INT_ENABLE	0x00f0
6235654354SManivannan Sadhasivam #define ADUX1020_PROX_ON1_INT		BIT(0)
6335654354SManivannan Sadhasivam #define ADUX1020_PROX_OFF1_INT		BIT(1)
6435654354SManivannan Sadhasivam #define ADUX1020_FIFO_INT_ENABLE	0x7f
6535654354SManivannan Sadhasivam #define ADUX1020_MODE_INT_DISABLE	0xff
6635654354SManivannan Sadhasivam #define ADUX1020_MODE_INT_STATUS_MASK	GENMASK(7, 0)
6735654354SManivannan Sadhasivam #define ADUX1020_FIFO_STATUS_MASK	GENMASK(15, 8)
6835654354SManivannan Sadhasivam #define ADUX1020_INT_CLEAR		0xff
6935654354SManivannan Sadhasivam #define ADUX1020_PROX_TYPE		BIT(15)
7035654354SManivannan Sadhasivam 
7135654354SManivannan Sadhasivam #define ADUX1020_INT_PROX_ON1		BIT(0)
7235654354SManivannan Sadhasivam #define ADUX1020_INT_PROX_OFF1		BIT(1)
7335654354SManivannan Sadhasivam 
7435654354SManivannan Sadhasivam #define ADUX1020_FORCE_CLOCK_ON		0x0f4f
7535654354SManivannan Sadhasivam #define ADUX1020_FORCE_CLOCK_RESET	0x0040
7635654354SManivannan Sadhasivam #define ADUX1020_ACTIVE_4_STATE		0x0008
7735654354SManivannan Sadhasivam 
7835654354SManivannan Sadhasivam #define ADUX1020_PROX_FREQ_MASK		GENMASK(7, 4)
7935654354SManivannan Sadhasivam #define ADUX1020_PROX_FREQ(x)		FIELD_PREP(ADUX1020_PROX_FREQ_MASK, x)
8035654354SManivannan Sadhasivam 
8135654354SManivannan Sadhasivam #define ADUX1020_LED_CURRENT_MASK	GENMASK(3, 0)
8235654354SManivannan Sadhasivam #define ADUX1020_LED_PIREF_EN		BIT(12)
8335654354SManivannan Sadhasivam 
8435654354SManivannan Sadhasivam /* Operating modes */
8535654354SManivannan Sadhasivam enum adux1020_op_modes {
8635654354SManivannan Sadhasivam 	ADUX1020_MODE_STANDBY,
8735654354SManivannan Sadhasivam 	ADUX1020_MODE_PROX_I,
8835654354SManivannan Sadhasivam 	ADUX1020_MODE_PROX_XY,
8935654354SManivannan Sadhasivam 	ADUX1020_MODE_GEST,
9035654354SManivannan Sadhasivam 	ADUX1020_MODE_SAMPLE,
9135654354SManivannan Sadhasivam 	ADUX1020_MODE_FORCE = 0x0e,
9235654354SManivannan Sadhasivam 	ADUX1020_MODE_IDLE = 0x0f,
9335654354SManivannan Sadhasivam };
9435654354SManivannan Sadhasivam 
9535654354SManivannan Sadhasivam struct adux1020_data {
9635654354SManivannan Sadhasivam 	struct i2c_client *client;
9735654354SManivannan Sadhasivam 	struct iio_dev *indio_dev;
9835654354SManivannan Sadhasivam 	struct mutex lock;
9935654354SManivannan Sadhasivam 	struct regmap *regmap;
10035654354SManivannan Sadhasivam };
10135654354SManivannan Sadhasivam 
10235654354SManivannan Sadhasivam struct adux1020_mode_data {
10335654354SManivannan Sadhasivam 	u8 bytes;
10435654354SManivannan Sadhasivam 	u8 buf_len;
10535654354SManivannan Sadhasivam 	u16 int_en;
10635654354SManivannan Sadhasivam };
10735654354SManivannan Sadhasivam 
10835654354SManivannan Sadhasivam static const struct adux1020_mode_data adux1020_modes[] = {
10935654354SManivannan Sadhasivam 	[ADUX1020_MODE_PROX_I] = {
11035654354SManivannan Sadhasivam 		.bytes = 2,
11135654354SManivannan Sadhasivam 		.buf_len = 1,
11235654354SManivannan Sadhasivam 		.int_en = ADUX1020_PROX_INT_ENABLE,
11335654354SManivannan Sadhasivam 	},
11435654354SManivannan Sadhasivam };
11535654354SManivannan Sadhasivam 
11635654354SManivannan Sadhasivam static const struct regmap_config adux1020_regmap_config = {
11735654354SManivannan Sadhasivam 	.name = ADUX1020_REGMAP_NAME,
11835654354SManivannan Sadhasivam 	.reg_bits = 8,
11935654354SManivannan Sadhasivam 	.val_bits = 16,
12035654354SManivannan Sadhasivam 	.max_register = 0x6F,
12135654354SManivannan Sadhasivam 	.cache_type = REGCACHE_NONE,
12235654354SManivannan Sadhasivam };
12335654354SManivannan Sadhasivam 
12435654354SManivannan Sadhasivam static const struct reg_sequence adux1020_def_conf[] = {
12535654354SManivannan Sadhasivam 	{ 0x000c, 0x000f },
12635654354SManivannan Sadhasivam 	{ 0x0010, 0x1010 },
12735654354SManivannan Sadhasivam 	{ 0x0011, 0x004c },
12835654354SManivannan Sadhasivam 	{ 0x0012, 0x5f0c },
12935654354SManivannan Sadhasivam 	{ 0x0013, 0xada5 },
13035654354SManivannan Sadhasivam 	{ 0x0014, 0x0080 },
13135654354SManivannan Sadhasivam 	{ 0x0015, 0x0000 },
13235654354SManivannan Sadhasivam 	{ 0x0016, 0x0600 },
13335654354SManivannan Sadhasivam 	{ 0x0017, 0x0000 },
13435654354SManivannan Sadhasivam 	{ 0x0018, 0x2693 },
13535654354SManivannan Sadhasivam 	{ 0x0019, 0x0004 },
13635654354SManivannan Sadhasivam 	{ 0x001a, 0x4280 },
13735654354SManivannan Sadhasivam 	{ 0x001b, 0x0060 },
13835654354SManivannan Sadhasivam 	{ 0x001c, 0x2094 },
13935654354SManivannan Sadhasivam 	{ 0x001d, 0x0020 },
14035654354SManivannan Sadhasivam 	{ 0x001e, 0x0001 },
14135654354SManivannan Sadhasivam 	{ 0x001f, 0x0100 },
14235654354SManivannan Sadhasivam 	{ 0x0020, 0x0320 },
14335654354SManivannan Sadhasivam 	{ 0x0021, 0x0A13 },
14435654354SManivannan Sadhasivam 	{ 0x0022, 0x0320 },
14535654354SManivannan Sadhasivam 	{ 0x0023, 0x0113 },
14635654354SManivannan Sadhasivam 	{ 0x0024, 0x0000 },
14735654354SManivannan Sadhasivam 	{ 0x0025, 0x2412 },
14835654354SManivannan Sadhasivam 	{ 0x0026, 0x2412 },
14935654354SManivannan Sadhasivam 	{ 0x0027, 0x0022 },
15035654354SManivannan Sadhasivam 	{ 0x0028, 0x0000 },
15135654354SManivannan Sadhasivam 	{ 0x0029, 0x0300 },
15235654354SManivannan Sadhasivam 	{ 0x002a, 0x0700 },
15335654354SManivannan Sadhasivam 	{ 0x002b, 0x0600 },
15435654354SManivannan Sadhasivam 	{ 0x002c, 0x6000 },
15535654354SManivannan Sadhasivam 	{ 0x002d, 0x4000 },
15635654354SManivannan Sadhasivam 	{ 0x002e, 0x0000 },
15735654354SManivannan Sadhasivam 	{ 0x002f, 0x0000 },
15835654354SManivannan Sadhasivam 	{ 0x0030, 0x0000 },
15935654354SManivannan Sadhasivam 	{ 0x0031, 0x0000 },
16035654354SManivannan Sadhasivam 	{ 0x0032, 0x0040 },
16135654354SManivannan Sadhasivam 	{ 0x0033, 0x0008 },
16235654354SManivannan Sadhasivam 	{ 0x0034, 0xE400 },
16335654354SManivannan Sadhasivam 	{ 0x0038, 0x8080 },
16435654354SManivannan Sadhasivam 	{ 0x0039, 0x8080 },
16535654354SManivannan Sadhasivam 	{ 0x003a, 0x2000 },
16635654354SManivannan Sadhasivam 	{ 0x003b, 0x1f00 },
16735654354SManivannan Sadhasivam 	{ 0x003c, 0x2000 },
16835654354SManivannan Sadhasivam 	{ 0x003d, 0x2000 },
16935654354SManivannan Sadhasivam 	{ 0x003e, 0x0000 },
17035654354SManivannan Sadhasivam 	{ 0x0040, 0x8069 },
17135654354SManivannan Sadhasivam 	{ 0x0041, 0x1f2f },
17235654354SManivannan Sadhasivam 	{ 0x0042, 0x4000 },
17335654354SManivannan Sadhasivam 	{ 0x0043, 0x0000 },
17435654354SManivannan Sadhasivam 	{ 0x0044, 0x0008 },
17535654354SManivannan Sadhasivam 	{ 0x0046, 0x0000 },
17635654354SManivannan Sadhasivam 	{ 0x0048, 0x00ef },
17735654354SManivannan Sadhasivam 	{ 0x0049, 0x0000 },
17835654354SManivannan Sadhasivam 	{ 0x0045, 0x0000 },
17935654354SManivannan Sadhasivam };
18035654354SManivannan Sadhasivam 
18135654354SManivannan Sadhasivam static const int adux1020_rates[][2] = {
18235654354SManivannan Sadhasivam 	{ 0, 100000 },
18335654354SManivannan Sadhasivam 	{ 0, 200000 },
18435654354SManivannan Sadhasivam 	{ 0, 500000 },
18535654354SManivannan Sadhasivam 	{ 1, 0 },
18635654354SManivannan Sadhasivam 	{ 2, 0 },
18735654354SManivannan Sadhasivam 	{ 5, 0 },
18835654354SManivannan Sadhasivam 	{ 10, 0 },
18935654354SManivannan Sadhasivam 	{ 20, 0 },
19035654354SManivannan Sadhasivam 	{ 50, 0 },
19135654354SManivannan Sadhasivam 	{ 100, 0 },
19235654354SManivannan Sadhasivam 	{ 190, 0 },
19335654354SManivannan Sadhasivam 	{ 450, 0 },
19435654354SManivannan Sadhasivam 	{ 820, 0 },
19535654354SManivannan Sadhasivam 	{ 1400, 0 },
19635654354SManivannan Sadhasivam };
19735654354SManivannan Sadhasivam 
19835654354SManivannan Sadhasivam static const int adux1020_led_currents[][2] = {
19935654354SManivannan Sadhasivam 	{ 0, 25000 },
20035654354SManivannan Sadhasivam 	{ 0, 40000 },
20135654354SManivannan Sadhasivam 	{ 0, 55000 },
20235654354SManivannan Sadhasivam 	{ 0, 70000 },
20335654354SManivannan Sadhasivam 	{ 0, 85000 },
20435654354SManivannan Sadhasivam 	{ 0, 100000 },
20535654354SManivannan Sadhasivam 	{ 0, 115000 },
20635654354SManivannan Sadhasivam 	{ 0, 130000 },
20735654354SManivannan Sadhasivam 	{ 0, 145000 },
20835654354SManivannan Sadhasivam 	{ 0, 160000 },
20935654354SManivannan Sadhasivam 	{ 0, 175000 },
21035654354SManivannan Sadhasivam 	{ 0, 190000 },
21135654354SManivannan Sadhasivam 	{ 0, 205000 },
21235654354SManivannan Sadhasivam 	{ 0, 220000 },
21335654354SManivannan Sadhasivam 	{ 0, 235000 },
21435654354SManivannan Sadhasivam 	{ 0, 250000 },
21535654354SManivannan Sadhasivam };
21635654354SManivannan Sadhasivam 
adux1020_flush_fifo(struct adux1020_data * data)21735654354SManivannan Sadhasivam static int adux1020_flush_fifo(struct adux1020_data *data)
21835654354SManivannan Sadhasivam {
21935654354SManivannan Sadhasivam 	int ret;
22035654354SManivannan Sadhasivam 
22135654354SManivannan Sadhasivam 	/* Force Idle mode */
22235654354SManivannan Sadhasivam 	ret = regmap_write(data->regmap, ADUX1020_REG_FORCE_MODE,
22335654354SManivannan Sadhasivam 			   ADUX1020_ACTIVE_4_STATE);
22435654354SManivannan Sadhasivam 	if (ret < 0)
22535654354SManivannan Sadhasivam 		return ret;
22635654354SManivannan Sadhasivam 
22735654354SManivannan Sadhasivam 	ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
22835654354SManivannan Sadhasivam 				 ADUX1020_OP_MODE_MASK, ADUX1020_MODE_FORCE);
22935654354SManivannan Sadhasivam 	if (ret < 0)
23035654354SManivannan Sadhasivam 		return ret;
23135654354SManivannan Sadhasivam 
23235654354SManivannan Sadhasivam 	ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
23335654354SManivannan Sadhasivam 				 ADUX1020_OP_MODE_MASK, ADUX1020_MODE_IDLE);
23435654354SManivannan Sadhasivam 	if (ret < 0)
23535654354SManivannan Sadhasivam 		return ret;
23635654354SManivannan Sadhasivam 
23735654354SManivannan Sadhasivam 	/* Flush FIFO */
23835654354SManivannan Sadhasivam 	ret = regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
23935654354SManivannan Sadhasivam 			   ADUX1020_FORCE_CLOCK_ON);
24035654354SManivannan Sadhasivam 	if (ret < 0)
24135654354SManivannan Sadhasivam 		return ret;
24235654354SManivannan Sadhasivam 
24335654354SManivannan Sadhasivam 	ret = regmap_write(data->regmap, ADUX1020_REG_INT_STATUS,
24435654354SManivannan Sadhasivam 			   ADUX1020_FIFO_FLUSH);
24535654354SManivannan Sadhasivam 	if (ret < 0)
24635654354SManivannan Sadhasivam 		return ret;
24735654354SManivannan Sadhasivam 
24835654354SManivannan Sadhasivam 	return regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
24935654354SManivannan Sadhasivam 			    ADUX1020_FORCE_CLOCK_RESET);
25035654354SManivannan Sadhasivam }
25135654354SManivannan Sadhasivam 
adux1020_read_fifo(struct adux1020_data * data,u16 * buf,u8 buf_len)25235654354SManivannan Sadhasivam static int adux1020_read_fifo(struct adux1020_data *data, u16 *buf, u8 buf_len)
25335654354SManivannan Sadhasivam {
25435654354SManivannan Sadhasivam 	unsigned int regval;
25535654354SManivannan Sadhasivam 	int i, ret;
25635654354SManivannan Sadhasivam 
25735654354SManivannan Sadhasivam 	/* Enable 32MHz clock */
25835654354SManivannan Sadhasivam 	ret = regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
25935654354SManivannan Sadhasivam 			   ADUX1020_FORCE_CLOCK_ON);
26035654354SManivannan Sadhasivam 	if (ret < 0)
26135654354SManivannan Sadhasivam 		return ret;
26235654354SManivannan Sadhasivam 
26335654354SManivannan Sadhasivam 	for (i = 0; i < buf_len; i++) {
26435654354SManivannan Sadhasivam 		ret = regmap_read(data->regmap, ADUX1020_REG_DATA_BUFFER,
26535654354SManivannan Sadhasivam 				  &regval);
26635654354SManivannan Sadhasivam 		if (ret < 0)
26735654354SManivannan Sadhasivam 			return ret;
26835654354SManivannan Sadhasivam 
26935654354SManivannan Sadhasivam 		buf[i] = regval;
27035654354SManivannan Sadhasivam 	}
27135654354SManivannan Sadhasivam 
27235654354SManivannan Sadhasivam 	/* Set 32MHz clock to be controlled by internal state machine */
27335654354SManivannan Sadhasivam 	return regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3,
27435654354SManivannan Sadhasivam 			    ADUX1020_FORCE_CLOCK_RESET);
27535654354SManivannan Sadhasivam }
27635654354SManivannan Sadhasivam 
adux1020_set_mode(struct adux1020_data * data,enum adux1020_op_modes mode)27735654354SManivannan Sadhasivam static int adux1020_set_mode(struct adux1020_data *data,
27835654354SManivannan Sadhasivam 			     enum adux1020_op_modes mode)
27935654354SManivannan Sadhasivam {
28035654354SManivannan Sadhasivam 	int ret;
28135654354SManivannan Sadhasivam 
28235654354SManivannan Sadhasivam 	/* Switch to standby mode before changing the mode */
28335654354SManivannan Sadhasivam 	ret = regmap_write(data->regmap, ADUX1020_REG_OP_MODE,
28435654354SManivannan Sadhasivam 			   ADUX1020_MODE_STANDBY);
28535654354SManivannan Sadhasivam 	if (ret < 0)
28635654354SManivannan Sadhasivam 		return ret;
28735654354SManivannan Sadhasivam 
28835654354SManivannan Sadhasivam 	/* Set data out and switch to the desired mode */
28935654354SManivannan Sadhasivam 	switch (mode) {
29035654354SManivannan Sadhasivam 	case ADUX1020_MODE_PROX_I:
29135654354SManivannan Sadhasivam 		ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
29235654354SManivannan Sadhasivam 					 ADUX1020_DATA_OUT_MODE_MASK,
29335654354SManivannan Sadhasivam 					 ADUX1020_DATA_OUT_PROX_I);
29435654354SManivannan Sadhasivam 		if (ret < 0)
29535654354SManivannan Sadhasivam 			return ret;
29635654354SManivannan Sadhasivam 
29735654354SManivannan Sadhasivam 		ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE,
29835654354SManivannan Sadhasivam 					 ADUX1020_OP_MODE_MASK,
29935654354SManivannan Sadhasivam 					 ADUX1020_MODE_PROX_I);
30035654354SManivannan Sadhasivam 		if (ret < 0)
30135654354SManivannan Sadhasivam 			return ret;
30235654354SManivannan Sadhasivam 		break;
30335654354SManivannan Sadhasivam 	default:
30435654354SManivannan Sadhasivam 		return -EINVAL;
30535654354SManivannan Sadhasivam 	}
30635654354SManivannan Sadhasivam 
30735654354SManivannan Sadhasivam 	return 0;
30835654354SManivannan Sadhasivam }
30935654354SManivannan Sadhasivam 
adux1020_measure(struct adux1020_data * data,enum adux1020_op_modes mode,u16 * val)31035654354SManivannan Sadhasivam static int adux1020_measure(struct adux1020_data *data,
31135654354SManivannan Sadhasivam 			    enum adux1020_op_modes mode,
31235654354SManivannan Sadhasivam 			    u16 *val)
31335654354SManivannan Sadhasivam {
31435654354SManivannan Sadhasivam 	unsigned int status;
31535654354SManivannan Sadhasivam 	int ret, tries = 50;
31635654354SManivannan Sadhasivam 
31735654354SManivannan Sadhasivam 	/* Disable INT pin as polling is going to be used */
31835654354SManivannan Sadhasivam 	ret = regmap_write(data->regmap, ADUX1020_REG_INT_ENABLE,
31935654354SManivannan Sadhasivam 			   ADUX1020_INT_DISABLE);
32035654354SManivannan Sadhasivam 	if (ret < 0)
32135654354SManivannan Sadhasivam 		return ret;
32235654354SManivannan Sadhasivam 
32335654354SManivannan Sadhasivam 	/* Enable mode interrupt */
32435654354SManivannan Sadhasivam 	ret = regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
32535654354SManivannan Sadhasivam 				 ADUX1020_MODE_INT_MASK,
32635654354SManivannan Sadhasivam 				 adux1020_modes[mode].int_en);
32735654354SManivannan Sadhasivam 	if (ret < 0)
32835654354SManivannan Sadhasivam 		return ret;
32935654354SManivannan Sadhasivam 
33035654354SManivannan Sadhasivam 	while (tries--) {
33135654354SManivannan Sadhasivam 		ret = regmap_read(data->regmap, ADUX1020_REG_INT_STATUS,
33235654354SManivannan Sadhasivam 				  &status);
33335654354SManivannan Sadhasivam 		if (ret < 0)
33435654354SManivannan Sadhasivam 			return ret;
33535654354SManivannan Sadhasivam 
33635654354SManivannan Sadhasivam 		status &= ADUX1020_FIFO_STATUS_MASK;
33735654354SManivannan Sadhasivam 		if (status >= adux1020_modes[mode].bytes)
33835654354SManivannan Sadhasivam 			break;
33935654354SManivannan Sadhasivam 		msleep(20);
34035654354SManivannan Sadhasivam 	}
34135654354SManivannan Sadhasivam 
34235654354SManivannan Sadhasivam 	if (tries < 0)
34335654354SManivannan Sadhasivam 		return -EIO;
34435654354SManivannan Sadhasivam 
34535654354SManivannan Sadhasivam 	ret = adux1020_read_fifo(data, val, adux1020_modes[mode].buf_len);
34635654354SManivannan Sadhasivam 	if (ret < 0)
34735654354SManivannan Sadhasivam 		return ret;
34835654354SManivannan Sadhasivam 
34935654354SManivannan Sadhasivam 	/* Clear mode interrupt */
35035654354SManivannan Sadhasivam 	ret = regmap_write(data->regmap, ADUX1020_REG_INT_STATUS,
35135654354SManivannan Sadhasivam 			   (~adux1020_modes[mode].int_en));
35235654354SManivannan Sadhasivam 	if (ret < 0)
35335654354SManivannan Sadhasivam 		return ret;
35435654354SManivannan Sadhasivam 
35535654354SManivannan Sadhasivam 	/* Disable mode interrupts */
35635654354SManivannan Sadhasivam 	return regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
35735654354SManivannan Sadhasivam 				  ADUX1020_MODE_INT_MASK,
35835654354SManivannan Sadhasivam 				  ADUX1020_MODE_INT_DISABLE);
35935654354SManivannan Sadhasivam }
36035654354SManivannan Sadhasivam 
adux1020_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)36135654354SManivannan Sadhasivam static int adux1020_read_raw(struct iio_dev *indio_dev,
36235654354SManivannan Sadhasivam 			     struct iio_chan_spec const *chan,
36335654354SManivannan Sadhasivam 			     int *val, int *val2, long mask)
36435654354SManivannan Sadhasivam {
36535654354SManivannan Sadhasivam 	struct adux1020_data *data = iio_priv(indio_dev);
36635654354SManivannan Sadhasivam 	u16 buf[3];
36735654354SManivannan Sadhasivam 	int ret = -EINVAL;
36835654354SManivannan Sadhasivam 	unsigned int regval;
36935654354SManivannan Sadhasivam 
37035654354SManivannan Sadhasivam 	mutex_lock(&data->lock);
37135654354SManivannan Sadhasivam 
37235654354SManivannan Sadhasivam 	switch (mask) {
37335654354SManivannan Sadhasivam 	case IIO_CHAN_INFO_RAW:
37435654354SManivannan Sadhasivam 		switch (chan->type) {
37535654354SManivannan Sadhasivam 		case IIO_PROXIMITY:
37635654354SManivannan Sadhasivam 			ret = adux1020_set_mode(data, ADUX1020_MODE_PROX_I);
37735654354SManivannan Sadhasivam 			if (ret < 0)
37835654354SManivannan Sadhasivam 				goto fail;
37935654354SManivannan Sadhasivam 
38035654354SManivannan Sadhasivam 			ret = adux1020_measure(data, ADUX1020_MODE_PROX_I, buf);
38135654354SManivannan Sadhasivam 			if (ret < 0)
38235654354SManivannan Sadhasivam 				goto fail;
38335654354SManivannan Sadhasivam 
38435654354SManivannan Sadhasivam 			*val = buf[0];
38535654354SManivannan Sadhasivam 			ret = IIO_VAL_INT;
38635654354SManivannan Sadhasivam 			break;
38735654354SManivannan Sadhasivam 		default:
38835654354SManivannan Sadhasivam 			break;
38935654354SManivannan Sadhasivam 		}
39035654354SManivannan Sadhasivam 		break;
39135654354SManivannan Sadhasivam 	case IIO_CHAN_INFO_PROCESSED:
39235654354SManivannan Sadhasivam 		switch (chan->type) {
39335654354SManivannan Sadhasivam 		case IIO_CURRENT:
39435654354SManivannan Sadhasivam 			ret = regmap_read(data->regmap,
39535654354SManivannan Sadhasivam 					  ADUX1020_REG_LED_CURRENT, &regval);
39635654354SManivannan Sadhasivam 			if (ret < 0)
39735654354SManivannan Sadhasivam 				goto fail;
39835654354SManivannan Sadhasivam 
39935654354SManivannan Sadhasivam 			regval = regval & ADUX1020_LED_CURRENT_MASK;
40035654354SManivannan Sadhasivam 
40135654354SManivannan Sadhasivam 			*val = adux1020_led_currents[regval][0];
40235654354SManivannan Sadhasivam 			*val2 = adux1020_led_currents[regval][1];
40335654354SManivannan Sadhasivam 
40435654354SManivannan Sadhasivam 			ret = IIO_VAL_INT_PLUS_MICRO;
40535654354SManivannan Sadhasivam 			break;
40635654354SManivannan Sadhasivam 		default:
40735654354SManivannan Sadhasivam 			break;
40835654354SManivannan Sadhasivam 		}
40935654354SManivannan Sadhasivam 		break;
41035654354SManivannan Sadhasivam 	case IIO_CHAN_INFO_SAMP_FREQ:
41135654354SManivannan Sadhasivam 		switch (chan->type) {
41235654354SManivannan Sadhasivam 		case IIO_PROXIMITY:
41335654354SManivannan Sadhasivam 			ret = regmap_read(data->regmap, ADUX1020_REG_FREQUENCY,
41435654354SManivannan Sadhasivam 					  &regval);
41535654354SManivannan Sadhasivam 			if (ret < 0)
41635654354SManivannan Sadhasivam 				goto fail;
41735654354SManivannan Sadhasivam 
41835654354SManivannan Sadhasivam 			regval = FIELD_GET(ADUX1020_PROX_FREQ_MASK, regval);
41935654354SManivannan Sadhasivam 
42035654354SManivannan Sadhasivam 			*val = adux1020_rates[regval][0];
42135654354SManivannan Sadhasivam 			*val2 = adux1020_rates[regval][1];
42235654354SManivannan Sadhasivam 
42335654354SManivannan Sadhasivam 			ret = IIO_VAL_INT_PLUS_MICRO;
42435654354SManivannan Sadhasivam 			break;
42535654354SManivannan Sadhasivam 		default:
42635654354SManivannan Sadhasivam 			break;
42735654354SManivannan Sadhasivam 		}
42835654354SManivannan Sadhasivam 		break;
42935654354SManivannan Sadhasivam 	default:
43035654354SManivannan Sadhasivam 		break;
43135654354SManivannan Sadhasivam 	}
43235654354SManivannan Sadhasivam 
43335654354SManivannan Sadhasivam fail:
43435654354SManivannan Sadhasivam 	mutex_unlock(&data->lock);
43535654354SManivannan Sadhasivam 
43635654354SManivannan Sadhasivam 	return ret;
43735654354SManivannan Sadhasivam };
43835654354SManivannan Sadhasivam 
adux1020_find_index(const int array[][2],int count,int val,int val2)43935654354SManivannan Sadhasivam static inline int adux1020_find_index(const int array[][2], int count, int val,
44035654354SManivannan Sadhasivam 				      int val2)
44135654354SManivannan Sadhasivam {
44235654354SManivannan Sadhasivam 	int i;
44335654354SManivannan Sadhasivam 
44435654354SManivannan Sadhasivam 	for (i = 0; i < count; i++)
44535654354SManivannan Sadhasivam 		if (val == array[i][0] && val2 == array[i][1])
44635654354SManivannan Sadhasivam 			return i;
44735654354SManivannan Sadhasivam 
44835654354SManivannan Sadhasivam 	return -EINVAL;
44935654354SManivannan Sadhasivam }
45035654354SManivannan Sadhasivam 
adux1020_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)45135654354SManivannan Sadhasivam static int adux1020_write_raw(struct iio_dev *indio_dev,
45235654354SManivannan Sadhasivam 			      struct iio_chan_spec const *chan,
45335654354SManivannan Sadhasivam 			      int val, int val2, long mask)
45435654354SManivannan Sadhasivam {
45535654354SManivannan Sadhasivam 	struct adux1020_data *data = iio_priv(indio_dev);
45635654354SManivannan Sadhasivam 	int i, ret = -EINVAL;
45735654354SManivannan Sadhasivam 
45835654354SManivannan Sadhasivam 	mutex_lock(&data->lock);
45935654354SManivannan Sadhasivam 
46035654354SManivannan Sadhasivam 	switch (mask) {
46135654354SManivannan Sadhasivam 	case IIO_CHAN_INFO_SAMP_FREQ:
46235654354SManivannan Sadhasivam 		if (chan->type == IIO_PROXIMITY) {
46335654354SManivannan Sadhasivam 			i = adux1020_find_index(adux1020_rates,
46435654354SManivannan Sadhasivam 						ARRAY_SIZE(adux1020_rates),
46535654354SManivannan Sadhasivam 						val, val2);
46635654354SManivannan Sadhasivam 			if (i < 0) {
46735654354SManivannan Sadhasivam 				ret = i;
46835654354SManivannan Sadhasivam 				goto fail;
46935654354SManivannan Sadhasivam 			}
47035654354SManivannan Sadhasivam 
47135654354SManivannan Sadhasivam 			ret = regmap_update_bits(data->regmap,
47235654354SManivannan Sadhasivam 						 ADUX1020_REG_FREQUENCY,
47335654354SManivannan Sadhasivam 						 ADUX1020_PROX_FREQ_MASK,
47435654354SManivannan Sadhasivam 						 ADUX1020_PROX_FREQ(i));
47535654354SManivannan Sadhasivam 		}
47635654354SManivannan Sadhasivam 		break;
47735654354SManivannan Sadhasivam 	case IIO_CHAN_INFO_PROCESSED:
47835654354SManivannan Sadhasivam 		if (chan->type == IIO_CURRENT) {
47935654354SManivannan Sadhasivam 			i = adux1020_find_index(adux1020_led_currents,
48035654354SManivannan Sadhasivam 					ARRAY_SIZE(adux1020_led_currents),
48135654354SManivannan Sadhasivam 					val, val2);
48235654354SManivannan Sadhasivam 			if (i < 0) {
48335654354SManivannan Sadhasivam 				ret = i;
48435654354SManivannan Sadhasivam 				goto fail;
48535654354SManivannan Sadhasivam 			}
48635654354SManivannan Sadhasivam 
48735654354SManivannan Sadhasivam 			ret = regmap_update_bits(data->regmap,
48835654354SManivannan Sadhasivam 						 ADUX1020_REG_LED_CURRENT,
48935654354SManivannan Sadhasivam 						 ADUX1020_LED_CURRENT_MASK, i);
49035654354SManivannan Sadhasivam 		}
49135654354SManivannan Sadhasivam 		break;
49235654354SManivannan Sadhasivam 	default:
49335654354SManivannan Sadhasivam 		break;
49435654354SManivannan Sadhasivam 	}
49535654354SManivannan Sadhasivam 
49635654354SManivannan Sadhasivam fail:
49735654354SManivannan Sadhasivam 	mutex_unlock(&data->lock);
49835654354SManivannan Sadhasivam 
49935654354SManivannan Sadhasivam 	return ret;
50035654354SManivannan Sadhasivam }
50135654354SManivannan Sadhasivam 
adux1020_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)50235654354SManivannan Sadhasivam static int adux1020_write_event_config(struct iio_dev *indio_dev,
50335654354SManivannan Sadhasivam 				       const struct iio_chan_spec *chan,
50435654354SManivannan Sadhasivam 				       enum iio_event_type type,
50535654354SManivannan Sadhasivam 				       enum iio_event_direction dir, int state)
50635654354SManivannan Sadhasivam {
50735654354SManivannan Sadhasivam 	struct adux1020_data *data = iio_priv(indio_dev);
50835654354SManivannan Sadhasivam 	int ret, mask;
50935654354SManivannan Sadhasivam 
51035654354SManivannan Sadhasivam 	mutex_lock(&data->lock);
51135654354SManivannan Sadhasivam 
51235654354SManivannan Sadhasivam 	ret = regmap_write(data->regmap, ADUX1020_REG_INT_ENABLE,
51335654354SManivannan Sadhasivam 			   ADUX1020_INT_ENABLE);
51435654354SManivannan Sadhasivam 	if (ret < 0)
51535654354SManivannan Sadhasivam 		goto fail;
51635654354SManivannan Sadhasivam 
51735654354SManivannan Sadhasivam 	ret = regmap_write(data->regmap, ADUX1020_REG_INT_POLARITY, 0);
51835654354SManivannan Sadhasivam 	if (ret < 0)
51935654354SManivannan Sadhasivam 		goto fail;
52035654354SManivannan Sadhasivam 
52135654354SManivannan Sadhasivam 	switch (chan->type) {
52235654354SManivannan Sadhasivam 	case IIO_PROXIMITY:
52335654354SManivannan Sadhasivam 		if (dir == IIO_EV_DIR_RISING)
52435654354SManivannan Sadhasivam 			mask = ADUX1020_PROX_ON1_INT;
52535654354SManivannan Sadhasivam 		else
52635654354SManivannan Sadhasivam 			mask = ADUX1020_PROX_OFF1_INT;
52735654354SManivannan Sadhasivam 
52835654354SManivannan Sadhasivam 		if (state)
52935654354SManivannan Sadhasivam 			state = 0;
53035654354SManivannan Sadhasivam 		else
53135654354SManivannan Sadhasivam 			state = mask;
53235654354SManivannan Sadhasivam 
53335654354SManivannan Sadhasivam 		ret = regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
53435654354SManivannan Sadhasivam 					 mask, state);
53535654354SManivannan Sadhasivam 		if (ret < 0)
53635654354SManivannan Sadhasivam 			goto fail;
53735654354SManivannan Sadhasivam 
53835654354SManivannan Sadhasivam 		/*
53935654354SManivannan Sadhasivam 		 * Trigger proximity interrupt when the intensity is above
54035654354SManivannan Sadhasivam 		 * or below threshold
54135654354SManivannan Sadhasivam 		 */
54235654354SManivannan Sadhasivam 		ret = regmap_update_bits(data->regmap, ADUX1020_REG_PROX_TYPE,
54335654354SManivannan Sadhasivam 					 ADUX1020_PROX_TYPE,
54435654354SManivannan Sadhasivam 					 ADUX1020_PROX_TYPE);
54535654354SManivannan Sadhasivam 		if (ret < 0)
54635654354SManivannan Sadhasivam 			goto fail;
54735654354SManivannan Sadhasivam 
54835654354SManivannan Sadhasivam 		/* Set proximity mode */
54935654354SManivannan Sadhasivam 		ret = adux1020_set_mode(data, ADUX1020_MODE_PROX_I);
55035654354SManivannan Sadhasivam 		break;
55135654354SManivannan Sadhasivam 	default:
55235654354SManivannan Sadhasivam 		ret = -EINVAL;
55335654354SManivannan Sadhasivam 		break;
55435654354SManivannan Sadhasivam 	}
55535654354SManivannan Sadhasivam 
55635654354SManivannan Sadhasivam fail:
55735654354SManivannan Sadhasivam 	mutex_unlock(&data->lock);
55835654354SManivannan Sadhasivam 
55935654354SManivannan Sadhasivam 	return ret;
56035654354SManivannan Sadhasivam }
56135654354SManivannan Sadhasivam 
adux1020_read_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir)56235654354SManivannan Sadhasivam static int adux1020_read_event_config(struct iio_dev *indio_dev,
56335654354SManivannan Sadhasivam 				      const struct iio_chan_spec *chan,
56435654354SManivannan Sadhasivam 				      enum iio_event_type type,
56535654354SManivannan Sadhasivam 				      enum iio_event_direction dir)
56635654354SManivannan Sadhasivam {
56735654354SManivannan Sadhasivam 	struct adux1020_data *data = iio_priv(indio_dev);
56835654354SManivannan Sadhasivam 	int ret, mask;
56935654354SManivannan Sadhasivam 	unsigned int regval;
57035654354SManivannan Sadhasivam 
57135654354SManivannan Sadhasivam 	switch (chan->type) {
57235654354SManivannan Sadhasivam 	case IIO_PROXIMITY:
57335654354SManivannan Sadhasivam 		if (dir == IIO_EV_DIR_RISING)
57435654354SManivannan Sadhasivam 			mask = ADUX1020_PROX_ON1_INT;
57535654354SManivannan Sadhasivam 		else
57635654354SManivannan Sadhasivam 			mask = ADUX1020_PROX_OFF1_INT;
57735654354SManivannan Sadhasivam 		break;
57835654354SManivannan Sadhasivam 	default:
57935654354SManivannan Sadhasivam 		return -EINVAL;
58035654354SManivannan Sadhasivam 	}
58135654354SManivannan Sadhasivam 
58235654354SManivannan Sadhasivam 	ret = regmap_read(data->regmap, ADUX1020_REG_INT_MASK, &regval);
58335654354SManivannan Sadhasivam 	if (ret < 0)
58435654354SManivannan Sadhasivam 		return ret;
58535654354SManivannan Sadhasivam 
58635654354SManivannan Sadhasivam 	return !(regval & mask);
58735654354SManivannan Sadhasivam }
58835654354SManivannan Sadhasivam 
adux1020_read_thresh(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)58935654354SManivannan Sadhasivam static int adux1020_read_thresh(struct iio_dev *indio_dev,
59035654354SManivannan Sadhasivam 				const struct iio_chan_spec *chan,
59135654354SManivannan Sadhasivam 				enum iio_event_type type,
59235654354SManivannan Sadhasivam 				enum iio_event_direction dir,
59335654354SManivannan Sadhasivam 				enum iio_event_info info, int *val, int *val2)
59435654354SManivannan Sadhasivam {
59535654354SManivannan Sadhasivam 	struct adux1020_data *data = iio_priv(indio_dev);
59635654354SManivannan Sadhasivam 	u8 reg;
59735654354SManivannan Sadhasivam 	int ret;
59835654354SManivannan Sadhasivam 	unsigned int regval;
59935654354SManivannan Sadhasivam 
60035654354SManivannan Sadhasivam 	switch (chan->type) {
60135654354SManivannan Sadhasivam 	case IIO_PROXIMITY:
60235654354SManivannan Sadhasivam 		if (dir == IIO_EV_DIR_RISING)
60335654354SManivannan Sadhasivam 			reg = ADUX1020_REG_PROX_TH_ON1;
60435654354SManivannan Sadhasivam 		else
60535654354SManivannan Sadhasivam 			reg = ADUX1020_REG_PROX_TH_OFF1;
60635654354SManivannan Sadhasivam 		break;
60735654354SManivannan Sadhasivam 	default:
60835654354SManivannan Sadhasivam 		return -EINVAL;
60935654354SManivannan Sadhasivam 	}
61035654354SManivannan Sadhasivam 
61135654354SManivannan Sadhasivam 	ret = regmap_read(data->regmap, reg, &regval);
61235654354SManivannan Sadhasivam 	if (ret < 0)
61335654354SManivannan Sadhasivam 		return ret;
61435654354SManivannan Sadhasivam 
61535654354SManivannan Sadhasivam 	*val = regval;
61635654354SManivannan Sadhasivam 
61735654354SManivannan Sadhasivam 	return IIO_VAL_INT;
61835654354SManivannan Sadhasivam }
61935654354SManivannan Sadhasivam 
adux1020_write_thresh(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)62035654354SManivannan Sadhasivam static int adux1020_write_thresh(struct iio_dev *indio_dev,
62135654354SManivannan Sadhasivam 				 const struct iio_chan_spec *chan,
62235654354SManivannan Sadhasivam 				 enum iio_event_type type,
62335654354SManivannan Sadhasivam 				 enum iio_event_direction dir,
62435654354SManivannan Sadhasivam 				 enum iio_event_info info, int val, int val2)
62535654354SManivannan Sadhasivam {
62635654354SManivannan Sadhasivam 	struct adux1020_data *data = iio_priv(indio_dev);
62735654354SManivannan Sadhasivam 	u8 reg;
62835654354SManivannan Sadhasivam 
62935654354SManivannan Sadhasivam 	switch (chan->type) {
63035654354SManivannan Sadhasivam 	case IIO_PROXIMITY:
63135654354SManivannan Sadhasivam 		if (dir == IIO_EV_DIR_RISING)
63235654354SManivannan Sadhasivam 			reg = ADUX1020_REG_PROX_TH_ON1;
63335654354SManivannan Sadhasivam 		else
63435654354SManivannan Sadhasivam 			reg = ADUX1020_REG_PROX_TH_OFF1;
63535654354SManivannan Sadhasivam 		break;
63635654354SManivannan Sadhasivam 	default:
63735654354SManivannan Sadhasivam 		return -EINVAL;
63835654354SManivannan Sadhasivam 	}
63935654354SManivannan Sadhasivam 
64035654354SManivannan Sadhasivam 	/* Full scale threshold value is 0-65535  */
64135654354SManivannan Sadhasivam 	if (val < 0 || val > 65535)
64235654354SManivannan Sadhasivam 		return -EINVAL;
64335654354SManivannan Sadhasivam 
64435654354SManivannan Sadhasivam 	return regmap_write(data->regmap, reg, val);
64535654354SManivannan Sadhasivam }
64635654354SManivannan Sadhasivam 
64735654354SManivannan Sadhasivam static const struct iio_event_spec adux1020_proximity_event[] = {
64835654354SManivannan Sadhasivam 	{
64935654354SManivannan Sadhasivam 		.type = IIO_EV_TYPE_THRESH,
65035654354SManivannan Sadhasivam 		.dir = IIO_EV_DIR_RISING,
65135654354SManivannan Sadhasivam 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
65235654354SManivannan Sadhasivam 			BIT(IIO_EV_INFO_ENABLE),
65335654354SManivannan Sadhasivam 	},
65435654354SManivannan Sadhasivam 	{
65535654354SManivannan Sadhasivam 		.type = IIO_EV_TYPE_THRESH,
65635654354SManivannan Sadhasivam 		.dir = IIO_EV_DIR_FALLING,
65735654354SManivannan Sadhasivam 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
65835654354SManivannan Sadhasivam 			BIT(IIO_EV_INFO_ENABLE),
65935654354SManivannan Sadhasivam 	},
66035654354SManivannan Sadhasivam };
66135654354SManivannan Sadhasivam 
66235654354SManivannan Sadhasivam static const struct iio_chan_spec adux1020_channels[] = {
66335654354SManivannan Sadhasivam 	{
66435654354SManivannan Sadhasivam 		.type = IIO_PROXIMITY,
66535654354SManivannan Sadhasivam 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
66635654354SManivannan Sadhasivam 				      BIT(IIO_CHAN_INFO_SAMP_FREQ),
66735654354SManivannan Sadhasivam 		.event_spec = adux1020_proximity_event,
66835654354SManivannan Sadhasivam 		.num_event_specs = ARRAY_SIZE(adux1020_proximity_event),
66935654354SManivannan Sadhasivam 	},
67035654354SManivannan Sadhasivam 	{
67135654354SManivannan Sadhasivam 		.type = IIO_CURRENT,
67235654354SManivannan Sadhasivam 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
67335654354SManivannan Sadhasivam 		.extend_name = "led",
67435654354SManivannan Sadhasivam 		.output = 1,
67535654354SManivannan Sadhasivam 	},
67635654354SManivannan Sadhasivam };
67735654354SManivannan Sadhasivam 
67835654354SManivannan Sadhasivam static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
67935654354SManivannan Sadhasivam 		      "0.1 0.2 0.5 1 2 5 10 20 50 100 190 450 820 1400");
68035654354SManivannan Sadhasivam 
68135654354SManivannan Sadhasivam static struct attribute *adux1020_attributes[] = {
68235654354SManivannan Sadhasivam 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
68335654354SManivannan Sadhasivam 	NULL
68435654354SManivannan Sadhasivam };
68535654354SManivannan Sadhasivam 
68635654354SManivannan Sadhasivam static const struct attribute_group adux1020_attribute_group = {
68735654354SManivannan Sadhasivam 	.attrs = adux1020_attributes,
68835654354SManivannan Sadhasivam };
68935654354SManivannan Sadhasivam 
69035654354SManivannan Sadhasivam static const struct iio_info adux1020_info = {
69135654354SManivannan Sadhasivam 	.attrs = &adux1020_attribute_group,
69235654354SManivannan Sadhasivam 	.read_raw = adux1020_read_raw,
69335654354SManivannan Sadhasivam 	.write_raw = adux1020_write_raw,
69435654354SManivannan Sadhasivam 	.read_event_config = adux1020_read_event_config,
69535654354SManivannan Sadhasivam 	.write_event_config = adux1020_write_event_config,
69635654354SManivannan Sadhasivam 	.read_event_value = adux1020_read_thresh,
69735654354SManivannan Sadhasivam 	.write_event_value = adux1020_write_thresh,
69835654354SManivannan Sadhasivam };
69935654354SManivannan Sadhasivam 
adux1020_interrupt_handler(int irq,void * private)70035654354SManivannan Sadhasivam static irqreturn_t adux1020_interrupt_handler(int irq, void *private)
70135654354SManivannan Sadhasivam {
70235654354SManivannan Sadhasivam 	struct iio_dev *indio_dev = private;
70335654354SManivannan Sadhasivam 	struct adux1020_data *data = iio_priv(indio_dev);
70435654354SManivannan Sadhasivam 	int ret, status;
70535654354SManivannan Sadhasivam 
70635654354SManivannan Sadhasivam 	ret = regmap_read(data->regmap, ADUX1020_REG_INT_STATUS, &status);
70735654354SManivannan Sadhasivam 	if (ret < 0)
70835654354SManivannan Sadhasivam 		return IRQ_HANDLED;
70935654354SManivannan Sadhasivam 
71035654354SManivannan Sadhasivam 	status &= ADUX1020_MODE_INT_STATUS_MASK;
71135654354SManivannan Sadhasivam 
71235654354SManivannan Sadhasivam 	if (status & ADUX1020_INT_PROX_ON1) {
71335654354SManivannan Sadhasivam 		iio_push_event(indio_dev,
71435654354SManivannan Sadhasivam 			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
71535654354SManivannan Sadhasivam 						    IIO_EV_TYPE_THRESH,
71635654354SManivannan Sadhasivam 						    IIO_EV_DIR_RISING),
71735654354SManivannan Sadhasivam 			       iio_get_time_ns(indio_dev));
71835654354SManivannan Sadhasivam 	}
71935654354SManivannan Sadhasivam 
72035654354SManivannan Sadhasivam 	if (status & ADUX1020_INT_PROX_OFF1) {
72135654354SManivannan Sadhasivam 		iio_push_event(indio_dev,
72235654354SManivannan Sadhasivam 			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
72335654354SManivannan Sadhasivam 						    IIO_EV_TYPE_THRESH,
72435654354SManivannan Sadhasivam 						    IIO_EV_DIR_FALLING),
72535654354SManivannan Sadhasivam 			       iio_get_time_ns(indio_dev));
72635654354SManivannan Sadhasivam 	}
72735654354SManivannan Sadhasivam 
72835654354SManivannan Sadhasivam 	regmap_update_bits(data->regmap, ADUX1020_REG_INT_STATUS,
72935654354SManivannan Sadhasivam 			   ADUX1020_MODE_INT_MASK, ADUX1020_INT_CLEAR);
73035654354SManivannan Sadhasivam 
73135654354SManivannan Sadhasivam 	return IRQ_HANDLED;
73235654354SManivannan Sadhasivam }
73335654354SManivannan Sadhasivam 
adux1020_chip_init(struct adux1020_data * data)73435654354SManivannan Sadhasivam static int adux1020_chip_init(struct adux1020_data *data)
73535654354SManivannan Sadhasivam {
73635654354SManivannan Sadhasivam 	struct i2c_client *client = data->client;
73735654354SManivannan Sadhasivam 	int ret;
73835654354SManivannan Sadhasivam 	unsigned int val;
73935654354SManivannan Sadhasivam 
74035654354SManivannan Sadhasivam 	ret = regmap_read(data->regmap, ADUX1020_REG_CHIP_ID, &val);
74135654354SManivannan Sadhasivam 	if (ret < 0)
74235654354SManivannan Sadhasivam 		return ret;
74335654354SManivannan Sadhasivam 
74435654354SManivannan Sadhasivam 	if ((val & ADUX1020_CHIP_ID_MASK) != ADUX1020_CHIP_ID) {
74535654354SManivannan Sadhasivam 		dev_err(&client->dev, "invalid chip id 0x%04x\n", val);
74635654354SManivannan Sadhasivam 		return -ENODEV;
74735654354SManivannan Sadhasivam 	}
74835654354SManivannan Sadhasivam 
74935654354SManivannan Sadhasivam 	dev_dbg(&client->dev, "Detected ADUX1020 with chip id: 0x%04x\n", val);
75035654354SManivannan Sadhasivam 
75135654354SManivannan Sadhasivam 	ret = regmap_update_bits(data->regmap, ADUX1020_REG_SW_RESET,
75235654354SManivannan Sadhasivam 				 ADUX1020_SW_RESET, ADUX1020_SW_RESET);
75335654354SManivannan Sadhasivam 	if (ret < 0)
75435654354SManivannan Sadhasivam 		return ret;
75535654354SManivannan Sadhasivam 
75635654354SManivannan Sadhasivam 	/* Load default configuration */
75735654354SManivannan Sadhasivam 	ret = regmap_multi_reg_write(data->regmap, adux1020_def_conf,
75835654354SManivannan Sadhasivam 				     ARRAY_SIZE(adux1020_def_conf));
75935654354SManivannan Sadhasivam 	if (ret < 0)
76035654354SManivannan Sadhasivam 		return ret;
76135654354SManivannan Sadhasivam 
76235654354SManivannan Sadhasivam 	ret = adux1020_flush_fifo(data);
76335654354SManivannan Sadhasivam 	if (ret < 0)
76435654354SManivannan Sadhasivam 		return ret;
76535654354SManivannan Sadhasivam 
76635654354SManivannan Sadhasivam 	/* Use LED_IREF for proximity mode */
76735654354SManivannan Sadhasivam 	ret = regmap_update_bits(data->regmap, ADUX1020_REG_LED_CURRENT,
76835654354SManivannan Sadhasivam 				 ADUX1020_LED_PIREF_EN, 0);
76935654354SManivannan Sadhasivam 	if (ret < 0)
77035654354SManivannan Sadhasivam 		return ret;
77135654354SManivannan Sadhasivam 
77235654354SManivannan Sadhasivam 	/* Mask all interrupts */
77335654354SManivannan Sadhasivam 	return regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK,
77435654354SManivannan Sadhasivam 			   ADUX1020_MODE_INT_MASK, ADUX1020_MODE_INT_DISABLE);
77535654354SManivannan Sadhasivam }
77635654354SManivannan Sadhasivam 
adux1020_probe(struct i2c_client * client)777fd63b0a4SUwe Kleine-König static int adux1020_probe(struct i2c_client *client)
77835654354SManivannan Sadhasivam {
77935654354SManivannan Sadhasivam 	struct adux1020_data *data;
78035654354SManivannan Sadhasivam 	struct iio_dev *indio_dev;
78135654354SManivannan Sadhasivam 	int ret;
78235654354SManivannan Sadhasivam 
78335654354SManivannan Sadhasivam 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
78435654354SManivannan Sadhasivam 	if (!indio_dev)
78535654354SManivannan Sadhasivam 		return -ENOMEM;
78635654354SManivannan Sadhasivam 
78735654354SManivannan Sadhasivam 	indio_dev->info = &adux1020_info;
78835654354SManivannan Sadhasivam 	indio_dev->name = ADUX1020_DRV_NAME;
78935654354SManivannan Sadhasivam 	indio_dev->channels = adux1020_channels;
79035654354SManivannan Sadhasivam 	indio_dev->num_channels = ARRAY_SIZE(adux1020_channels);
79135654354SManivannan Sadhasivam 	indio_dev->modes = INDIO_DIRECT_MODE;
79235654354SManivannan Sadhasivam 
79335654354SManivannan Sadhasivam 	data = iio_priv(indio_dev);
79435654354SManivannan Sadhasivam 
79535654354SManivannan Sadhasivam 	data->regmap = devm_regmap_init_i2c(client, &adux1020_regmap_config);
79635654354SManivannan Sadhasivam 	if (IS_ERR(data->regmap)) {
79735654354SManivannan Sadhasivam 		dev_err(&client->dev, "regmap initialization failed.\n");
79835654354SManivannan Sadhasivam 		return PTR_ERR(data->regmap);
79935654354SManivannan Sadhasivam 	}
80035654354SManivannan Sadhasivam 
80135654354SManivannan Sadhasivam 	data->client = client;
80235654354SManivannan Sadhasivam 	data->indio_dev = indio_dev;
80335654354SManivannan Sadhasivam 	mutex_init(&data->lock);
80435654354SManivannan Sadhasivam 
80535654354SManivannan Sadhasivam 	ret = adux1020_chip_init(data);
80635654354SManivannan Sadhasivam 	if (ret)
80735654354SManivannan Sadhasivam 		return ret;
80835654354SManivannan Sadhasivam 
80935654354SManivannan Sadhasivam 	if (client->irq) {
81035654354SManivannan Sadhasivam 		ret = devm_request_threaded_irq(&client->dev, client->irq,
81135654354SManivannan Sadhasivam 					NULL, adux1020_interrupt_handler,
81235654354SManivannan Sadhasivam 					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
81335654354SManivannan Sadhasivam 					ADUX1020_DRV_NAME, indio_dev);
81435654354SManivannan Sadhasivam 		if (ret) {
81535654354SManivannan Sadhasivam 			dev_err(&client->dev, "irq request error %d\n", -ret);
81635654354SManivannan Sadhasivam 			return ret;
81735654354SManivannan Sadhasivam 		}
81835654354SManivannan Sadhasivam 	}
81935654354SManivannan Sadhasivam 
82035654354SManivannan Sadhasivam 	return devm_iio_device_register(&client->dev, indio_dev);
82135654354SManivannan Sadhasivam }
82235654354SManivannan Sadhasivam 
82335654354SManivannan Sadhasivam static const struct i2c_device_id adux1020_id[] = {
82435654354SManivannan Sadhasivam 	{ "adux1020", 0 },
82535654354SManivannan Sadhasivam 	{}
82635654354SManivannan Sadhasivam };
82735654354SManivannan Sadhasivam MODULE_DEVICE_TABLE(i2c, adux1020_id);
82835654354SManivannan Sadhasivam 
82935654354SManivannan Sadhasivam static const struct of_device_id adux1020_of_match[] = {
83035654354SManivannan Sadhasivam 	{ .compatible = "adi,adux1020" },
83135654354SManivannan Sadhasivam 	{ }
83235654354SManivannan Sadhasivam };
83335654354SManivannan Sadhasivam MODULE_DEVICE_TABLE(of, adux1020_of_match);
83435654354SManivannan Sadhasivam 
83535654354SManivannan Sadhasivam static struct i2c_driver adux1020_driver = {
83635654354SManivannan Sadhasivam 	.driver = {
83735654354SManivannan Sadhasivam 		.name	= ADUX1020_DRV_NAME,
83835654354SManivannan Sadhasivam 		.of_match_table = adux1020_of_match,
83935654354SManivannan Sadhasivam 	},
840*7cf15f42SUwe Kleine-König 	.probe		= adux1020_probe,
84135654354SManivannan Sadhasivam 	.id_table	= adux1020_id,
84235654354SManivannan Sadhasivam };
84335654354SManivannan Sadhasivam module_i2c_driver(adux1020_driver);
84435654354SManivannan Sadhasivam 
84535654354SManivannan Sadhasivam MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
84635654354SManivannan Sadhasivam MODULE_DESCRIPTION("ADUX1020 photometric sensor");
84735654354SManivannan Sadhasivam MODULE_LICENSE("GPL");
848