162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ADS1015 - Texas Instruments Analog-to-Digital Converter
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2016, Intel Corporation.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * IIO driver for ADS1015 ADC 7-bit I2C slave address:
862306a36Sopenharmony_ci *	* 0x48 - ADDR connected to Ground
962306a36Sopenharmony_ci *	* 0x49 - ADDR connected to Vdd
1062306a36Sopenharmony_ci *	* 0x4A - ADDR connected to SDA
1162306a36Sopenharmony_ci *	* 0x4B - ADDR connected to SCL
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/init.h>
1662306a36Sopenharmony_ci#include <linux/irq.h>
1762306a36Sopenharmony_ci#include <linux/i2c.h>
1862306a36Sopenharmony_ci#include <linux/property.h>
1962306a36Sopenharmony_ci#include <linux/regmap.h>
2062306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2162306a36Sopenharmony_ci#include <linux/mutex.h>
2262306a36Sopenharmony_ci#include <linux/delay.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <linux/iio/iio.h>
2562306a36Sopenharmony_ci#include <linux/iio/types.h>
2662306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
2762306a36Sopenharmony_ci#include <linux/iio/events.h>
2862306a36Sopenharmony_ci#include <linux/iio/buffer.h>
2962306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
3062306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define ADS1015_DRV_NAME "ads1015"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define ADS1015_CHANNELS 8
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define ADS1015_CONV_REG	0x00
3762306a36Sopenharmony_ci#define ADS1015_CFG_REG		0x01
3862306a36Sopenharmony_ci#define ADS1015_LO_THRESH_REG	0x02
3962306a36Sopenharmony_ci#define ADS1015_HI_THRESH_REG	0x03
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define ADS1015_CFG_COMP_QUE_SHIFT	0
4262306a36Sopenharmony_ci#define ADS1015_CFG_COMP_LAT_SHIFT	2
4362306a36Sopenharmony_ci#define ADS1015_CFG_COMP_POL_SHIFT	3
4462306a36Sopenharmony_ci#define ADS1015_CFG_COMP_MODE_SHIFT	4
4562306a36Sopenharmony_ci#define ADS1015_CFG_DR_SHIFT	5
4662306a36Sopenharmony_ci#define ADS1015_CFG_MOD_SHIFT	8
4762306a36Sopenharmony_ci#define ADS1015_CFG_PGA_SHIFT	9
4862306a36Sopenharmony_ci#define ADS1015_CFG_MUX_SHIFT	12
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define ADS1015_CFG_COMP_QUE_MASK	GENMASK(1, 0)
5162306a36Sopenharmony_ci#define ADS1015_CFG_COMP_LAT_MASK	BIT(2)
5262306a36Sopenharmony_ci#define ADS1015_CFG_COMP_POL_MASK	BIT(3)
5362306a36Sopenharmony_ci#define ADS1015_CFG_COMP_MODE_MASK	BIT(4)
5462306a36Sopenharmony_ci#define ADS1015_CFG_DR_MASK	GENMASK(7, 5)
5562306a36Sopenharmony_ci#define ADS1015_CFG_MOD_MASK	BIT(8)
5662306a36Sopenharmony_ci#define ADS1015_CFG_PGA_MASK	GENMASK(11, 9)
5762306a36Sopenharmony_ci#define ADS1015_CFG_MUX_MASK	GENMASK(14, 12)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* Comparator queue and disable field */
6062306a36Sopenharmony_ci#define ADS1015_CFG_COMP_DISABLE	3
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* Comparator polarity field */
6362306a36Sopenharmony_ci#define ADS1015_CFG_COMP_POL_LOW	0
6462306a36Sopenharmony_ci#define ADS1015_CFG_COMP_POL_HIGH	1
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* Comparator mode field */
6762306a36Sopenharmony_ci#define ADS1015_CFG_COMP_MODE_TRAD	0
6862306a36Sopenharmony_ci#define ADS1015_CFG_COMP_MODE_WINDOW	1
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* device operating modes */
7162306a36Sopenharmony_ci#define ADS1015_CONTINUOUS	0
7262306a36Sopenharmony_ci#define ADS1015_SINGLESHOT	1
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define ADS1015_SLEEP_DELAY_MS		2000
7562306a36Sopenharmony_ci#define ADS1015_DEFAULT_PGA		2
7662306a36Sopenharmony_ci#define ADS1015_DEFAULT_DATA_RATE	4
7762306a36Sopenharmony_ci#define ADS1015_DEFAULT_CHAN		0
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistruct ads1015_chip_data {
8062306a36Sopenharmony_ci	struct iio_chan_spec const	*channels;
8162306a36Sopenharmony_ci	int				num_channels;
8262306a36Sopenharmony_ci	const struct iio_info		*info;
8362306a36Sopenharmony_ci	const int			*data_rate;
8462306a36Sopenharmony_ci	const int			data_rate_len;
8562306a36Sopenharmony_ci	const int			*scale;
8662306a36Sopenharmony_ci	const int			scale_len;
8762306a36Sopenharmony_ci	bool				has_comparator;
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cienum ads1015_channels {
9162306a36Sopenharmony_ci	ADS1015_AIN0_AIN1 = 0,
9262306a36Sopenharmony_ci	ADS1015_AIN0_AIN3,
9362306a36Sopenharmony_ci	ADS1015_AIN1_AIN3,
9462306a36Sopenharmony_ci	ADS1015_AIN2_AIN3,
9562306a36Sopenharmony_ci	ADS1015_AIN0,
9662306a36Sopenharmony_ci	ADS1015_AIN1,
9762306a36Sopenharmony_ci	ADS1015_AIN2,
9862306a36Sopenharmony_ci	ADS1015_AIN3,
9962306a36Sopenharmony_ci	ADS1015_TIMESTAMP,
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic const int ads1015_data_rate[] = {
10362306a36Sopenharmony_ci	128, 250, 490, 920, 1600, 2400, 3300, 3300
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic const int ads1115_data_rate[] = {
10762306a36Sopenharmony_ci	8, 16, 32, 64, 128, 250, 475, 860
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/*
11162306a36Sopenharmony_ci * Translation from PGA bits to full-scale positive and negative input voltage
11262306a36Sopenharmony_ci * range in mV
11362306a36Sopenharmony_ci */
11462306a36Sopenharmony_cistatic const int ads1015_fullscale_range[] = {
11562306a36Sopenharmony_ci	6144, 4096, 2048, 1024, 512, 256, 256, 256
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic const int ads1015_scale[] = {	/* 12bit ADC */
11962306a36Sopenharmony_ci	256, 11,
12062306a36Sopenharmony_ci	512, 11,
12162306a36Sopenharmony_ci	1024, 11,
12262306a36Sopenharmony_ci	2048, 11,
12362306a36Sopenharmony_ci	4096, 11,
12462306a36Sopenharmony_ci	6144, 11
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const int ads1115_scale[] = {	/* 16bit ADC */
12862306a36Sopenharmony_ci	256, 15,
12962306a36Sopenharmony_ci	512, 15,
13062306a36Sopenharmony_ci	1024, 15,
13162306a36Sopenharmony_ci	2048, 15,
13262306a36Sopenharmony_ci	4096, 15,
13362306a36Sopenharmony_ci	6144, 15
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/*
13762306a36Sopenharmony_ci * Translation from COMP_QUE field value to the number of successive readings
13862306a36Sopenharmony_ci * exceed the threshold values before an interrupt is generated
13962306a36Sopenharmony_ci */
14062306a36Sopenharmony_cistatic const int ads1015_comp_queue[] = { 1, 2, 4 };
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic const struct iio_event_spec ads1015_events[] = {
14362306a36Sopenharmony_ci	{
14462306a36Sopenharmony_ci		.type = IIO_EV_TYPE_THRESH,
14562306a36Sopenharmony_ci		.dir = IIO_EV_DIR_RISING,
14662306a36Sopenharmony_ci		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
14762306a36Sopenharmony_ci				BIT(IIO_EV_INFO_ENABLE),
14862306a36Sopenharmony_ci	}, {
14962306a36Sopenharmony_ci		.type = IIO_EV_TYPE_THRESH,
15062306a36Sopenharmony_ci		.dir = IIO_EV_DIR_FALLING,
15162306a36Sopenharmony_ci		.mask_separate = BIT(IIO_EV_INFO_VALUE),
15262306a36Sopenharmony_ci	}, {
15362306a36Sopenharmony_ci		.type = IIO_EV_TYPE_THRESH,
15462306a36Sopenharmony_ci		.dir = IIO_EV_DIR_EITHER,
15562306a36Sopenharmony_ci		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
15662306a36Sopenharmony_ci				BIT(IIO_EV_INFO_PERIOD),
15762306a36Sopenharmony_ci	},
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/*
16162306a36Sopenharmony_ci * Compile-time check whether _fitbits can accommodate up to _testbits
16262306a36Sopenharmony_ci * bits. Returns _fitbits on success, fails to compile otherwise.
16362306a36Sopenharmony_ci *
16462306a36Sopenharmony_ci * The test works such that it multiplies constant _fitbits by constant
16562306a36Sopenharmony_ci * double-negation of size of a non-empty structure, i.e. it multiplies
16662306a36Sopenharmony_ci * constant _fitbits by constant 1 in each successful compilation case.
16762306a36Sopenharmony_ci * The non-empty structure may contain C11 _Static_assert(), make use of
16862306a36Sopenharmony_ci * this and place the kernel variant of static assert in there, so that
16962306a36Sopenharmony_ci * it performs the compile-time check for _testbits <= _fitbits. Note
17062306a36Sopenharmony_ci * that it is not possible to directly use static_assert in compound
17162306a36Sopenharmony_ci * statements, hence this convoluted construct.
17262306a36Sopenharmony_ci */
17362306a36Sopenharmony_ci#define FIT_CHECK(_testbits, _fitbits)					\
17462306a36Sopenharmony_ci	(								\
17562306a36Sopenharmony_ci		(_fitbits) *						\
17662306a36Sopenharmony_ci		!!sizeof(struct {					\
17762306a36Sopenharmony_ci			static_assert((_testbits) <= (_fitbits));	\
17862306a36Sopenharmony_ci			int pad;					\
17962306a36Sopenharmony_ci		})							\
18062306a36Sopenharmony_ci	)
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci#define ADS1015_V_CHAN(_chan, _addr, _realbits, _shift, _event_spec, _num_event_specs) { \
18362306a36Sopenharmony_ci	.type = IIO_VOLTAGE,					\
18462306a36Sopenharmony_ci	.indexed = 1,						\
18562306a36Sopenharmony_ci	.address = _addr,					\
18662306a36Sopenharmony_ci	.channel = _chan,					\
18762306a36Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
18862306a36Sopenharmony_ci				BIT(IIO_CHAN_INFO_SCALE) |	\
18962306a36Sopenharmony_ci				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
19062306a36Sopenharmony_ci	.info_mask_shared_by_all_available =			\
19162306a36Sopenharmony_ci				BIT(IIO_CHAN_INFO_SCALE) |	\
19262306a36Sopenharmony_ci				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
19362306a36Sopenharmony_ci	.scan_index = _addr,					\
19462306a36Sopenharmony_ci	.scan_type = {						\
19562306a36Sopenharmony_ci		.sign = 's',					\
19662306a36Sopenharmony_ci		.realbits = (_realbits),			\
19762306a36Sopenharmony_ci		.storagebits = FIT_CHECK((_realbits) + (_shift), 16),	\
19862306a36Sopenharmony_ci		.shift = (_shift),				\
19962306a36Sopenharmony_ci		.endianness = IIO_CPU,				\
20062306a36Sopenharmony_ci	},							\
20162306a36Sopenharmony_ci	.event_spec = (_event_spec),				\
20262306a36Sopenharmony_ci	.num_event_specs = (_num_event_specs),			\
20362306a36Sopenharmony_ci	.datasheet_name = "AIN"#_chan,				\
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci#define ADS1015_V_DIFF_CHAN(_chan, _chan2, _addr, _realbits, _shift, _event_spec, _num_event_specs) { \
20762306a36Sopenharmony_ci	.type = IIO_VOLTAGE,					\
20862306a36Sopenharmony_ci	.differential = 1,					\
20962306a36Sopenharmony_ci	.indexed = 1,						\
21062306a36Sopenharmony_ci	.address = _addr,					\
21162306a36Sopenharmony_ci	.channel = _chan,					\
21262306a36Sopenharmony_ci	.channel2 = _chan2,					\
21362306a36Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
21462306a36Sopenharmony_ci				BIT(IIO_CHAN_INFO_SCALE) |	\
21562306a36Sopenharmony_ci				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
21662306a36Sopenharmony_ci	.info_mask_shared_by_all_available =			\
21762306a36Sopenharmony_ci				BIT(IIO_CHAN_INFO_SCALE) |	\
21862306a36Sopenharmony_ci				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
21962306a36Sopenharmony_ci	.scan_index = _addr,					\
22062306a36Sopenharmony_ci	.scan_type = {						\
22162306a36Sopenharmony_ci		.sign = 's',					\
22262306a36Sopenharmony_ci		.realbits = (_realbits),			\
22362306a36Sopenharmony_ci		.storagebits = FIT_CHECK((_realbits) + (_shift), 16),	\
22462306a36Sopenharmony_ci		.shift = (_shift),				\
22562306a36Sopenharmony_ci		.endianness = IIO_CPU,				\
22662306a36Sopenharmony_ci	},							\
22762306a36Sopenharmony_ci	.event_spec = (_event_spec),				\
22862306a36Sopenharmony_ci	.num_event_specs = (_num_event_specs),			\
22962306a36Sopenharmony_ci	.datasheet_name = "AIN"#_chan"-AIN"#_chan2,		\
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistruct ads1015_channel_data {
23362306a36Sopenharmony_ci	bool enabled;
23462306a36Sopenharmony_ci	unsigned int pga;
23562306a36Sopenharmony_ci	unsigned int data_rate;
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistruct ads1015_thresh_data {
23962306a36Sopenharmony_ci	unsigned int comp_queue;
24062306a36Sopenharmony_ci	int high_thresh;
24162306a36Sopenharmony_ci	int low_thresh;
24262306a36Sopenharmony_ci};
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistruct ads1015_data {
24562306a36Sopenharmony_ci	struct regmap *regmap;
24662306a36Sopenharmony_ci	/*
24762306a36Sopenharmony_ci	 * Protects ADC ops, e.g: concurrent sysfs/buffered
24862306a36Sopenharmony_ci	 * data reads, configuration updates
24962306a36Sopenharmony_ci	 */
25062306a36Sopenharmony_ci	struct mutex lock;
25162306a36Sopenharmony_ci	struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	unsigned int event_channel;
25462306a36Sopenharmony_ci	unsigned int comp_mode;
25562306a36Sopenharmony_ci	struct ads1015_thresh_data thresh_data[ADS1015_CHANNELS];
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	const struct ads1015_chip_data *chip;
25862306a36Sopenharmony_ci	/*
25962306a36Sopenharmony_ci	 * Set to true when the ADC is switched to the continuous-conversion
26062306a36Sopenharmony_ci	 * mode and exits from a power-down state.  This flag is used to avoid
26162306a36Sopenharmony_ci	 * getting the stale result from the conversion register.
26262306a36Sopenharmony_ci	 */
26362306a36Sopenharmony_ci	bool conv_invalid;
26462306a36Sopenharmony_ci};
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic bool ads1015_event_channel_enabled(struct ads1015_data *data)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	return (data->event_channel != ADS1015_CHANNELS);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void ads1015_event_channel_enable(struct ads1015_data *data, int chan,
27262306a36Sopenharmony_ci					 int comp_mode)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	WARN_ON(ads1015_event_channel_enabled(data));
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	data->event_channel = chan;
27762306a36Sopenharmony_ci	data->comp_mode = comp_mode;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic void ads1015_event_channel_disable(struct ads1015_data *data, int chan)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	data->event_channel = ADS1015_CHANNELS;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic const struct regmap_range ads1015_writeable_ranges[] = {
28662306a36Sopenharmony_ci	regmap_reg_range(ADS1015_CFG_REG, ADS1015_HI_THRESH_REG),
28762306a36Sopenharmony_ci};
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic const struct regmap_access_table ads1015_writeable_table = {
29062306a36Sopenharmony_ci	.yes_ranges = ads1015_writeable_ranges,
29162306a36Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(ads1015_writeable_ranges),
29262306a36Sopenharmony_ci};
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic const struct regmap_config ads1015_regmap_config = {
29562306a36Sopenharmony_ci	.reg_bits = 8,
29662306a36Sopenharmony_ci	.val_bits = 16,
29762306a36Sopenharmony_ci	.max_register = ADS1015_HI_THRESH_REG,
29862306a36Sopenharmony_ci	.wr_table = &ads1015_writeable_table,
29962306a36Sopenharmony_ci};
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic const struct regmap_range tla2024_writeable_ranges[] = {
30262306a36Sopenharmony_ci	regmap_reg_range(ADS1015_CFG_REG, ADS1015_CFG_REG),
30362306a36Sopenharmony_ci};
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic const struct regmap_access_table tla2024_writeable_table = {
30662306a36Sopenharmony_ci	.yes_ranges = tla2024_writeable_ranges,
30762306a36Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(tla2024_writeable_ranges),
30862306a36Sopenharmony_ci};
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic const struct regmap_config tla2024_regmap_config = {
31162306a36Sopenharmony_ci	.reg_bits = 8,
31262306a36Sopenharmony_ci	.val_bits = 16,
31362306a36Sopenharmony_ci	.max_register = ADS1015_CFG_REG,
31462306a36Sopenharmony_ci	.wr_table = &tla2024_writeable_table,
31562306a36Sopenharmony_ci};
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic const struct iio_chan_spec ads1015_channels[] = {
31862306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(0, 1, ADS1015_AIN0_AIN1, 12, 4,
31962306a36Sopenharmony_ci			    ads1015_events, ARRAY_SIZE(ads1015_events)),
32062306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(0, 3, ADS1015_AIN0_AIN3, 12, 4,
32162306a36Sopenharmony_ci			    ads1015_events, ARRAY_SIZE(ads1015_events)),
32262306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(1, 3, ADS1015_AIN1_AIN3, 12, 4,
32362306a36Sopenharmony_ci			    ads1015_events, ARRAY_SIZE(ads1015_events)),
32462306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(2, 3, ADS1015_AIN2_AIN3, 12, 4,
32562306a36Sopenharmony_ci			    ads1015_events, ARRAY_SIZE(ads1015_events)),
32662306a36Sopenharmony_ci	ADS1015_V_CHAN(0, ADS1015_AIN0, 12, 4,
32762306a36Sopenharmony_ci		       ads1015_events, ARRAY_SIZE(ads1015_events)),
32862306a36Sopenharmony_ci	ADS1015_V_CHAN(1, ADS1015_AIN1, 12, 4,
32962306a36Sopenharmony_ci		       ads1015_events, ARRAY_SIZE(ads1015_events)),
33062306a36Sopenharmony_ci	ADS1015_V_CHAN(2, ADS1015_AIN2, 12, 4,
33162306a36Sopenharmony_ci		       ads1015_events, ARRAY_SIZE(ads1015_events)),
33262306a36Sopenharmony_ci	ADS1015_V_CHAN(3, ADS1015_AIN3, 12, 4,
33362306a36Sopenharmony_ci		       ads1015_events, ARRAY_SIZE(ads1015_events)),
33462306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
33562306a36Sopenharmony_ci};
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic const struct iio_chan_spec ads1115_channels[] = {
33862306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(0, 1, ADS1015_AIN0_AIN1, 16, 0,
33962306a36Sopenharmony_ci			    ads1015_events, ARRAY_SIZE(ads1015_events)),
34062306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(0, 3, ADS1015_AIN0_AIN3, 16, 0,
34162306a36Sopenharmony_ci			    ads1015_events, ARRAY_SIZE(ads1015_events)),
34262306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(1, 3, ADS1015_AIN1_AIN3, 16, 0,
34362306a36Sopenharmony_ci			    ads1015_events, ARRAY_SIZE(ads1015_events)),
34462306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(2, 3, ADS1015_AIN2_AIN3, 16, 0,
34562306a36Sopenharmony_ci			    ads1015_events, ARRAY_SIZE(ads1015_events)),
34662306a36Sopenharmony_ci	ADS1015_V_CHAN(0, ADS1015_AIN0, 16, 0,
34762306a36Sopenharmony_ci		       ads1015_events, ARRAY_SIZE(ads1015_events)),
34862306a36Sopenharmony_ci	ADS1015_V_CHAN(1, ADS1015_AIN1, 16, 0,
34962306a36Sopenharmony_ci		       ads1015_events, ARRAY_SIZE(ads1015_events)),
35062306a36Sopenharmony_ci	ADS1015_V_CHAN(2, ADS1015_AIN2, 16, 0,
35162306a36Sopenharmony_ci		       ads1015_events, ARRAY_SIZE(ads1015_events)),
35262306a36Sopenharmony_ci	ADS1015_V_CHAN(3, ADS1015_AIN3, 16, 0,
35362306a36Sopenharmony_ci		       ads1015_events, ARRAY_SIZE(ads1015_events)),
35462306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
35562306a36Sopenharmony_ci};
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic const struct iio_chan_spec tla2024_channels[] = {
35862306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(0, 1, ADS1015_AIN0_AIN1, 12, 4, NULL, 0),
35962306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(0, 3, ADS1015_AIN0_AIN3, 12, 4, NULL, 0),
36062306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(1, 3, ADS1015_AIN1_AIN3, 12, 4, NULL, 0),
36162306a36Sopenharmony_ci	ADS1015_V_DIFF_CHAN(2, 3, ADS1015_AIN2_AIN3, 12, 4, NULL, 0),
36262306a36Sopenharmony_ci	ADS1015_V_CHAN(0, ADS1015_AIN0, 12, 4, NULL, 0),
36362306a36Sopenharmony_ci	ADS1015_V_CHAN(1, ADS1015_AIN1, 12, 4, NULL, 0),
36462306a36Sopenharmony_ci	ADS1015_V_CHAN(2, ADS1015_AIN2, 12, 4, NULL, 0),
36562306a36Sopenharmony_ci	ADS1015_V_CHAN(3, ADS1015_AIN3, 12, 4, NULL, 0),
36662306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
36762306a36Sopenharmony_ci};
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci#ifdef CONFIG_PM
37162306a36Sopenharmony_cistatic int ads1015_set_power_state(struct ads1015_data *data, bool on)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	int ret;
37462306a36Sopenharmony_ci	struct device *dev = regmap_get_device(data->regmap);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (on) {
37762306a36Sopenharmony_ci		ret = pm_runtime_resume_and_get(dev);
37862306a36Sopenharmony_ci	} else {
37962306a36Sopenharmony_ci		pm_runtime_mark_last_busy(dev);
38062306a36Sopenharmony_ci		ret = pm_runtime_put_autosuspend(dev);
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return ret < 0 ? ret : 0;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci#else /* !CONFIG_PM */
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic int ads1015_set_power_state(struct ads1015_data *data, bool on)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	return 0;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci#endif /* !CONFIG_PM */
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic
39662306a36Sopenharmony_ciint ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	const int *data_rate = data->chip->data_rate;
39962306a36Sopenharmony_ci	int ret, pga, dr, dr_old, conv_time;
40062306a36Sopenharmony_ci	unsigned int old, mask, cfg;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (chan < 0 || chan >= ADS1015_CHANNELS)
40362306a36Sopenharmony_ci		return -EINVAL;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	ret = regmap_read(data->regmap, ADS1015_CFG_REG, &old);
40662306a36Sopenharmony_ci	if (ret)
40762306a36Sopenharmony_ci		return ret;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	pga = data->channel_data[chan].pga;
41062306a36Sopenharmony_ci	dr = data->channel_data[chan].data_rate;
41162306a36Sopenharmony_ci	mask = ADS1015_CFG_MUX_MASK | ADS1015_CFG_PGA_MASK |
41262306a36Sopenharmony_ci		ADS1015_CFG_DR_MASK;
41362306a36Sopenharmony_ci	cfg = chan << ADS1015_CFG_MUX_SHIFT | pga << ADS1015_CFG_PGA_SHIFT |
41462306a36Sopenharmony_ci		dr << ADS1015_CFG_DR_SHIFT;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (ads1015_event_channel_enabled(data)) {
41762306a36Sopenharmony_ci		mask |= ADS1015_CFG_COMP_QUE_MASK | ADS1015_CFG_COMP_MODE_MASK;
41862306a36Sopenharmony_ci		cfg |= data->thresh_data[chan].comp_queue <<
41962306a36Sopenharmony_ci				ADS1015_CFG_COMP_QUE_SHIFT |
42062306a36Sopenharmony_ci			data->comp_mode <<
42162306a36Sopenharmony_ci				ADS1015_CFG_COMP_MODE_SHIFT;
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	cfg = (old & ~mask) | (cfg & mask);
42562306a36Sopenharmony_ci	if (old != cfg) {
42662306a36Sopenharmony_ci		ret = regmap_write(data->regmap, ADS1015_CFG_REG, cfg);
42762306a36Sopenharmony_ci		if (ret)
42862306a36Sopenharmony_ci			return ret;
42962306a36Sopenharmony_ci		data->conv_invalid = true;
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci	if (data->conv_invalid) {
43262306a36Sopenharmony_ci		dr_old = (old & ADS1015_CFG_DR_MASK) >> ADS1015_CFG_DR_SHIFT;
43362306a36Sopenharmony_ci		conv_time = DIV_ROUND_UP(USEC_PER_SEC, data_rate[dr_old]);
43462306a36Sopenharmony_ci		conv_time += DIV_ROUND_UP(USEC_PER_SEC, data_rate[dr]);
43562306a36Sopenharmony_ci		conv_time += conv_time / 10; /* 10% internal clock inaccuracy */
43662306a36Sopenharmony_ci		usleep_range(conv_time, conv_time + 1);
43762306a36Sopenharmony_ci		data->conv_invalid = false;
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	return regmap_read(data->regmap, ADS1015_CONV_REG, val);
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic irqreturn_t ads1015_trigger_handler(int irq, void *p)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	struct iio_poll_func *pf = p;
44662306a36Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
44762306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
44862306a36Sopenharmony_ci	/* Ensure natural alignment of timestamp */
44962306a36Sopenharmony_ci	struct {
45062306a36Sopenharmony_ci		s16 chan;
45162306a36Sopenharmony_ci		s64 timestamp __aligned(8);
45262306a36Sopenharmony_ci	} scan;
45362306a36Sopenharmony_ci	int chan, ret, res;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	memset(&scan, 0, sizeof(scan));
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	mutex_lock(&data->lock);
45862306a36Sopenharmony_ci	chan = find_first_bit(indio_dev->active_scan_mask,
45962306a36Sopenharmony_ci			      indio_dev->masklength);
46062306a36Sopenharmony_ci	ret = ads1015_get_adc_result(data, chan, &res);
46162306a36Sopenharmony_ci	if (ret < 0) {
46262306a36Sopenharmony_ci		mutex_unlock(&data->lock);
46362306a36Sopenharmony_ci		goto err;
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	scan.chan = res;
46762306a36Sopenharmony_ci	mutex_unlock(&data->lock);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
47062306a36Sopenharmony_ci					   iio_get_time_ns(indio_dev));
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cierr:
47362306a36Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	return IRQ_HANDLED;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic int ads1015_set_scale(struct ads1015_data *data,
47962306a36Sopenharmony_ci			     struct iio_chan_spec const *chan,
48062306a36Sopenharmony_ci			     int scale, int uscale)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	int i;
48362306a36Sopenharmony_ci	int fullscale = div_s64((scale * 1000000LL + uscale) <<
48462306a36Sopenharmony_ci				(chan->scan_type.realbits - 1), 1000000);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ads1015_fullscale_range); i++) {
48762306a36Sopenharmony_ci		if (ads1015_fullscale_range[i] == fullscale) {
48862306a36Sopenharmony_ci			data->channel_data[chan->address].pga = i;
48962306a36Sopenharmony_ci			return 0;
49062306a36Sopenharmony_ci		}
49162306a36Sopenharmony_ci	}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	return -EINVAL;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic int ads1015_set_data_rate(struct ads1015_data *data, int chan, int rate)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	int i;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	for (i = 0; i < data->chip->data_rate_len; i++) {
50162306a36Sopenharmony_ci		if (data->chip->data_rate[i] == rate) {
50262306a36Sopenharmony_ci			data->channel_data[chan].data_rate = i;
50362306a36Sopenharmony_ci			return 0;
50462306a36Sopenharmony_ci		}
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	return -EINVAL;
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic int ads1015_read_avail(struct iio_dev *indio_dev,
51162306a36Sopenharmony_ci			      struct iio_chan_spec const *chan,
51262306a36Sopenharmony_ci			      const int **vals, int *type, int *length,
51362306a36Sopenharmony_ci			      long mask)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if (chan->type != IIO_VOLTAGE)
51862306a36Sopenharmony_ci		return -EINVAL;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	switch (mask) {
52162306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
52262306a36Sopenharmony_ci		*type = IIO_VAL_FRACTIONAL_LOG2;
52362306a36Sopenharmony_ci		*vals =  data->chip->scale;
52462306a36Sopenharmony_ci		*length = data->chip->scale_len;
52562306a36Sopenharmony_ci		return IIO_AVAIL_LIST;
52662306a36Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
52762306a36Sopenharmony_ci		*type = IIO_VAL_INT;
52862306a36Sopenharmony_ci		*vals = data->chip->data_rate;
52962306a36Sopenharmony_ci		*length = data->chip->data_rate_len;
53062306a36Sopenharmony_ci		return IIO_AVAIL_LIST;
53162306a36Sopenharmony_ci	default:
53262306a36Sopenharmony_ci		return -EINVAL;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic int ads1015_read_raw(struct iio_dev *indio_dev,
53762306a36Sopenharmony_ci			    struct iio_chan_spec const *chan, int *val,
53862306a36Sopenharmony_ci			    int *val2, long mask)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	int ret, idx;
54162306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	mutex_lock(&data->lock);
54462306a36Sopenharmony_ci	switch (mask) {
54562306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
54662306a36Sopenharmony_ci		ret = iio_device_claim_direct_mode(indio_dev);
54762306a36Sopenharmony_ci		if (ret)
54862306a36Sopenharmony_ci			break;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		if (ads1015_event_channel_enabled(data) &&
55162306a36Sopenharmony_ci				data->event_channel != chan->address) {
55262306a36Sopenharmony_ci			ret = -EBUSY;
55362306a36Sopenharmony_ci			goto release_direct;
55462306a36Sopenharmony_ci		}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		ret = ads1015_set_power_state(data, true);
55762306a36Sopenharmony_ci		if (ret < 0)
55862306a36Sopenharmony_ci			goto release_direct;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci		ret = ads1015_get_adc_result(data, chan->address, val);
56162306a36Sopenharmony_ci		if (ret < 0) {
56262306a36Sopenharmony_ci			ads1015_set_power_state(data, false);
56362306a36Sopenharmony_ci			goto release_direct;
56462306a36Sopenharmony_ci		}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci		*val = sign_extend32(*val >> chan->scan_type.shift,
56762306a36Sopenharmony_ci				     chan->scan_type.realbits - 1);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci		ret = ads1015_set_power_state(data, false);
57062306a36Sopenharmony_ci		if (ret < 0)
57162306a36Sopenharmony_ci			goto release_direct;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci		ret = IIO_VAL_INT;
57462306a36Sopenharmony_cirelease_direct:
57562306a36Sopenharmony_ci		iio_device_release_direct_mode(indio_dev);
57662306a36Sopenharmony_ci		break;
57762306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
57862306a36Sopenharmony_ci		idx = data->channel_data[chan->address].pga;
57962306a36Sopenharmony_ci		*val = ads1015_fullscale_range[idx];
58062306a36Sopenharmony_ci		*val2 = chan->scan_type.realbits - 1;
58162306a36Sopenharmony_ci		ret = IIO_VAL_FRACTIONAL_LOG2;
58262306a36Sopenharmony_ci		break;
58362306a36Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
58462306a36Sopenharmony_ci		idx = data->channel_data[chan->address].data_rate;
58562306a36Sopenharmony_ci		*val = data->chip->data_rate[idx];
58662306a36Sopenharmony_ci		ret = IIO_VAL_INT;
58762306a36Sopenharmony_ci		break;
58862306a36Sopenharmony_ci	default:
58962306a36Sopenharmony_ci		ret = -EINVAL;
59062306a36Sopenharmony_ci		break;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci	mutex_unlock(&data->lock);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	return ret;
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic int ads1015_write_raw(struct iio_dev *indio_dev,
59862306a36Sopenharmony_ci			     struct iio_chan_spec const *chan, int val,
59962306a36Sopenharmony_ci			     int val2, long mask)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
60262306a36Sopenharmony_ci	int ret;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	mutex_lock(&data->lock);
60562306a36Sopenharmony_ci	switch (mask) {
60662306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
60762306a36Sopenharmony_ci		ret = ads1015_set_scale(data, chan, val, val2);
60862306a36Sopenharmony_ci		break;
60962306a36Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
61062306a36Sopenharmony_ci		ret = ads1015_set_data_rate(data, chan->address, val);
61162306a36Sopenharmony_ci		break;
61262306a36Sopenharmony_ci	default:
61362306a36Sopenharmony_ci		ret = -EINVAL;
61462306a36Sopenharmony_ci		break;
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci	mutex_unlock(&data->lock);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	return ret;
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic int ads1015_read_event(struct iio_dev *indio_dev,
62262306a36Sopenharmony_ci	const struct iio_chan_spec *chan, enum iio_event_type type,
62362306a36Sopenharmony_ci	enum iio_event_direction dir, enum iio_event_info info, int *val,
62462306a36Sopenharmony_ci	int *val2)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
62762306a36Sopenharmony_ci	int ret;
62862306a36Sopenharmony_ci	unsigned int comp_queue;
62962306a36Sopenharmony_ci	int period;
63062306a36Sopenharmony_ci	int dr;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	mutex_lock(&data->lock);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	switch (info) {
63562306a36Sopenharmony_ci	case IIO_EV_INFO_VALUE:
63662306a36Sopenharmony_ci		*val = (dir == IIO_EV_DIR_RISING) ?
63762306a36Sopenharmony_ci			data->thresh_data[chan->address].high_thresh :
63862306a36Sopenharmony_ci			data->thresh_data[chan->address].low_thresh;
63962306a36Sopenharmony_ci		ret = IIO_VAL_INT;
64062306a36Sopenharmony_ci		break;
64162306a36Sopenharmony_ci	case IIO_EV_INFO_PERIOD:
64262306a36Sopenharmony_ci		dr = data->channel_data[chan->address].data_rate;
64362306a36Sopenharmony_ci		comp_queue = data->thresh_data[chan->address].comp_queue;
64462306a36Sopenharmony_ci		period = ads1015_comp_queue[comp_queue] *
64562306a36Sopenharmony_ci			USEC_PER_SEC / data->chip->data_rate[dr];
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		*val = period / USEC_PER_SEC;
64862306a36Sopenharmony_ci		*val2 = period % USEC_PER_SEC;
64962306a36Sopenharmony_ci		ret = IIO_VAL_INT_PLUS_MICRO;
65062306a36Sopenharmony_ci		break;
65162306a36Sopenharmony_ci	default:
65262306a36Sopenharmony_ci		ret = -EINVAL;
65362306a36Sopenharmony_ci		break;
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	mutex_unlock(&data->lock);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return ret;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int ads1015_write_event(struct iio_dev *indio_dev,
66262306a36Sopenharmony_ci	const struct iio_chan_spec *chan, enum iio_event_type type,
66362306a36Sopenharmony_ci	enum iio_event_direction dir, enum iio_event_info info, int val,
66462306a36Sopenharmony_ci	int val2)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
66762306a36Sopenharmony_ci	const int *data_rate = data->chip->data_rate;
66862306a36Sopenharmony_ci	int realbits = chan->scan_type.realbits;
66962306a36Sopenharmony_ci	int ret = 0;
67062306a36Sopenharmony_ci	long long period;
67162306a36Sopenharmony_ci	int i;
67262306a36Sopenharmony_ci	int dr;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	mutex_lock(&data->lock);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	switch (info) {
67762306a36Sopenharmony_ci	case IIO_EV_INFO_VALUE:
67862306a36Sopenharmony_ci		if (val >= 1 << (realbits - 1) || val < -1 << (realbits - 1)) {
67962306a36Sopenharmony_ci			ret = -EINVAL;
68062306a36Sopenharmony_ci			break;
68162306a36Sopenharmony_ci		}
68262306a36Sopenharmony_ci		if (dir == IIO_EV_DIR_RISING)
68362306a36Sopenharmony_ci			data->thresh_data[chan->address].high_thresh = val;
68462306a36Sopenharmony_ci		else
68562306a36Sopenharmony_ci			data->thresh_data[chan->address].low_thresh = val;
68662306a36Sopenharmony_ci		break;
68762306a36Sopenharmony_ci	case IIO_EV_INFO_PERIOD:
68862306a36Sopenharmony_ci		dr = data->channel_data[chan->address].data_rate;
68962306a36Sopenharmony_ci		period = val * USEC_PER_SEC + val2;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(ads1015_comp_queue) - 1; i++) {
69262306a36Sopenharmony_ci			if (period <= ads1015_comp_queue[i] *
69362306a36Sopenharmony_ci					USEC_PER_SEC / data_rate[dr])
69462306a36Sopenharmony_ci				break;
69562306a36Sopenharmony_ci		}
69662306a36Sopenharmony_ci		data->thresh_data[chan->address].comp_queue = i;
69762306a36Sopenharmony_ci		break;
69862306a36Sopenharmony_ci	default:
69962306a36Sopenharmony_ci		ret = -EINVAL;
70062306a36Sopenharmony_ci		break;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	mutex_unlock(&data->lock);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	return ret;
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic int ads1015_read_event_config(struct iio_dev *indio_dev,
70962306a36Sopenharmony_ci	const struct iio_chan_spec *chan, enum iio_event_type type,
71062306a36Sopenharmony_ci	enum iio_event_direction dir)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
71362306a36Sopenharmony_ci	int ret = 0;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	mutex_lock(&data->lock);
71662306a36Sopenharmony_ci	if (data->event_channel == chan->address) {
71762306a36Sopenharmony_ci		switch (dir) {
71862306a36Sopenharmony_ci		case IIO_EV_DIR_RISING:
71962306a36Sopenharmony_ci			ret = 1;
72062306a36Sopenharmony_ci			break;
72162306a36Sopenharmony_ci		case IIO_EV_DIR_EITHER:
72262306a36Sopenharmony_ci			ret = (data->comp_mode == ADS1015_CFG_COMP_MODE_WINDOW);
72362306a36Sopenharmony_ci			break;
72462306a36Sopenharmony_ci		default:
72562306a36Sopenharmony_ci			ret = -EINVAL;
72662306a36Sopenharmony_ci			break;
72762306a36Sopenharmony_ci		}
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci	mutex_unlock(&data->lock);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	return ret;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic int ads1015_enable_event_config(struct ads1015_data *data,
73562306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int comp_mode)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	int low_thresh = data->thresh_data[chan->address].low_thresh;
73862306a36Sopenharmony_ci	int high_thresh = data->thresh_data[chan->address].high_thresh;
73962306a36Sopenharmony_ci	int ret;
74062306a36Sopenharmony_ci	unsigned int val;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (ads1015_event_channel_enabled(data)) {
74362306a36Sopenharmony_ci		if (data->event_channel != chan->address ||
74462306a36Sopenharmony_ci			(data->comp_mode == ADS1015_CFG_COMP_MODE_TRAD &&
74562306a36Sopenharmony_ci				comp_mode == ADS1015_CFG_COMP_MODE_WINDOW))
74662306a36Sopenharmony_ci			return -EBUSY;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci		return 0;
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (comp_mode == ADS1015_CFG_COMP_MODE_TRAD) {
75262306a36Sopenharmony_ci		low_thresh = max(-1 << (chan->scan_type.realbits - 1),
75362306a36Sopenharmony_ci				high_thresh - 1);
75462306a36Sopenharmony_ci	}
75562306a36Sopenharmony_ci	ret = regmap_write(data->regmap, ADS1015_LO_THRESH_REG,
75662306a36Sopenharmony_ci			low_thresh << chan->scan_type.shift);
75762306a36Sopenharmony_ci	if (ret)
75862306a36Sopenharmony_ci		return ret;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	ret = regmap_write(data->regmap, ADS1015_HI_THRESH_REG,
76162306a36Sopenharmony_ci			high_thresh << chan->scan_type.shift);
76262306a36Sopenharmony_ci	if (ret)
76362306a36Sopenharmony_ci		return ret;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	ret = ads1015_set_power_state(data, true);
76662306a36Sopenharmony_ci	if (ret < 0)
76762306a36Sopenharmony_ci		return ret;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	ads1015_event_channel_enable(data, chan->address, comp_mode);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	ret = ads1015_get_adc_result(data, chan->address, &val);
77262306a36Sopenharmony_ci	if (ret) {
77362306a36Sopenharmony_ci		ads1015_event_channel_disable(data, chan->address);
77462306a36Sopenharmony_ci		ads1015_set_power_state(data, false);
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	return ret;
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic int ads1015_disable_event_config(struct ads1015_data *data,
78162306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int comp_mode)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	int ret;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	if (!ads1015_event_channel_enabled(data))
78662306a36Sopenharmony_ci		return 0;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (data->event_channel != chan->address)
78962306a36Sopenharmony_ci		return 0;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (data->comp_mode == ADS1015_CFG_COMP_MODE_TRAD &&
79262306a36Sopenharmony_ci			comp_mode == ADS1015_CFG_COMP_MODE_WINDOW)
79362306a36Sopenharmony_ci		return 0;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
79662306a36Sopenharmony_ci				ADS1015_CFG_COMP_QUE_MASK,
79762306a36Sopenharmony_ci				ADS1015_CFG_COMP_DISABLE <<
79862306a36Sopenharmony_ci					ADS1015_CFG_COMP_QUE_SHIFT);
79962306a36Sopenharmony_ci	if (ret)
80062306a36Sopenharmony_ci		return ret;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	ads1015_event_channel_disable(data, chan->address);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	return ads1015_set_power_state(data, false);
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic int ads1015_write_event_config(struct iio_dev *indio_dev,
80862306a36Sopenharmony_ci	const struct iio_chan_spec *chan, enum iio_event_type type,
80962306a36Sopenharmony_ci	enum iio_event_direction dir, int state)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
81262306a36Sopenharmony_ci	int ret;
81362306a36Sopenharmony_ci	int comp_mode = (dir == IIO_EV_DIR_EITHER) ?
81462306a36Sopenharmony_ci		ADS1015_CFG_COMP_MODE_WINDOW : ADS1015_CFG_COMP_MODE_TRAD;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	mutex_lock(&data->lock);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	/* Prevent from enabling both buffer and event at a time */
81962306a36Sopenharmony_ci	ret = iio_device_claim_direct_mode(indio_dev);
82062306a36Sopenharmony_ci	if (ret) {
82162306a36Sopenharmony_ci		mutex_unlock(&data->lock);
82262306a36Sopenharmony_ci		return ret;
82362306a36Sopenharmony_ci	}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	if (state)
82662306a36Sopenharmony_ci		ret = ads1015_enable_event_config(data, chan, comp_mode);
82762306a36Sopenharmony_ci	else
82862306a36Sopenharmony_ci		ret = ads1015_disable_event_config(data, chan, comp_mode);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	iio_device_release_direct_mode(indio_dev);
83162306a36Sopenharmony_ci	mutex_unlock(&data->lock);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	return ret;
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic irqreturn_t ads1015_event_handler(int irq, void *priv)
83762306a36Sopenharmony_ci{
83862306a36Sopenharmony_ci	struct iio_dev *indio_dev = priv;
83962306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
84062306a36Sopenharmony_ci	int val;
84162306a36Sopenharmony_ci	int ret;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	/* Clear the latched ALERT/RDY pin */
84462306a36Sopenharmony_ci	ret = regmap_read(data->regmap, ADS1015_CONV_REG, &val);
84562306a36Sopenharmony_ci	if (ret)
84662306a36Sopenharmony_ci		return IRQ_HANDLED;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (ads1015_event_channel_enabled(data)) {
84962306a36Sopenharmony_ci		enum iio_event_direction dir;
85062306a36Sopenharmony_ci		u64 code;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci		dir = data->comp_mode == ADS1015_CFG_COMP_MODE_TRAD ?
85362306a36Sopenharmony_ci					IIO_EV_DIR_RISING : IIO_EV_DIR_EITHER;
85462306a36Sopenharmony_ci		code = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, data->event_channel,
85562306a36Sopenharmony_ci					IIO_EV_TYPE_THRESH, dir);
85662306a36Sopenharmony_ci		iio_push_event(indio_dev, code, iio_get_time_ns(indio_dev));
85762306a36Sopenharmony_ci	}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	return IRQ_HANDLED;
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic int ads1015_buffer_preenable(struct iio_dev *indio_dev)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	/* Prevent from enabling both buffer and event at a time */
86762306a36Sopenharmony_ci	if (ads1015_event_channel_enabled(data))
86862306a36Sopenharmony_ci		return -EBUSY;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	return ads1015_set_power_state(iio_priv(indio_dev), true);
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_cistatic int ads1015_buffer_postdisable(struct iio_dev *indio_dev)
87462306a36Sopenharmony_ci{
87562306a36Sopenharmony_ci	return ads1015_set_power_state(iio_priv(indio_dev), false);
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic const struct iio_buffer_setup_ops ads1015_buffer_setup_ops = {
87962306a36Sopenharmony_ci	.preenable	= ads1015_buffer_preenable,
88062306a36Sopenharmony_ci	.postdisable	= ads1015_buffer_postdisable,
88162306a36Sopenharmony_ci	.validate_scan_mask = &iio_validate_scan_mask_onehot,
88262306a36Sopenharmony_ci};
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_cistatic const struct iio_info ads1015_info = {
88562306a36Sopenharmony_ci	.read_avail	= ads1015_read_avail,
88662306a36Sopenharmony_ci	.read_raw	= ads1015_read_raw,
88762306a36Sopenharmony_ci	.write_raw	= ads1015_write_raw,
88862306a36Sopenharmony_ci	.read_event_value = ads1015_read_event,
88962306a36Sopenharmony_ci	.write_event_value = ads1015_write_event,
89062306a36Sopenharmony_ci	.read_event_config = ads1015_read_event_config,
89162306a36Sopenharmony_ci	.write_event_config = ads1015_write_event_config,
89262306a36Sopenharmony_ci};
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_cistatic const struct iio_info tla2024_info = {
89562306a36Sopenharmony_ci	.read_avail	= ads1015_read_avail,
89662306a36Sopenharmony_ci	.read_raw	= ads1015_read_raw,
89762306a36Sopenharmony_ci	.write_raw	= ads1015_write_raw,
89862306a36Sopenharmony_ci};
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic int ads1015_client_get_channels_config(struct i2c_client *client)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	struct iio_dev *indio_dev = i2c_get_clientdata(client);
90362306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
90462306a36Sopenharmony_ci	struct device *dev = &client->dev;
90562306a36Sopenharmony_ci	struct fwnode_handle *node;
90662306a36Sopenharmony_ci	int i = -1;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	device_for_each_child_node(dev, node) {
90962306a36Sopenharmony_ci		u32 pval;
91062306a36Sopenharmony_ci		unsigned int channel;
91162306a36Sopenharmony_ci		unsigned int pga = ADS1015_DEFAULT_PGA;
91262306a36Sopenharmony_ci		unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci		if (fwnode_property_read_u32(node, "reg", &pval)) {
91562306a36Sopenharmony_ci			dev_err(dev, "invalid reg on %pfw\n", node);
91662306a36Sopenharmony_ci			continue;
91762306a36Sopenharmony_ci		}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci		channel = pval;
92062306a36Sopenharmony_ci		if (channel >= ADS1015_CHANNELS) {
92162306a36Sopenharmony_ci			dev_err(dev, "invalid channel index %d on %pfw\n",
92262306a36Sopenharmony_ci				channel, node);
92362306a36Sopenharmony_ci			continue;
92462306a36Sopenharmony_ci		}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci		if (!fwnode_property_read_u32(node, "ti,gain", &pval)) {
92762306a36Sopenharmony_ci			pga = pval;
92862306a36Sopenharmony_ci			if (pga > 6) {
92962306a36Sopenharmony_ci				dev_err(dev, "invalid gain on %pfw\n", node);
93062306a36Sopenharmony_ci				fwnode_handle_put(node);
93162306a36Sopenharmony_ci				return -EINVAL;
93262306a36Sopenharmony_ci			}
93362306a36Sopenharmony_ci		}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci		if (!fwnode_property_read_u32(node, "ti,datarate", &pval)) {
93662306a36Sopenharmony_ci			data_rate = pval;
93762306a36Sopenharmony_ci			if (data_rate > 7) {
93862306a36Sopenharmony_ci				dev_err(dev, "invalid data_rate on %pfw\n", node);
93962306a36Sopenharmony_ci				fwnode_handle_put(node);
94062306a36Sopenharmony_ci				return -EINVAL;
94162306a36Sopenharmony_ci			}
94262306a36Sopenharmony_ci		}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		data->channel_data[channel].pga = pga;
94562306a36Sopenharmony_ci		data->channel_data[channel].data_rate = data_rate;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci		i++;
94862306a36Sopenharmony_ci	}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	return i < 0 ? -EINVAL : 0;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_cistatic void ads1015_get_channels_config(struct i2c_client *client)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	unsigned int k;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	struct iio_dev *indio_dev = i2c_get_clientdata(client);
95862306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	if (!ads1015_client_get_channels_config(client))
96162306a36Sopenharmony_ci		return;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	/* fallback on default configuration */
96462306a36Sopenharmony_ci	for (k = 0; k < ADS1015_CHANNELS; ++k) {
96562306a36Sopenharmony_ci		data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
96662306a36Sopenharmony_ci		data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
96762306a36Sopenharmony_ci	}
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cistatic int ads1015_set_conv_mode(struct ads1015_data *data, int mode)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci	return regmap_update_bits(data->regmap, ADS1015_CFG_REG,
97362306a36Sopenharmony_ci				  ADS1015_CFG_MOD_MASK,
97462306a36Sopenharmony_ci				  mode << ADS1015_CFG_MOD_SHIFT);
97562306a36Sopenharmony_ci}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_cistatic int ads1015_probe(struct i2c_client *client)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	const struct i2c_device_id *id = i2c_client_get_device_id(client);
98062306a36Sopenharmony_ci	const struct ads1015_chip_data *chip;
98162306a36Sopenharmony_ci	struct iio_dev *indio_dev;
98262306a36Sopenharmony_ci	struct ads1015_data *data;
98362306a36Sopenharmony_ci	int ret;
98462306a36Sopenharmony_ci	int i;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	chip = device_get_match_data(&client->dev);
98762306a36Sopenharmony_ci	if (!chip)
98862306a36Sopenharmony_ci		chip = (const struct ads1015_chip_data *)id->driver_data;
98962306a36Sopenharmony_ci	if (!chip)
99062306a36Sopenharmony_ci		return dev_err_probe(&client->dev, -EINVAL, "Unknown chip\n");
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
99362306a36Sopenharmony_ci	if (!indio_dev)
99462306a36Sopenharmony_ci		return -ENOMEM;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	data = iio_priv(indio_dev);
99762306a36Sopenharmony_ci	i2c_set_clientdata(client, indio_dev);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	mutex_init(&data->lock);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	indio_dev->name = ADS1015_DRV_NAME;
100262306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	indio_dev->channels = chip->channels;
100562306a36Sopenharmony_ci	indio_dev->num_channels = chip->num_channels;
100662306a36Sopenharmony_ci	indio_dev->info = chip->info;
100762306a36Sopenharmony_ci	data->chip = chip;
100862306a36Sopenharmony_ci	data->event_channel = ADS1015_CHANNELS;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	/*
101162306a36Sopenharmony_ci	 * Set default lower and upper threshold to min and max value
101262306a36Sopenharmony_ci	 * respectively.
101362306a36Sopenharmony_ci	 */
101462306a36Sopenharmony_ci	for (i = 0; i < ADS1015_CHANNELS; i++) {
101562306a36Sopenharmony_ci		int realbits = indio_dev->channels[i].scan_type.realbits;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci		data->thresh_data[i].low_thresh = -1 << (realbits - 1);
101862306a36Sopenharmony_ci		data->thresh_data[i].high_thresh = (1 << (realbits - 1)) - 1;
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	/* we need to keep this ABI the same as used by hwmon ADS1015 driver */
102262306a36Sopenharmony_ci	ads1015_get_channels_config(client);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	data->regmap = devm_regmap_init_i2c(client, chip->has_comparator ?
102562306a36Sopenharmony_ci					    &ads1015_regmap_config :
102662306a36Sopenharmony_ci					    &tla2024_regmap_config);
102762306a36Sopenharmony_ci	if (IS_ERR(data->regmap)) {
102862306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to allocate register map\n");
102962306a36Sopenharmony_ci		return PTR_ERR(data->regmap);
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
103362306a36Sopenharmony_ci					      ads1015_trigger_handler,
103462306a36Sopenharmony_ci					      &ads1015_buffer_setup_ops);
103562306a36Sopenharmony_ci	if (ret < 0) {
103662306a36Sopenharmony_ci		dev_err(&client->dev, "iio triggered buffer setup failed\n");
103762306a36Sopenharmony_ci		return ret;
103862306a36Sopenharmony_ci	}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	if (client->irq && chip->has_comparator) {
104162306a36Sopenharmony_ci		unsigned long irq_trig =
104262306a36Sopenharmony_ci			irqd_get_trigger_type(irq_get_irq_data(client->irq));
104362306a36Sopenharmony_ci		unsigned int cfg_comp_mask = ADS1015_CFG_COMP_QUE_MASK |
104462306a36Sopenharmony_ci			ADS1015_CFG_COMP_LAT_MASK | ADS1015_CFG_COMP_POL_MASK;
104562306a36Sopenharmony_ci		unsigned int cfg_comp =
104662306a36Sopenharmony_ci			ADS1015_CFG_COMP_DISABLE << ADS1015_CFG_COMP_QUE_SHIFT |
104762306a36Sopenharmony_ci			1 << ADS1015_CFG_COMP_LAT_SHIFT;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci		switch (irq_trig) {
105062306a36Sopenharmony_ci		case IRQF_TRIGGER_LOW:
105162306a36Sopenharmony_ci			cfg_comp |= ADS1015_CFG_COMP_POL_LOW <<
105262306a36Sopenharmony_ci					ADS1015_CFG_COMP_POL_SHIFT;
105362306a36Sopenharmony_ci			break;
105462306a36Sopenharmony_ci		case IRQF_TRIGGER_HIGH:
105562306a36Sopenharmony_ci			cfg_comp |= ADS1015_CFG_COMP_POL_HIGH <<
105662306a36Sopenharmony_ci					ADS1015_CFG_COMP_POL_SHIFT;
105762306a36Sopenharmony_ci			break;
105862306a36Sopenharmony_ci		default:
105962306a36Sopenharmony_ci			return -EINVAL;
106062306a36Sopenharmony_ci		}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci		ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
106362306a36Sopenharmony_ci					cfg_comp_mask, cfg_comp);
106462306a36Sopenharmony_ci		if (ret)
106562306a36Sopenharmony_ci			return ret;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci		ret = devm_request_threaded_irq(&client->dev, client->irq,
106862306a36Sopenharmony_ci						NULL, ads1015_event_handler,
106962306a36Sopenharmony_ci						irq_trig | IRQF_ONESHOT,
107062306a36Sopenharmony_ci						client->name, indio_dev);
107162306a36Sopenharmony_ci		if (ret)
107262306a36Sopenharmony_ci			return ret;
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	ret = ads1015_set_conv_mode(data, ADS1015_CONTINUOUS);
107662306a36Sopenharmony_ci	if (ret)
107762306a36Sopenharmony_ci		return ret;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	data->conv_invalid = true;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	ret = pm_runtime_set_active(&client->dev);
108262306a36Sopenharmony_ci	if (ret)
108362306a36Sopenharmony_ci		return ret;
108462306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&client->dev, ADS1015_SLEEP_DELAY_MS);
108562306a36Sopenharmony_ci	pm_runtime_use_autosuspend(&client->dev);
108662306a36Sopenharmony_ci	pm_runtime_enable(&client->dev);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	ret = iio_device_register(indio_dev);
108962306a36Sopenharmony_ci	if (ret < 0) {
109062306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to register IIO device\n");
109162306a36Sopenharmony_ci		return ret;
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	return 0;
109562306a36Sopenharmony_ci}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_cistatic void ads1015_remove(struct i2c_client *client)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	struct iio_dev *indio_dev = i2c_get_clientdata(client);
110062306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
110162306a36Sopenharmony_ci	int ret;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	iio_device_unregister(indio_dev);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	pm_runtime_disable(&client->dev);
110662306a36Sopenharmony_ci	pm_runtime_set_suspended(&client->dev);
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	/* power down single shot mode */
110962306a36Sopenharmony_ci	ret = ads1015_set_conv_mode(data, ADS1015_SINGLESHOT);
111062306a36Sopenharmony_ci	if (ret)
111162306a36Sopenharmony_ci		dev_warn(&client->dev, "Failed to power down (%pe)\n",
111262306a36Sopenharmony_ci			 ERR_PTR(ret));
111362306a36Sopenharmony_ci}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci#ifdef CONFIG_PM
111662306a36Sopenharmony_cistatic int ads1015_runtime_suspend(struct device *dev)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
111962306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	return ads1015_set_conv_mode(data, ADS1015_SINGLESHOT);
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_cistatic int ads1015_runtime_resume(struct device *dev)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
112762306a36Sopenharmony_ci	struct ads1015_data *data = iio_priv(indio_dev);
112862306a36Sopenharmony_ci	int ret;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	ret = ads1015_set_conv_mode(data, ADS1015_CONTINUOUS);
113162306a36Sopenharmony_ci	if (!ret)
113262306a36Sopenharmony_ci		data->conv_invalid = true;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	return ret;
113562306a36Sopenharmony_ci}
113662306a36Sopenharmony_ci#endif
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_cistatic const struct dev_pm_ops ads1015_pm_ops = {
113962306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(ads1015_runtime_suspend,
114062306a36Sopenharmony_ci			   ads1015_runtime_resume, NULL)
114162306a36Sopenharmony_ci};
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_cistatic const struct ads1015_chip_data ads1015_data = {
114462306a36Sopenharmony_ci	.channels	= ads1015_channels,
114562306a36Sopenharmony_ci	.num_channels	= ARRAY_SIZE(ads1015_channels),
114662306a36Sopenharmony_ci	.info		= &ads1015_info,
114762306a36Sopenharmony_ci	.data_rate	= ads1015_data_rate,
114862306a36Sopenharmony_ci	.data_rate_len	= ARRAY_SIZE(ads1015_data_rate),
114962306a36Sopenharmony_ci	.scale		= ads1015_scale,
115062306a36Sopenharmony_ci	.scale_len	= ARRAY_SIZE(ads1015_scale),
115162306a36Sopenharmony_ci	.has_comparator	= true,
115262306a36Sopenharmony_ci};
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_cistatic const struct ads1015_chip_data ads1115_data = {
115562306a36Sopenharmony_ci	.channels	= ads1115_channels,
115662306a36Sopenharmony_ci	.num_channels	= ARRAY_SIZE(ads1115_channels),
115762306a36Sopenharmony_ci	.info		= &ads1015_info,
115862306a36Sopenharmony_ci	.data_rate	= ads1115_data_rate,
115962306a36Sopenharmony_ci	.data_rate_len	= ARRAY_SIZE(ads1115_data_rate),
116062306a36Sopenharmony_ci	.scale		= ads1115_scale,
116162306a36Sopenharmony_ci	.scale_len	= ARRAY_SIZE(ads1115_scale),
116262306a36Sopenharmony_ci	.has_comparator	= true,
116362306a36Sopenharmony_ci};
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_cistatic const struct ads1015_chip_data tla2024_data = {
116662306a36Sopenharmony_ci	.channels	= tla2024_channels,
116762306a36Sopenharmony_ci	.num_channels	= ARRAY_SIZE(tla2024_channels),
116862306a36Sopenharmony_ci	.info		= &tla2024_info,
116962306a36Sopenharmony_ci	.data_rate	= ads1015_data_rate,
117062306a36Sopenharmony_ci	.data_rate_len	= ARRAY_SIZE(ads1015_data_rate),
117162306a36Sopenharmony_ci	.scale		= ads1015_scale,
117262306a36Sopenharmony_ci	.scale_len	= ARRAY_SIZE(ads1015_scale),
117362306a36Sopenharmony_ci	.has_comparator	= false,
117462306a36Sopenharmony_ci};
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_cistatic const struct i2c_device_id ads1015_id[] = {
117762306a36Sopenharmony_ci	{ "ads1015", (kernel_ulong_t)&ads1015_data },
117862306a36Sopenharmony_ci	{ "ads1115", (kernel_ulong_t)&ads1115_data },
117962306a36Sopenharmony_ci	{ "tla2024", (kernel_ulong_t)&tla2024_data },
118062306a36Sopenharmony_ci	{}
118162306a36Sopenharmony_ci};
118262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ads1015_id);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_cistatic const struct of_device_id ads1015_of_match[] = {
118562306a36Sopenharmony_ci	{ .compatible = "ti,ads1015", .data = &ads1015_data },
118662306a36Sopenharmony_ci	{ .compatible = "ti,ads1115", .data = &ads1115_data },
118762306a36Sopenharmony_ci	{ .compatible = "ti,tla2024", .data = &tla2024_data },
118862306a36Sopenharmony_ci	{}
118962306a36Sopenharmony_ci};
119062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ads1015_of_match);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_cistatic struct i2c_driver ads1015_driver = {
119362306a36Sopenharmony_ci	.driver = {
119462306a36Sopenharmony_ci		.name = ADS1015_DRV_NAME,
119562306a36Sopenharmony_ci		.of_match_table = ads1015_of_match,
119662306a36Sopenharmony_ci		.pm = &ads1015_pm_ops,
119762306a36Sopenharmony_ci	},
119862306a36Sopenharmony_ci	.probe		= ads1015_probe,
119962306a36Sopenharmony_ci	.remove		= ads1015_remove,
120062306a36Sopenharmony_ci	.id_table	= ads1015_id,
120162306a36Sopenharmony_ci};
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_cimodule_i2c_driver(ads1015_driver);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ciMODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
120662306a36Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments ADS1015 ADC driver");
120762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1208