xref: /openbmc/linux/drivers/iio/accel/adxl367.c (revision 73d42ed4)
1cbab791cSCosmin Tanislav // SPDX-License-Identifier: GPL-2.0+
2cbab791cSCosmin Tanislav /*
3cbab791cSCosmin Tanislav  * Copyright (C) 2021 Analog Devices, Inc.
4cbab791cSCosmin Tanislav  * Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
5cbab791cSCosmin Tanislav  */
6cbab791cSCosmin Tanislav 
7cbab791cSCosmin Tanislav #include <linux/bitfield.h>
8cbab791cSCosmin Tanislav #include <linux/bitops.h>
9cbab791cSCosmin Tanislav #include <linux/iio/buffer.h>
10cbab791cSCosmin Tanislav #include <linux/iio/events.h>
11cbab791cSCosmin Tanislav #include <linux/iio/iio.h>
12cbab791cSCosmin Tanislav #include <linux/iio/kfifo_buf.h>
13cbab791cSCosmin Tanislav #include <linux/iio/sysfs.h>
14cbab791cSCosmin Tanislav #include <linux/interrupt.h>
15cbab791cSCosmin Tanislav #include <linux/irq.h>
16cbab791cSCosmin Tanislav #include <linux/mod_devicetable.h>
17cbab791cSCosmin Tanislav #include <linux/regmap.h>
18cbab791cSCosmin Tanislav #include <linux/regulator/consumer.h>
19cbab791cSCosmin Tanislav #include <asm/unaligned.h>
20cbab791cSCosmin Tanislav 
21cbab791cSCosmin Tanislav #include "adxl367.h"
22cbab791cSCosmin Tanislav 
23cbab791cSCosmin Tanislav #define ADXL367_REG_DEVID		0x00
24cbab791cSCosmin Tanislav #define ADXL367_DEVID_AD		0xAD
25cbab791cSCosmin Tanislav 
26cbab791cSCosmin Tanislav #define ADXL367_REG_STATUS		0x0B
27cbab791cSCosmin Tanislav #define ADXL367_STATUS_INACT_MASK	BIT(5)
28cbab791cSCosmin Tanislav #define ADXL367_STATUS_ACT_MASK		BIT(4)
29cbab791cSCosmin Tanislav #define ADXL367_STATUS_FIFO_FULL_MASK	BIT(2)
30cbab791cSCosmin Tanislav 
31cbab791cSCosmin Tanislav #define ADXL367_FIFO_ENT_H_MASK		GENMASK(1, 0)
32cbab791cSCosmin Tanislav 
33cbab791cSCosmin Tanislav #define ADXL367_REG_X_DATA_H		0x0E
34cbab791cSCosmin Tanislav #define ADXL367_REG_Y_DATA_H		0x10
35cbab791cSCosmin Tanislav #define ADXL367_REG_Z_DATA_H		0x12
36cbab791cSCosmin Tanislav #define ADXL367_REG_TEMP_DATA_H		0x14
37cbab791cSCosmin Tanislav #define ADXL367_REG_EX_ADC_DATA_H	0x16
38cbab791cSCosmin Tanislav #define ADXL367_DATA_MASK		GENMASK(15, 2)
39cbab791cSCosmin Tanislav 
40cbab791cSCosmin Tanislav #define ADXL367_TEMP_25C		165
41cbab791cSCosmin Tanislav #define ADXL367_TEMP_PER_C		54
42cbab791cSCosmin Tanislav 
43cbab791cSCosmin Tanislav #define ADXL367_VOLTAGE_OFFSET		8192
44cbab791cSCosmin Tanislav #define ADXL367_VOLTAGE_MAX_MV		1000
45cbab791cSCosmin Tanislav #define ADXL367_VOLTAGE_MAX_RAW		GENMASK(13, 0)
46cbab791cSCosmin Tanislav 
47cbab791cSCosmin Tanislav #define ADXL367_REG_RESET		0x1F
48cbab791cSCosmin Tanislav #define ADXL367_RESET_CODE		0x52
49cbab791cSCosmin Tanislav 
50cbab791cSCosmin Tanislav #define ADXL367_REG_THRESH_ACT_H	0x20
51cbab791cSCosmin Tanislav #define ADXL367_REG_THRESH_INACT_H	0x23
52cbab791cSCosmin Tanislav #define ADXL367_THRESH_MAX		GENMASK(12, 0)
53cbab791cSCosmin Tanislav #define ADXL367_THRESH_VAL_H_MASK	GENMASK(12, 6)
54cbab791cSCosmin Tanislav #define ADXL367_THRESH_H_MASK		GENMASK(6, 0)
55cbab791cSCosmin Tanislav #define ADXL367_THRESH_VAL_L_MASK	GENMASK(5, 0)
56cbab791cSCosmin Tanislav #define ADXL367_THRESH_L_MASK		GENMASK(7, 2)
57cbab791cSCosmin Tanislav 
58cbab791cSCosmin Tanislav #define ADXL367_REG_TIME_ACT		0x22
59cbab791cSCosmin Tanislav #define ADXL367_REG_TIME_INACT_H	0x25
60cbab791cSCosmin Tanislav #define ADXL367_TIME_ACT_MAX		GENMASK(7, 0)
61cbab791cSCosmin Tanislav #define ADXL367_TIME_INACT_MAX		GENMASK(15, 0)
62cbab791cSCosmin Tanislav #define ADXL367_TIME_INACT_VAL_H_MASK	GENMASK(15, 8)
63cbab791cSCosmin Tanislav #define ADXL367_TIME_INACT_H_MASK	GENMASK(7, 0)
64cbab791cSCosmin Tanislav #define ADXL367_TIME_INACT_VAL_L_MASK	GENMASK(7, 0)
65cbab791cSCosmin Tanislav #define ADXL367_TIME_INACT_L_MASK	GENMASK(7, 0)
66cbab791cSCosmin Tanislav 
67cbab791cSCosmin Tanislav #define ADXL367_REG_ACT_INACT_CTL	0x27
68cbab791cSCosmin Tanislav #define ADXL367_ACT_EN_MASK		GENMASK(1, 0)
69cbab791cSCosmin Tanislav #define ADXL367_ACT_LINKLOOP_MASK	GENMASK(5, 4)
70cbab791cSCosmin Tanislav 
71cbab791cSCosmin Tanislav #define ADXL367_REG_FIFO_CTL		0x28
72cbab791cSCosmin Tanislav #define ADXL367_FIFO_CTL_FORMAT_MASK	GENMASK(6, 3)
73cbab791cSCosmin Tanislav #define ADXL367_FIFO_CTL_MODE_MASK	GENMASK(1, 0)
74cbab791cSCosmin Tanislav 
75cbab791cSCosmin Tanislav #define ADXL367_REG_FIFO_SAMPLES	0x29
76cbab791cSCosmin Tanislav #define ADXL367_FIFO_SIZE		512
77cbab791cSCosmin Tanislav #define ADXL367_FIFO_MAX_WATERMARK	511
78cbab791cSCosmin Tanislav 
79cbab791cSCosmin Tanislav #define ADXL367_SAMPLES_VAL_H_MASK	BIT(8)
80cbab791cSCosmin Tanislav #define ADXL367_SAMPLES_H_MASK		BIT(2)
81cbab791cSCosmin Tanislav #define ADXL367_SAMPLES_VAL_L_MASK	GENMASK(7, 0)
82cbab791cSCosmin Tanislav #define ADXL367_SAMPLES_L_MASK		GENMASK(7, 0)
83cbab791cSCosmin Tanislav 
84cbab791cSCosmin Tanislav #define ADXL367_REG_INT1_MAP		0x2A
85cbab791cSCosmin Tanislav #define ADXL367_INT_INACT_MASK		BIT(5)
86cbab791cSCosmin Tanislav #define ADXL367_INT_ACT_MASK		BIT(4)
87cbab791cSCosmin Tanislav #define ADXL367_INT_FIFO_WATERMARK_MASK	BIT(2)
88cbab791cSCosmin Tanislav 
89cbab791cSCosmin Tanislav #define ADXL367_REG_FILTER_CTL		0x2C
90cbab791cSCosmin Tanislav #define ADXL367_FILTER_CTL_RANGE_MASK	GENMASK(7, 6)
91cbab791cSCosmin Tanislav #define ADXL367_2G_RANGE_1G		4095
92cbab791cSCosmin Tanislav #define ADXL367_2G_RANGE_100MG		409
93cbab791cSCosmin Tanislav #define ADXL367_FILTER_CTL_ODR_MASK	GENMASK(2, 0)
94cbab791cSCosmin Tanislav 
95cbab791cSCosmin Tanislav #define ADXL367_REG_POWER_CTL		0x2D
96cbab791cSCosmin Tanislav #define ADXL367_POWER_CTL_MODE_MASK	GENMASK(1, 0)
97cbab791cSCosmin Tanislav 
98cbab791cSCosmin Tanislav #define ADXL367_REG_ADC_CTL		0x3C
99cbab791cSCosmin Tanislav #define ADXL367_REG_TEMP_CTL		0x3D
100cbab791cSCosmin Tanislav #define ADXL367_ADC_EN_MASK		BIT(0)
101cbab791cSCosmin Tanislav 
102cbab791cSCosmin Tanislav enum adxl367_range {
103cbab791cSCosmin Tanislav 	ADXL367_2G_RANGE,
104cbab791cSCosmin Tanislav 	ADXL367_4G_RANGE,
105cbab791cSCosmin Tanislav 	ADXL367_8G_RANGE,
106cbab791cSCosmin Tanislav };
107cbab791cSCosmin Tanislav 
108cbab791cSCosmin Tanislav enum adxl367_fifo_mode {
109cbab791cSCosmin Tanislav 	ADXL367_FIFO_MODE_DISABLED = 0b00,
110cbab791cSCosmin Tanislav 	ADXL367_FIFO_MODE_STREAM = 0b10,
111cbab791cSCosmin Tanislav };
112cbab791cSCosmin Tanislav 
113cbab791cSCosmin Tanislav enum adxl367_fifo_format {
114cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_XYZ,
115cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_X,
116cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_Y,
117cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_Z,
118cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_XYZT,
119cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_XT,
120cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_YT,
121cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_ZT,
122cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_XYZA,
123cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_XA,
124cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_YA,
125cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_ZA,
126cbab791cSCosmin Tanislav };
127cbab791cSCosmin Tanislav 
128cbab791cSCosmin Tanislav enum adxl367_op_mode {
129cbab791cSCosmin Tanislav 	ADXL367_OP_STANDBY = 0b00,
130cbab791cSCosmin Tanislav 	ADXL367_OP_MEASURE = 0b10,
131cbab791cSCosmin Tanislav };
132cbab791cSCosmin Tanislav 
133cbab791cSCosmin Tanislav enum adxl367_act_proc_mode {
134cbab791cSCosmin Tanislav 	ADXL367_LOOPED = 0b11,
135cbab791cSCosmin Tanislav };
136cbab791cSCosmin Tanislav 
137cbab791cSCosmin Tanislav enum adxl367_act_en_mode {
138cbab791cSCosmin Tanislav 	ADXL367_ACT_DISABLED = 0b00,
139cbab791cSCosmin Tanislav 	ADCL367_ACT_REF_ENABLED = 0b11,
140cbab791cSCosmin Tanislav };
141cbab791cSCosmin Tanislav 
142cbab791cSCosmin Tanislav enum adxl367_activity_type {
143cbab791cSCosmin Tanislav 	ADXL367_ACTIVITY,
144cbab791cSCosmin Tanislav 	ADXL367_INACTIVITY,
145cbab791cSCosmin Tanislav };
146cbab791cSCosmin Tanislav 
147cbab791cSCosmin Tanislav enum adxl367_odr {
148cbab791cSCosmin Tanislav 	ADXL367_ODR_12P5HZ,
149cbab791cSCosmin Tanislav 	ADXL367_ODR_25HZ,
150cbab791cSCosmin Tanislav 	ADXL367_ODR_50HZ,
151cbab791cSCosmin Tanislav 	ADXL367_ODR_100HZ,
152cbab791cSCosmin Tanislav 	ADXL367_ODR_200HZ,
153cbab791cSCosmin Tanislav 	ADXL367_ODR_400HZ,
154cbab791cSCosmin Tanislav };
155cbab791cSCosmin Tanislav 
156cbab791cSCosmin Tanislav struct adxl367_state {
157cbab791cSCosmin Tanislav 	const struct adxl367_ops	*ops;
158cbab791cSCosmin Tanislav 	void				*context;
159cbab791cSCosmin Tanislav 
160cbab791cSCosmin Tanislav 	struct device			*dev;
161cbab791cSCosmin Tanislav 	struct regmap			*regmap;
162cbab791cSCosmin Tanislav 
163cbab791cSCosmin Tanislav 	/*
164cbab791cSCosmin Tanislav 	 * Synchronize access to members of driver state, and ensure atomicity
165cbab791cSCosmin Tanislav 	 * of consecutive regmap operations.
166cbab791cSCosmin Tanislav 	 */
167cbab791cSCosmin Tanislav 	struct mutex		lock;
168cbab791cSCosmin Tanislav 
169cbab791cSCosmin Tanislav 	enum adxl367_odr	odr;
170cbab791cSCosmin Tanislav 	enum adxl367_range	range;
171cbab791cSCosmin Tanislav 
172cbab791cSCosmin Tanislav 	unsigned int	act_threshold;
173cbab791cSCosmin Tanislav 	unsigned int	act_time_ms;
174cbab791cSCosmin Tanislav 	unsigned int	inact_threshold;
175cbab791cSCosmin Tanislav 	unsigned int	inact_time_ms;
176cbab791cSCosmin Tanislav 
177cbab791cSCosmin Tanislav 	unsigned int	fifo_set_size;
178cbab791cSCosmin Tanislav 	unsigned int	fifo_watermark;
179cbab791cSCosmin Tanislav 
180e1f956a8SJonathan Cameron 	__be16		fifo_buf[ADXL367_FIFO_SIZE] __aligned(IIO_DMA_MINALIGN);
181cbab791cSCosmin Tanislav 	__be16		sample_buf;
182cbab791cSCosmin Tanislav 	u8		act_threshold_buf[2];
183cbab791cSCosmin Tanislav 	u8		inact_time_buf[2];
184cbab791cSCosmin Tanislav 	u8		status_buf[3];
185cbab791cSCosmin Tanislav };
186cbab791cSCosmin Tanislav 
187cbab791cSCosmin Tanislav static const unsigned int adxl367_threshold_h_reg_tbl[] = {
188cbab791cSCosmin Tanislav 	[ADXL367_ACTIVITY]   = ADXL367_REG_THRESH_ACT_H,
189cbab791cSCosmin Tanislav 	[ADXL367_INACTIVITY] = ADXL367_REG_THRESH_INACT_H,
190cbab791cSCosmin Tanislav };
191cbab791cSCosmin Tanislav 
192cbab791cSCosmin Tanislav static const unsigned int adxl367_act_en_shift_tbl[] = {
193cbab791cSCosmin Tanislav 	[ADXL367_ACTIVITY]   = 0,
194cbab791cSCosmin Tanislav 	[ADXL367_INACTIVITY] = 2,
195cbab791cSCosmin Tanislav };
196cbab791cSCosmin Tanislav 
197cbab791cSCosmin Tanislav static const unsigned int adxl367_act_int_mask_tbl[] = {
198cbab791cSCosmin Tanislav 	[ADXL367_ACTIVITY]   = ADXL367_INT_ACT_MASK,
199cbab791cSCosmin Tanislav 	[ADXL367_INACTIVITY] = ADXL367_INT_INACT_MASK,
200cbab791cSCosmin Tanislav };
201cbab791cSCosmin Tanislav 
202cbab791cSCosmin Tanislav static const int adxl367_samp_freq_tbl[][2] = {
203cbab791cSCosmin Tanislav 	[ADXL367_ODR_12P5HZ] = {12, 500000},
204cbab791cSCosmin Tanislav 	[ADXL367_ODR_25HZ]   = {25, 0},
205cbab791cSCosmin Tanislav 	[ADXL367_ODR_50HZ]   = {50, 0},
206cbab791cSCosmin Tanislav 	[ADXL367_ODR_100HZ]  = {100, 0},
207cbab791cSCosmin Tanislav 	[ADXL367_ODR_200HZ]  = {200, 0},
208cbab791cSCosmin Tanislav 	[ADXL367_ODR_400HZ]  = {400, 0},
209cbab791cSCosmin Tanislav };
210cbab791cSCosmin Tanislav 
211cbab791cSCosmin Tanislav /* (g * 2) * 9.80665 * 1000000 / (2^14 - 1) */
212cbab791cSCosmin Tanislav static const int adxl367_range_scale_tbl[][2] = {
213cbab791cSCosmin Tanislav 	[ADXL367_2G_RANGE] = {0, 2394347},
214cbab791cSCosmin Tanislav 	[ADXL367_4G_RANGE] = {0, 4788695},
215cbab791cSCosmin Tanislav 	[ADXL367_8G_RANGE] = {0, 9577391},
216cbab791cSCosmin Tanislav };
217cbab791cSCosmin Tanislav 
218cbab791cSCosmin Tanislav static const int adxl367_range_scale_factor_tbl[] = {
219cbab791cSCosmin Tanislav 	[ADXL367_2G_RANGE] = 1,
220cbab791cSCosmin Tanislav 	[ADXL367_4G_RANGE] = 2,
221cbab791cSCosmin Tanislav 	[ADXL367_8G_RANGE] = 4,
222cbab791cSCosmin Tanislav };
223cbab791cSCosmin Tanislav 
224cbab791cSCosmin Tanislav enum {
225cbab791cSCosmin Tanislav 	ADXL367_X_CHANNEL_INDEX,
226cbab791cSCosmin Tanislav 	ADXL367_Y_CHANNEL_INDEX,
227cbab791cSCosmin Tanislav 	ADXL367_Z_CHANNEL_INDEX,
228cbab791cSCosmin Tanislav 	ADXL367_TEMP_CHANNEL_INDEX,
229cbab791cSCosmin Tanislav 	ADXL367_EX_ADC_CHANNEL_INDEX
230cbab791cSCosmin Tanislav };
231cbab791cSCosmin Tanislav 
232cbab791cSCosmin Tanislav #define ADXL367_X_CHANNEL_MASK		BIT(ADXL367_X_CHANNEL_INDEX)
233cbab791cSCosmin Tanislav #define ADXL367_Y_CHANNEL_MASK		BIT(ADXL367_Y_CHANNEL_INDEX)
234cbab791cSCosmin Tanislav #define ADXL367_Z_CHANNEL_MASK		BIT(ADXL367_Z_CHANNEL_INDEX)
235cbab791cSCosmin Tanislav #define ADXL367_TEMP_CHANNEL_MASK	BIT(ADXL367_TEMP_CHANNEL_INDEX)
236cbab791cSCosmin Tanislav #define ADXL367_EX_ADC_CHANNEL_MASK	BIT(ADXL367_EX_ADC_CHANNEL_INDEX)
237cbab791cSCosmin Tanislav 
238cbab791cSCosmin Tanislav static const enum adxl367_fifo_format adxl367_fifo_formats[] = {
239cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_X,
240cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_Y,
241cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_Z,
242cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_XT,
243cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_YT,
244cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_ZT,
245cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_XA,
246cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_YA,
247cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_ZA,
248cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_XYZ,
249cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_XYZT,
250cbab791cSCosmin Tanislav 	ADXL367_FIFO_FORMAT_XYZA,
251cbab791cSCosmin Tanislav };
252cbab791cSCosmin Tanislav 
253cbab791cSCosmin Tanislav static const unsigned long adxl367_channel_masks[] = {
254cbab791cSCosmin Tanislav 	ADXL367_X_CHANNEL_MASK,
255cbab791cSCosmin Tanislav 	ADXL367_Y_CHANNEL_MASK,
256cbab791cSCosmin Tanislav 	ADXL367_Z_CHANNEL_MASK,
257cbab791cSCosmin Tanislav 	ADXL367_X_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK,
258cbab791cSCosmin Tanislav 	ADXL367_Y_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK,
259cbab791cSCosmin Tanislav 	ADXL367_Z_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK,
260cbab791cSCosmin Tanislav 	ADXL367_X_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK,
261cbab791cSCosmin Tanislav 	ADXL367_Y_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK,
262cbab791cSCosmin Tanislav 	ADXL367_Z_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK,
263cbab791cSCosmin Tanislav 	ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK,
264cbab791cSCosmin Tanislav 	ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK |
265cbab791cSCosmin Tanislav 		ADXL367_TEMP_CHANNEL_MASK,
266cbab791cSCosmin Tanislav 	ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK |
267cbab791cSCosmin Tanislav 		ADXL367_EX_ADC_CHANNEL_MASK,
268cbab791cSCosmin Tanislav 	0,
269cbab791cSCosmin Tanislav };
270cbab791cSCosmin Tanislav 
adxl367_set_measure_en(struct adxl367_state * st,bool en)271cbab791cSCosmin Tanislav static int adxl367_set_measure_en(struct adxl367_state *st, bool en)
272cbab791cSCosmin Tanislav {
273cbab791cSCosmin Tanislav 	enum adxl367_op_mode op_mode = en ? ADXL367_OP_MEASURE
274cbab791cSCosmin Tanislav 					  : ADXL367_OP_STANDBY;
275cbab791cSCosmin Tanislav 	int ret;
276cbab791cSCosmin Tanislav 
277cbab791cSCosmin Tanislav 	ret = regmap_update_bits(st->regmap, ADXL367_REG_POWER_CTL,
278cbab791cSCosmin Tanislav 				 ADXL367_POWER_CTL_MODE_MASK,
279cbab791cSCosmin Tanislav 				 FIELD_PREP(ADXL367_POWER_CTL_MODE_MASK,
280cbab791cSCosmin Tanislav 					    op_mode));
281cbab791cSCosmin Tanislav 	if (ret)
282cbab791cSCosmin Tanislav 		return ret;
283cbab791cSCosmin Tanislav 
284cbab791cSCosmin Tanislav 	/*
285cbab791cSCosmin Tanislav 	 * Wait for acceleration output to settle after entering
286cbab791cSCosmin Tanislav 	 * measure mode.
287cbab791cSCosmin Tanislav 	 */
288cbab791cSCosmin Tanislav 	if (en)
289cbab791cSCosmin Tanislav 		msleep(100);
290cbab791cSCosmin Tanislav 
291cbab791cSCosmin Tanislav 	return 0;
292cbab791cSCosmin Tanislav }
293cbab791cSCosmin Tanislav 
adxl367_scale_act_thresholds(struct adxl367_state * st,enum adxl367_range old_range,enum adxl367_range new_range)294cbab791cSCosmin Tanislav static void adxl367_scale_act_thresholds(struct adxl367_state *st,
295cbab791cSCosmin Tanislav 					 enum adxl367_range old_range,
296cbab791cSCosmin Tanislav 					 enum adxl367_range new_range)
297cbab791cSCosmin Tanislav {
298cbab791cSCosmin Tanislav 	st->act_threshold = st->act_threshold
299cbab791cSCosmin Tanislav 			    * adxl367_range_scale_factor_tbl[old_range]
300cbab791cSCosmin Tanislav 			    / adxl367_range_scale_factor_tbl[new_range];
301cbab791cSCosmin Tanislav 	st->inact_threshold = st->inact_threshold
302cbab791cSCosmin Tanislav 			      * adxl367_range_scale_factor_tbl[old_range]
303cbab791cSCosmin Tanislav 			      / adxl367_range_scale_factor_tbl[new_range];
304cbab791cSCosmin Tanislav }
305cbab791cSCosmin Tanislav 
_adxl367_set_act_threshold(struct adxl367_state * st,enum adxl367_activity_type act,unsigned int threshold)306cbab791cSCosmin Tanislav static int _adxl367_set_act_threshold(struct adxl367_state *st,
307cbab791cSCosmin Tanislav 				      enum adxl367_activity_type act,
308cbab791cSCosmin Tanislav 				      unsigned int threshold)
309cbab791cSCosmin Tanislav {
310cbab791cSCosmin Tanislav 	u8 reg = adxl367_threshold_h_reg_tbl[act];
311cbab791cSCosmin Tanislav 	int ret;
312cbab791cSCosmin Tanislav 
313cbab791cSCosmin Tanislav 	if (threshold > ADXL367_THRESH_MAX)
314cbab791cSCosmin Tanislav 		return -EINVAL;
315cbab791cSCosmin Tanislav 
316cbab791cSCosmin Tanislav 	st->act_threshold_buf[0] = FIELD_PREP(ADXL367_THRESH_H_MASK,
317cbab791cSCosmin Tanislav 					      FIELD_GET(ADXL367_THRESH_VAL_H_MASK,
318cbab791cSCosmin Tanislav 							threshold));
319cbab791cSCosmin Tanislav 	st->act_threshold_buf[1] = FIELD_PREP(ADXL367_THRESH_L_MASK,
320cbab791cSCosmin Tanislav 					      FIELD_GET(ADXL367_THRESH_VAL_L_MASK,
321cbab791cSCosmin Tanislav 							threshold));
322cbab791cSCosmin Tanislav 
323cbab791cSCosmin Tanislav 	ret = regmap_bulk_write(st->regmap, reg, st->act_threshold_buf,
324cbab791cSCosmin Tanislav 				sizeof(st->act_threshold_buf));
325cbab791cSCosmin Tanislav 	if (ret)
326cbab791cSCosmin Tanislav 		return ret;
327cbab791cSCosmin Tanislav 
328cbab791cSCosmin Tanislav 	if (act == ADXL367_ACTIVITY)
329cbab791cSCosmin Tanislav 		st->act_threshold = threshold;
330cbab791cSCosmin Tanislav 	else
331cbab791cSCosmin Tanislav 		st->inact_threshold = threshold;
332cbab791cSCosmin Tanislav 
333cbab791cSCosmin Tanislav 	return 0;
334cbab791cSCosmin Tanislav }
335cbab791cSCosmin Tanislav 
adxl367_set_act_threshold(struct adxl367_state * st,enum adxl367_activity_type act,unsigned int threshold)336cbab791cSCosmin Tanislav static int adxl367_set_act_threshold(struct adxl367_state *st,
337cbab791cSCosmin Tanislav 				     enum adxl367_activity_type act,
338cbab791cSCosmin Tanislav 				     unsigned int threshold)
339cbab791cSCosmin Tanislav {
340cbab791cSCosmin Tanislav 	int ret;
341cbab791cSCosmin Tanislav 
342cbab791cSCosmin Tanislav 	mutex_lock(&st->lock);
343cbab791cSCosmin Tanislav 
344cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, false);
345cbab791cSCosmin Tanislav 	if (ret)
346cbab791cSCosmin Tanislav 		goto out;
347cbab791cSCosmin Tanislav 
348cbab791cSCosmin Tanislav 	ret = _adxl367_set_act_threshold(st, act, threshold);
349cbab791cSCosmin Tanislav 	if (ret)
350cbab791cSCosmin Tanislav 		goto out;
351cbab791cSCosmin Tanislav 
352cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, true);
353cbab791cSCosmin Tanislav 
354cbab791cSCosmin Tanislav out:
355cbab791cSCosmin Tanislav 	mutex_unlock(&st->lock);
356cbab791cSCosmin Tanislav 
357cbab791cSCosmin Tanislav 	return ret;
358cbab791cSCosmin Tanislav }
359cbab791cSCosmin Tanislav 
adxl367_set_act_proc_mode(struct adxl367_state * st,enum adxl367_act_proc_mode mode)360cbab791cSCosmin Tanislav static int adxl367_set_act_proc_mode(struct adxl367_state *st,
361cbab791cSCosmin Tanislav 				     enum adxl367_act_proc_mode mode)
362cbab791cSCosmin Tanislav {
363cbab791cSCosmin Tanislav 	return regmap_update_bits(st->regmap, ADXL367_REG_ACT_INACT_CTL,
364cbab791cSCosmin Tanislav 				  ADXL367_ACT_LINKLOOP_MASK,
365cbab791cSCosmin Tanislav 				  FIELD_PREP(ADXL367_ACT_LINKLOOP_MASK,
366cbab791cSCosmin Tanislav 					     mode));
367cbab791cSCosmin Tanislav }
368cbab791cSCosmin Tanislav 
adxl367_set_act_interrupt_en(struct adxl367_state * st,enum adxl367_activity_type act,bool en)369cbab791cSCosmin Tanislav static int adxl367_set_act_interrupt_en(struct adxl367_state *st,
370cbab791cSCosmin Tanislav 					enum adxl367_activity_type act,
371cbab791cSCosmin Tanislav 					bool en)
372cbab791cSCosmin Tanislav {
373cbab791cSCosmin Tanislav 	unsigned int mask = adxl367_act_int_mask_tbl[act];
374cbab791cSCosmin Tanislav 
375cbab791cSCosmin Tanislav 	return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP,
376cbab791cSCosmin Tanislav 				  mask, en ? mask : 0);
377cbab791cSCosmin Tanislav }
378cbab791cSCosmin Tanislav 
adxl367_get_act_interrupt_en(struct adxl367_state * st,enum adxl367_activity_type act,bool * en)379cbab791cSCosmin Tanislav static int adxl367_get_act_interrupt_en(struct adxl367_state *st,
380cbab791cSCosmin Tanislav 					enum adxl367_activity_type act,
381cbab791cSCosmin Tanislav 					bool *en)
382cbab791cSCosmin Tanislav {
383cbab791cSCosmin Tanislav 	unsigned int mask = adxl367_act_int_mask_tbl[act];
384cbab791cSCosmin Tanislav 	unsigned int val;
385cbab791cSCosmin Tanislav 	int ret;
386cbab791cSCosmin Tanislav 
387cbab791cSCosmin Tanislav 	ret = regmap_read(st->regmap, ADXL367_REG_INT1_MAP, &val);
388cbab791cSCosmin Tanislav 	if (ret)
389cbab791cSCosmin Tanislav 		return ret;
390cbab791cSCosmin Tanislav 
391cbab791cSCosmin Tanislav 	*en = !!(val & mask);
392cbab791cSCosmin Tanislav 
393cbab791cSCosmin Tanislav 	return 0;
394cbab791cSCosmin Tanislav }
395cbab791cSCosmin Tanislav 
adxl367_set_act_en(struct adxl367_state * st,enum adxl367_activity_type act,enum adxl367_act_en_mode en)396cbab791cSCosmin Tanislav static int adxl367_set_act_en(struct adxl367_state *st,
397cbab791cSCosmin Tanislav 			      enum adxl367_activity_type act,
398cbab791cSCosmin Tanislav 			      enum adxl367_act_en_mode en)
399cbab791cSCosmin Tanislav {
400cbab791cSCosmin Tanislav 	unsigned int ctl_shift = adxl367_act_en_shift_tbl[act];
401cbab791cSCosmin Tanislav 
402cbab791cSCosmin Tanislav 	return regmap_update_bits(st->regmap, ADXL367_REG_ACT_INACT_CTL,
403cbab791cSCosmin Tanislav 				  ADXL367_ACT_EN_MASK << ctl_shift,
404cbab791cSCosmin Tanislav 				  en << ctl_shift);
405cbab791cSCosmin Tanislav }
406cbab791cSCosmin Tanislav 
adxl367_set_fifo_watermark_interrupt_en(struct adxl367_state * st,bool en)407cbab791cSCosmin Tanislav static int adxl367_set_fifo_watermark_interrupt_en(struct adxl367_state *st,
408cbab791cSCosmin Tanislav 						   bool en)
409cbab791cSCosmin Tanislav {
410cbab791cSCosmin Tanislav 	return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP,
411cbab791cSCosmin Tanislav 				  ADXL367_INT_FIFO_WATERMARK_MASK,
412cbab791cSCosmin Tanislav 				  en ? ADXL367_INT_FIFO_WATERMARK_MASK : 0);
413cbab791cSCosmin Tanislav }
414cbab791cSCosmin Tanislav 
adxl367_get_fifo_mode(struct adxl367_state * st,enum adxl367_fifo_mode * fifo_mode)415cbab791cSCosmin Tanislav static int adxl367_get_fifo_mode(struct adxl367_state *st,
416cbab791cSCosmin Tanislav 				 enum adxl367_fifo_mode *fifo_mode)
417cbab791cSCosmin Tanislav {
418cbab791cSCosmin Tanislav 	unsigned int val;
419cbab791cSCosmin Tanislav 	int ret;
420cbab791cSCosmin Tanislav 
421cbab791cSCosmin Tanislav 	ret = regmap_read(st->regmap, ADXL367_REG_FIFO_CTL, &val);
422cbab791cSCosmin Tanislav 	if (ret)
423cbab791cSCosmin Tanislav 		return ret;
424cbab791cSCosmin Tanislav 
425cbab791cSCosmin Tanislav 	*fifo_mode = FIELD_GET(ADXL367_FIFO_CTL_MODE_MASK, val);
426cbab791cSCosmin Tanislav 
427cbab791cSCosmin Tanislav 	return 0;
428cbab791cSCosmin Tanislav }
429cbab791cSCosmin Tanislav 
adxl367_set_fifo_mode(struct adxl367_state * st,enum adxl367_fifo_mode fifo_mode)430cbab791cSCosmin Tanislav static int adxl367_set_fifo_mode(struct adxl367_state *st,
431cbab791cSCosmin Tanislav 				 enum adxl367_fifo_mode fifo_mode)
432cbab791cSCosmin Tanislav {
433cbab791cSCosmin Tanislav 	return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL,
434cbab791cSCosmin Tanislav 				  ADXL367_FIFO_CTL_MODE_MASK,
435cbab791cSCosmin Tanislav 				  FIELD_PREP(ADXL367_FIFO_CTL_MODE_MASK,
436cbab791cSCosmin Tanislav 					     fifo_mode));
437cbab791cSCosmin Tanislav }
438cbab791cSCosmin Tanislav 
adxl367_set_fifo_format(struct adxl367_state * st,enum adxl367_fifo_format fifo_format)439cbab791cSCosmin Tanislav static int adxl367_set_fifo_format(struct adxl367_state *st,
440cbab791cSCosmin Tanislav 				   enum adxl367_fifo_format fifo_format)
441cbab791cSCosmin Tanislav {
442cbab791cSCosmin Tanislav 	return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL,
443cbab791cSCosmin Tanislav 				  ADXL367_FIFO_CTL_FORMAT_MASK,
444cbab791cSCosmin Tanislav 				  FIELD_PREP(ADXL367_FIFO_CTL_FORMAT_MASK,
445cbab791cSCosmin Tanislav 					     fifo_format));
446cbab791cSCosmin Tanislav }
447cbab791cSCosmin Tanislav 
adxl367_set_fifo_watermark(struct adxl367_state * st,unsigned int fifo_watermark)4480bd0bb1fSCosmin Tanislav static int adxl367_set_fifo_watermark(struct adxl367_state *st,
4490bd0bb1fSCosmin Tanislav 				      unsigned int fifo_watermark)
450cbab791cSCosmin Tanislav {
4510bd0bb1fSCosmin Tanislav 	unsigned int fifo_samples = fifo_watermark * st->fifo_set_size;
452cbab791cSCosmin Tanislav 	unsigned int fifo_samples_h, fifo_samples_l;
453cbab791cSCosmin Tanislav 	int ret;
454cbab791cSCosmin Tanislav 
455cbab791cSCosmin Tanislav 	if (fifo_samples > ADXL367_FIFO_MAX_WATERMARK)
456cbab791cSCosmin Tanislav 		fifo_samples = ADXL367_FIFO_MAX_WATERMARK;
457cbab791cSCosmin Tanislav 
4580bd0bb1fSCosmin Tanislav 	fifo_samples /= st->fifo_set_size;
459cbab791cSCosmin Tanislav 
460cbab791cSCosmin Tanislav 	fifo_samples_h = FIELD_PREP(ADXL367_SAMPLES_H_MASK,
461cbab791cSCosmin Tanislav 				    FIELD_GET(ADXL367_SAMPLES_VAL_H_MASK,
462cbab791cSCosmin Tanislav 					      fifo_samples));
463cbab791cSCosmin Tanislav 	fifo_samples_l = FIELD_PREP(ADXL367_SAMPLES_L_MASK,
464cbab791cSCosmin Tanislav 				    FIELD_GET(ADXL367_SAMPLES_VAL_L_MASK,
465cbab791cSCosmin Tanislav 					      fifo_samples));
466cbab791cSCosmin Tanislav 
467cbab791cSCosmin Tanislav 	ret = regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL,
468cbab791cSCosmin Tanislav 				 ADXL367_SAMPLES_H_MASK, fifo_samples_h);
469cbab791cSCosmin Tanislav 	if (ret)
470cbab791cSCosmin Tanislav 		return ret;
471cbab791cSCosmin Tanislav 
4720bd0bb1fSCosmin Tanislav 	ret = regmap_update_bits(st->regmap, ADXL367_REG_FIFO_SAMPLES,
473cbab791cSCosmin Tanislav 				 ADXL367_SAMPLES_L_MASK, fifo_samples_l);
474cbab791cSCosmin Tanislav 	if (ret)
475cbab791cSCosmin Tanislav 		return ret;
476cbab791cSCosmin Tanislav 
477cbab791cSCosmin Tanislav 	st->fifo_watermark = fifo_watermark;
478cbab791cSCosmin Tanislav 
479cbab791cSCosmin Tanislav 	return 0;
480cbab791cSCosmin Tanislav }
481cbab791cSCosmin Tanislav 
adxl367_set_range(struct iio_dev * indio_dev,enum adxl367_range range)482cbab791cSCosmin Tanislav static int adxl367_set_range(struct iio_dev *indio_dev,
483cbab791cSCosmin Tanislav 			     enum adxl367_range range)
484cbab791cSCosmin Tanislav {
485cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
486cbab791cSCosmin Tanislav 	int ret;
487cbab791cSCosmin Tanislav 
488cbab791cSCosmin Tanislav 	ret = iio_device_claim_direct_mode(indio_dev);
489cbab791cSCosmin Tanislav 	if (ret)
490cbab791cSCosmin Tanislav 		return ret;
491cbab791cSCosmin Tanislav 
492cbab791cSCosmin Tanislav 	mutex_lock(&st->lock);
493cbab791cSCosmin Tanislav 
494cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, false);
495cbab791cSCosmin Tanislav 	if (ret)
496cbab791cSCosmin Tanislav 		goto out;
497cbab791cSCosmin Tanislav 
498cbab791cSCosmin Tanislav 	ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL,
499cbab791cSCosmin Tanislav 				 ADXL367_FILTER_CTL_RANGE_MASK,
500cbab791cSCosmin Tanislav 				 FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK,
501cbab791cSCosmin Tanislav 					    range));
502cbab791cSCosmin Tanislav 	if (ret)
503cbab791cSCosmin Tanislav 		goto out;
504cbab791cSCosmin Tanislav 
505cbab791cSCosmin Tanislav 	adxl367_scale_act_thresholds(st, st->range, range);
506cbab791cSCosmin Tanislav 
507cbab791cSCosmin Tanislav 	/* Activity thresholds depend on range */
508cbab791cSCosmin Tanislav 	ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY,
509cbab791cSCosmin Tanislav 					 st->act_threshold);
510cbab791cSCosmin Tanislav 	if (ret)
511cbab791cSCosmin Tanislav 		goto out;
512cbab791cSCosmin Tanislav 
513cbab791cSCosmin Tanislav 	ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY,
514cbab791cSCosmin Tanislav 					 st->inact_threshold);
515cbab791cSCosmin Tanislav 	if (ret)
516cbab791cSCosmin Tanislav 		goto out;
517cbab791cSCosmin Tanislav 
518cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, true);
519cbab791cSCosmin Tanislav 	if (ret)
520cbab791cSCosmin Tanislav 		goto out;
521cbab791cSCosmin Tanislav 
522cbab791cSCosmin Tanislav 	st->range = range;
523cbab791cSCosmin Tanislav 
524cbab791cSCosmin Tanislav out:
525cbab791cSCosmin Tanislav 	mutex_unlock(&st->lock);
526cbab791cSCosmin Tanislav 
527cbab791cSCosmin Tanislav 	iio_device_release_direct_mode(indio_dev);
528cbab791cSCosmin Tanislav 
529cbab791cSCosmin Tanislav 	return ret;
530cbab791cSCosmin Tanislav }
531cbab791cSCosmin Tanislav 
adxl367_time_ms_to_samples(struct adxl367_state * st,unsigned int ms)532cbab791cSCosmin Tanislav static int adxl367_time_ms_to_samples(struct adxl367_state *st, unsigned int ms)
533cbab791cSCosmin Tanislav {
534cbab791cSCosmin Tanislav 	int freq_hz = adxl367_samp_freq_tbl[st->odr][0];
535cbab791cSCosmin Tanislav 	int freq_microhz = adxl367_samp_freq_tbl[st->odr][1];
536cbab791cSCosmin Tanislav 	/* Scale to decihertz to prevent precision loss in 12.5Hz case. */
537cbab791cSCosmin Tanislav 	int freq_dhz = freq_hz * 10 + freq_microhz / 100000;
538cbab791cSCosmin Tanislav 
539cbab791cSCosmin Tanislav 	return DIV_ROUND_CLOSEST(ms * freq_dhz, 10000);
540cbab791cSCosmin Tanislav }
541cbab791cSCosmin Tanislav 
_adxl367_set_act_time_ms(struct adxl367_state * st,unsigned int ms)542cbab791cSCosmin Tanislav static int _adxl367_set_act_time_ms(struct adxl367_state *st, unsigned int ms)
543cbab791cSCosmin Tanislav {
544cbab791cSCosmin Tanislav 	unsigned int val = adxl367_time_ms_to_samples(st, ms);
545cbab791cSCosmin Tanislav 	int ret;
546cbab791cSCosmin Tanislav 
547cbab791cSCosmin Tanislav 	if (val > ADXL367_TIME_ACT_MAX)
548cbab791cSCosmin Tanislav 		val = ADXL367_TIME_ACT_MAX;
549cbab791cSCosmin Tanislav 
550cbab791cSCosmin Tanislav 	ret = regmap_write(st->regmap, ADXL367_REG_TIME_ACT, val);
551cbab791cSCosmin Tanislav 	if (ret)
552cbab791cSCosmin Tanislav 		return ret;
553cbab791cSCosmin Tanislav 
554cbab791cSCosmin Tanislav 	st->act_time_ms = ms;
555cbab791cSCosmin Tanislav 
556cbab791cSCosmin Tanislav 	return 0;
557cbab791cSCosmin Tanislav }
558cbab791cSCosmin Tanislav 
_adxl367_set_inact_time_ms(struct adxl367_state * st,unsigned int ms)559cbab791cSCosmin Tanislav static int _adxl367_set_inact_time_ms(struct adxl367_state *st, unsigned int ms)
560cbab791cSCosmin Tanislav {
561cbab791cSCosmin Tanislav 	unsigned int val = adxl367_time_ms_to_samples(st, ms);
562cbab791cSCosmin Tanislav 	int ret;
563cbab791cSCosmin Tanislav 
564cbab791cSCosmin Tanislav 	if (val > ADXL367_TIME_INACT_MAX)
565cbab791cSCosmin Tanislav 		val = ADXL367_TIME_INACT_MAX;
566cbab791cSCosmin Tanislav 
567cbab791cSCosmin Tanislav 	st->inact_time_buf[0] = FIELD_PREP(ADXL367_TIME_INACT_H_MASK,
568cbab791cSCosmin Tanislav 					   FIELD_GET(ADXL367_TIME_INACT_VAL_H_MASK,
569cbab791cSCosmin Tanislav 						     val));
570cbab791cSCosmin Tanislav 	st->inact_time_buf[1] = FIELD_PREP(ADXL367_TIME_INACT_L_MASK,
571cbab791cSCosmin Tanislav 					   FIELD_GET(ADXL367_TIME_INACT_VAL_L_MASK,
572cbab791cSCosmin Tanislav 						     val));
573cbab791cSCosmin Tanislav 
574cbab791cSCosmin Tanislav 	ret = regmap_bulk_write(st->regmap, ADXL367_REG_TIME_INACT_H,
575cbab791cSCosmin Tanislav 				st->inact_time_buf, sizeof(st->inact_time_buf));
576cbab791cSCosmin Tanislav 	if (ret)
577cbab791cSCosmin Tanislav 		return ret;
578cbab791cSCosmin Tanislav 
579cbab791cSCosmin Tanislav 	st->inact_time_ms = ms;
580cbab791cSCosmin Tanislav 
581cbab791cSCosmin Tanislav 	return 0;
582cbab791cSCosmin Tanislav }
583cbab791cSCosmin Tanislav 
adxl367_set_act_time_ms(struct adxl367_state * st,enum adxl367_activity_type act,unsigned int ms)584cbab791cSCosmin Tanislav static int adxl367_set_act_time_ms(struct adxl367_state *st,
585cbab791cSCosmin Tanislav 				   enum adxl367_activity_type act,
586cbab791cSCosmin Tanislav 				   unsigned int ms)
587cbab791cSCosmin Tanislav {
588cbab791cSCosmin Tanislav 	int ret;
589cbab791cSCosmin Tanislav 
590cbab791cSCosmin Tanislav 	mutex_lock(&st->lock);
591cbab791cSCosmin Tanislav 
592cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, false);
593cbab791cSCosmin Tanislav 	if (ret)
594cbab791cSCosmin Tanislav 		goto out;
595cbab791cSCosmin Tanislav 
596cbab791cSCosmin Tanislav 	if (act == ADXL367_ACTIVITY)
597cbab791cSCosmin Tanislav 		ret = _adxl367_set_act_time_ms(st, ms);
598cbab791cSCosmin Tanislav 	else
599cbab791cSCosmin Tanislav 		ret = _adxl367_set_inact_time_ms(st, ms);
600cbab791cSCosmin Tanislav 
601cbab791cSCosmin Tanislav 	if (ret)
602cbab791cSCosmin Tanislav 		goto out;
603cbab791cSCosmin Tanislav 
604cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, true);
605cbab791cSCosmin Tanislav 
606cbab791cSCosmin Tanislav out:
607cbab791cSCosmin Tanislav 	mutex_unlock(&st->lock);
608cbab791cSCosmin Tanislav 
609cbab791cSCosmin Tanislav 	return ret;
610cbab791cSCosmin Tanislav }
611cbab791cSCosmin Tanislav 
_adxl367_set_odr(struct adxl367_state * st,enum adxl367_odr odr)612cbab791cSCosmin Tanislav static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr)
613cbab791cSCosmin Tanislav {
614cbab791cSCosmin Tanislav 	int ret;
615cbab791cSCosmin Tanislav 
616cbab791cSCosmin Tanislav 	ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL,
617cbab791cSCosmin Tanislav 				 ADXL367_FILTER_CTL_ODR_MASK,
618cbab791cSCosmin Tanislav 				 FIELD_PREP(ADXL367_FILTER_CTL_ODR_MASK,
619cbab791cSCosmin Tanislav 					    odr));
620cbab791cSCosmin Tanislav 	if (ret)
621cbab791cSCosmin Tanislav 		return ret;
622cbab791cSCosmin Tanislav 
623cbab791cSCosmin Tanislav 	/* Activity timers depend on ODR */
624cbab791cSCosmin Tanislav 	ret = _adxl367_set_act_time_ms(st, st->act_time_ms);
625cbab791cSCosmin Tanislav 	if (ret)
626cbab791cSCosmin Tanislav 		return ret;
627cbab791cSCosmin Tanislav 
628cbab791cSCosmin Tanislav 	ret = _adxl367_set_inact_time_ms(st, st->inact_time_ms);
629cbab791cSCosmin Tanislav 	if (ret)
630cbab791cSCosmin Tanislav 		return ret;
631cbab791cSCosmin Tanislav 
632cbab791cSCosmin Tanislav 	st->odr = odr;
633cbab791cSCosmin Tanislav 
634cbab791cSCosmin Tanislav 	return 0;
635cbab791cSCosmin Tanislav }
636cbab791cSCosmin Tanislav 
adxl367_set_odr(struct iio_dev * indio_dev,enum adxl367_odr odr)637cbab791cSCosmin Tanislav static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr)
638cbab791cSCosmin Tanislav {
639cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
640cbab791cSCosmin Tanislav 	int ret;
641cbab791cSCosmin Tanislav 
642cbab791cSCosmin Tanislav 	ret = iio_device_claim_direct_mode(indio_dev);
643cbab791cSCosmin Tanislav 	if (ret)
644cbab791cSCosmin Tanislav 		return ret;
645cbab791cSCosmin Tanislav 
646cbab791cSCosmin Tanislav 	mutex_lock(&st->lock);
647cbab791cSCosmin Tanislav 
648cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, false);
649cbab791cSCosmin Tanislav 	if (ret)
650cbab791cSCosmin Tanislav 		goto out;
651cbab791cSCosmin Tanislav 
652cbab791cSCosmin Tanislav 	ret = _adxl367_set_odr(st, odr);
653cbab791cSCosmin Tanislav 	if (ret)
654cbab791cSCosmin Tanislav 		goto out;
655cbab791cSCosmin Tanislav 
656cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, true);
657cbab791cSCosmin Tanislav 
658cbab791cSCosmin Tanislav out:
659cbab791cSCosmin Tanislav 	mutex_unlock(&st->lock);
660cbab791cSCosmin Tanislav 
661cbab791cSCosmin Tanislav 	iio_device_release_direct_mode(indio_dev);
662cbab791cSCosmin Tanislav 
663cbab791cSCosmin Tanislav 	return ret;
664cbab791cSCosmin Tanislav }
665cbab791cSCosmin Tanislav 
adxl367_set_temp_adc_en(struct adxl367_state * st,unsigned int reg,bool en)666cbab791cSCosmin Tanislav static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg,
667cbab791cSCosmin Tanislav 				   bool en)
668cbab791cSCosmin Tanislav {
669cbab791cSCosmin Tanislav 	return regmap_update_bits(st->regmap, reg, ADXL367_ADC_EN_MASK,
670cbab791cSCosmin Tanislav 				  en ? ADXL367_ADC_EN_MASK : 0);
671cbab791cSCosmin Tanislav }
672cbab791cSCosmin Tanislav 
adxl367_set_temp_adc_reg_en(struct adxl367_state * st,unsigned int reg,bool en)673cbab791cSCosmin Tanislav static int adxl367_set_temp_adc_reg_en(struct adxl367_state *st,
674cbab791cSCosmin Tanislav 				       unsigned int reg, bool en)
675cbab791cSCosmin Tanislav {
676cbab791cSCosmin Tanislav 	int ret;
677cbab791cSCosmin Tanislav 
678cbab791cSCosmin Tanislav 	switch (reg) {
679cbab791cSCosmin Tanislav 	case ADXL367_REG_TEMP_DATA_H:
680cbab791cSCosmin Tanislav 		ret = adxl367_set_temp_adc_en(st, ADXL367_REG_TEMP_CTL, en);
681cbab791cSCosmin Tanislav 		break;
682cbab791cSCosmin Tanislav 	case ADXL367_REG_EX_ADC_DATA_H:
683cbab791cSCosmin Tanislav 		ret = adxl367_set_temp_adc_en(st, ADXL367_REG_ADC_CTL, en);
684cbab791cSCosmin Tanislav 		break;
685cbab791cSCosmin Tanislav 	default:
686cbab791cSCosmin Tanislav 		return 0;
687cbab791cSCosmin Tanislav 	}
688cbab791cSCosmin Tanislav 
689cbab791cSCosmin Tanislav 	if (ret)
690cbab791cSCosmin Tanislav 		return ret;
691cbab791cSCosmin Tanislav 
692cbab791cSCosmin Tanislav 	if (en)
693cbab791cSCosmin Tanislav 		msleep(100);
694cbab791cSCosmin Tanislav 
695cbab791cSCosmin Tanislav 	return 0;
696cbab791cSCosmin Tanislav }
697cbab791cSCosmin Tanislav 
adxl367_set_temp_adc_mask_en(struct adxl367_state * st,const unsigned long * active_scan_mask,bool en)698cbab791cSCosmin Tanislav static int adxl367_set_temp_adc_mask_en(struct adxl367_state *st,
699cbab791cSCosmin Tanislav 					const unsigned long *active_scan_mask,
700cbab791cSCosmin Tanislav 					bool en)
701cbab791cSCosmin Tanislav {
702cbab791cSCosmin Tanislav 	if (*active_scan_mask & ADXL367_TEMP_CHANNEL_MASK)
703cbab791cSCosmin Tanislav 		return adxl367_set_temp_adc_en(st, ADXL367_REG_TEMP_CTL, en);
704cbab791cSCosmin Tanislav 	else if (*active_scan_mask & ADXL367_EX_ADC_CHANNEL_MASK)
705cbab791cSCosmin Tanislav 		return adxl367_set_temp_adc_en(st, ADXL367_REG_ADC_CTL, en);
706cbab791cSCosmin Tanislav 
707cbab791cSCosmin Tanislav 	return 0;
708cbab791cSCosmin Tanislav }
709cbab791cSCosmin Tanislav 
adxl367_find_odr(struct adxl367_state * st,int val,int val2,enum adxl367_odr * odr)710cbab791cSCosmin Tanislav static int adxl367_find_odr(struct adxl367_state *st, int val, int val2,
711cbab791cSCosmin Tanislav 			    enum adxl367_odr *odr)
712cbab791cSCosmin Tanislav {
713cbab791cSCosmin Tanislav 	size_t size = ARRAY_SIZE(adxl367_samp_freq_tbl);
714cbab791cSCosmin Tanislav 	int i;
715cbab791cSCosmin Tanislav 
716cbab791cSCosmin Tanislav 	for (i = 0; i < size; i++)
717cbab791cSCosmin Tanislav 		if (val == adxl367_samp_freq_tbl[i][0] &&
718cbab791cSCosmin Tanislav 		    val2 == adxl367_samp_freq_tbl[i][1])
719cbab791cSCosmin Tanislav 			break;
720cbab791cSCosmin Tanislav 
721cbab791cSCosmin Tanislav 	if (i == size)
722cbab791cSCosmin Tanislav 		return -EINVAL;
723cbab791cSCosmin Tanislav 
724cbab791cSCosmin Tanislav 	*odr = i;
725cbab791cSCosmin Tanislav 
726cbab791cSCosmin Tanislav 	return 0;
727cbab791cSCosmin Tanislav }
728cbab791cSCosmin Tanislav 
adxl367_find_range(struct adxl367_state * st,int val,int val2,enum adxl367_range * range)729cbab791cSCosmin Tanislav static int adxl367_find_range(struct adxl367_state *st, int val, int val2,
730cbab791cSCosmin Tanislav 			      enum adxl367_range *range)
731cbab791cSCosmin Tanislav {
732cbab791cSCosmin Tanislav 	size_t size = ARRAY_SIZE(adxl367_range_scale_tbl);
733cbab791cSCosmin Tanislav 	int i;
734cbab791cSCosmin Tanislav 
735cbab791cSCosmin Tanislav 	for (i = 0; i < size; i++)
736cbab791cSCosmin Tanislav 		if (val == adxl367_range_scale_tbl[i][0] &&
737cbab791cSCosmin Tanislav 		    val2 == adxl367_range_scale_tbl[i][1])
738cbab791cSCosmin Tanislav 			break;
739cbab791cSCosmin Tanislav 
740cbab791cSCosmin Tanislav 	if (i == size)
741cbab791cSCosmin Tanislav 		return -EINVAL;
742cbab791cSCosmin Tanislav 
743cbab791cSCosmin Tanislav 	*range = i;
744cbab791cSCosmin Tanislav 
745cbab791cSCosmin Tanislav 	return 0;
746cbab791cSCosmin Tanislav }
747cbab791cSCosmin Tanislav 
adxl367_read_sample(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val)748cbab791cSCosmin Tanislav static int adxl367_read_sample(struct iio_dev *indio_dev,
749cbab791cSCosmin Tanislav 			       struct iio_chan_spec const *chan,
750cbab791cSCosmin Tanislav 			       int *val)
751cbab791cSCosmin Tanislav {
752cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
753cbab791cSCosmin Tanislav 	u16 sample;
754cbab791cSCosmin Tanislav 	int ret;
755cbab791cSCosmin Tanislav 
756cbab791cSCosmin Tanislav 	ret = iio_device_claim_direct_mode(indio_dev);
757cbab791cSCosmin Tanislav 	if (ret)
758cbab791cSCosmin Tanislav 		return ret;
759cbab791cSCosmin Tanislav 
760cbab791cSCosmin Tanislav 	mutex_lock(&st->lock);
761cbab791cSCosmin Tanislav 
762cbab791cSCosmin Tanislav 	ret = adxl367_set_temp_adc_reg_en(st, chan->address, true);
763cbab791cSCosmin Tanislav 	if (ret)
764cbab791cSCosmin Tanislav 		goto out;
765cbab791cSCosmin Tanislav 
766cbab791cSCosmin Tanislav 	ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf,
767cbab791cSCosmin Tanislav 			       sizeof(st->sample_buf));
768cbab791cSCosmin Tanislav 	if (ret)
769cbab791cSCosmin Tanislav 		goto out;
770cbab791cSCosmin Tanislav 
771cbab791cSCosmin Tanislav 	sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf));
772cbab791cSCosmin Tanislav 	*val = sign_extend32(sample, chan->scan_type.realbits - 1);
773cbab791cSCosmin Tanislav 
774cbab791cSCosmin Tanislav 	ret = adxl367_set_temp_adc_reg_en(st, chan->address, false);
775cbab791cSCosmin Tanislav 
776cbab791cSCosmin Tanislav out:
777cbab791cSCosmin Tanislav 	mutex_unlock(&st->lock);
778cbab791cSCosmin Tanislav 
779cbab791cSCosmin Tanislav 	iio_device_release_direct_mode(indio_dev);
780cbab791cSCosmin Tanislav 
781cbab791cSCosmin Tanislav 	return ret ?: IIO_VAL_INT;
782cbab791cSCosmin Tanislav }
783cbab791cSCosmin Tanislav 
adxl367_get_status(struct adxl367_state * st,u8 * status,u16 * fifo_entries)784cbab791cSCosmin Tanislav static int adxl367_get_status(struct adxl367_state *st, u8 *status,
785cbab791cSCosmin Tanislav 			      u16 *fifo_entries)
786cbab791cSCosmin Tanislav {
787cbab791cSCosmin Tanislav 	int ret;
788cbab791cSCosmin Tanislav 
789cbab791cSCosmin Tanislav 	/* Read STATUS, FIFO_ENT_L and FIFO_ENT_H */
790cbab791cSCosmin Tanislav 	ret = regmap_bulk_read(st->regmap, ADXL367_REG_STATUS,
791cbab791cSCosmin Tanislav 			       st->status_buf, sizeof(st->status_buf));
792cbab791cSCosmin Tanislav 	if (ret)
793cbab791cSCosmin Tanislav 		return ret;
794cbab791cSCosmin Tanislav 
795cbab791cSCosmin Tanislav 	st->status_buf[2] &= ADXL367_FIFO_ENT_H_MASK;
796cbab791cSCosmin Tanislav 
797cbab791cSCosmin Tanislav 	*status = st->status_buf[0];
798cbab791cSCosmin Tanislav 	*fifo_entries = get_unaligned_le16(&st->status_buf[1]);
799cbab791cSCosmin Tanislav 
800cbab791cSCosmin Tanislav 	return 0;
801cbab791cSCosmin Tanislav }
802cbab791cSCosmin Tanislav 
adxl367_push_event(struct iio_dev * indio_dev,u8 status)803cbab791cSCosmin Tanislav static bool adxl367_push_event(struct iio_dev *indio_dev, u8 status)
804cbab791cSCosmin Tanislav {
805cbab791cSCosmin Tanislav 	unsigned int ev_dir;
806cbab791cSCosmin Tanislav 
807cbab791cSCosmin Tanislav 	if (FIELD_GET(ADXL367_STATUS_ACT_MASK, status))
808cbab791cSCosmin Tanislav 		ev_dir = IIO_EV_DIR_RISING;
809cbab791cSCosmin Tanislav 	else if (FIELD_GET(ADXL367_STATUS_INACT_MASK, status))
810cbab791cSCosmin Tanislav 		ev_dir = IIO_EV_DIR_FALLING;
811cbab791cSCosmin Tanislav 	else
812cbab791cSCosmin Tanislav 		return false;
813cbab791cSCosmin Tanislav 
814cbab791cSCosmin Tanislav 	iio_push_event(indio_dev,
815cbab791cSCosmin Tanislav 		       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z,
816cbab791cSCosmin Tanislav 					  IIO_EV_TYPE_THRESH, ev_dir),
817cbab791cSCosmin Tanislav 		       iio_get_time_ns(indio_dev));
818cbab791cSCosmin Tanislav 
819cbab791cSCosmin Tanislav 	return true;
820cbab791cSCosmin Tanislav }
821cbab791cSCosmin Tanislav 
adxl367_push_fifo_data(struct iio_dev * indio_dev,u8 status,u16 fifo_entries)822cbab791cSCosmin Tanislav static bool adxl367_push_fifo_data(struct iio_dev *indio_dev, u8 status,
823cbab791cSCosmin Tanislav 				   u16 fifo_entries)
824cbab791cSCosmin Tanislav {
825cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
826cbab791cSCosmin Tanislav 	int ret;
827cbab791cSCosmin Tanislav 	int i;
828cbab791cSCosmin Tanislav 
829cbab791cSCosmin Tanislav 	if (!FIELD_GET(ADXL367_STATUS_FIFO_FULL_MASK, status))
830cbab791cSCosmin Tanislav 		return false;
831cbab791cSCosmin Tanislav 
832cbab791cSCosmin Tanislav 	fifo_entries -= fifo_entries % st->fifo_set_size;
833cbab791cSCosmin Tanislav 
834cbab791cSCosmin Tanislav 	ret = st->ops->read_fifo(st->context, st->fifo_buf, fifo_entries);
835cbab791cSCosmin Tanislav 	if (ret) {
836cbab791cSCosmin Tanislav 		dev_err(st->dev, "Failed to read FIFO: %d\n", ret);
837cbab791cSCosmin Tanislav 		return true;
838cbab791cSCosmin Tanislav 	}
839cbab791cSCosmin Tanislav 
840cbab791cSCosmin Tanislav 	for (i = 0; i < fifo_entries; i += st->fifo_set_size)
841cbab791cSCosmin Tanislav 		iio_push_to_buffers(indio_dev, &st->fifo_buf[i]);
842cbab791cSCosmin Tanislav 
843cbab791cSCosmin Tanislav 	return true;
844cbab791cSCosmin Tanislav }
845cbab791cSCosmin Tanislav 
adxl367_irq_handler(int irq,void * private)846cbab791cSCosmin Tanislav static irqreturn_t adxl367_irq_handler(int irq, void *private)
847cbab791cSCosmin Tanislav {
848cbab791cSCosmin Tanislav 	struct iio_dev *indio_dev = private;
849cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
850cbab791cSCosmin Tanislav 	u16 fifo_entries;
851cbab791cSCosmin Tanislav 	bool handled;
852cbab791cSCosmin Tanislav 	u8 status;
853cbab791cSCosmin Tanislav 	int ret;
854cbab791cSCosmin Tanislav 
855cbab791cSCosmin Tanislav 	ret = adxl367_get_status(st, &status, &fifo_entries);
856cbab791cSCosmin Tanislav 	if (ret)
857cbab791cSCosmin Tanislav 		return IRQ_NONE;
858cbab791cSCosmin Tanislav 
859185897d0SNathan Chancellor 	handled = adxl367_push_event(indio_dev, status);
860cbab791cSCosmin Tanislav 	handled |= adxl367_push_fifo_data(indio_dev, status, fifo_entries);
861cbab791cSCosmin Tanislav 
862cbab791cSCosmin Tanislav 	return handled ? IRQ_HANDLED : IRQ_NONE;
863cbab791cSCosmin Tanislav }
864cbab791cSCosmin Tanislav 
adxl367_reg_access(struct iio_dev * indio_dev,unsigned int reg,unsigned int writeval,unsigned int * readval)865cbab791cSCosmin Tanislav static int adxl367_reg_access(struct iio_dev *indio_dev,
866cbab791cSCosmin Tanislav 			      unsigned int reg,
867cbab791cSCosmin Tanislav 			      unsigned int writeval,
868cbab791cSCosmin Tanislav 			      unsigned int *readval)
869cbab791cSCosmin Tanislav {
870cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
871cbab791cSCosmin Tanislav 
872cbab791cSCosmin Tanislav 	if (readval)
873cbab791cSCosmin Tanislav 		return regmap_read(st->regmap, reg, readval);
874cbab791cSCosmin Tanislav 	else
875cbab791cSCosmin Tanislav 		return regmap_write(st->regmap, reg, writeval);
876cbab791cSCosmin Tanislav }
877cbab791cSCosmin Tanislav 
adxl367_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long info)878cbab791cSCosmin Tanislav static int adxl367_read_raw(struct iio_dev *indio_dev,
879cbab791cSCosmin Tanislav 			    struct iio_chan_spec const *chan,
880cbab791cSCosmin Tanislav 			    int *val, int *val2, long info)
881cbab791cSCosmin Tanislav {
882cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
883cbab791cSCosmin Tanislav 
884cbab791cSCosmin Tanislav 	switch (info) {
885cbab791cSCosmin Tanislav 	case IIO_CHAN_INFO_RAW:
886cbab791cSCosmin Tanislav 		return adxl367_read_sample(indio_dev, chan, val);
887cbab791cSCosmin Tanislav 	case IIO_CHAN_INFO_SCALE:
888cbab791cSCosmin Tanislav 		switch (chan->type) {
889cbab791cSCosmin Tanislav 		case IIO_ACCEL:
890cbab791cSCosmin Tanislav 			mutex_lock(&st->lock);
891cbab791cSCosmin Tanislav 			*val = adxl367_range_scale_tbl[st->range][0];
892cbab791cSCosmin Tanislav 			*val2 = adxl367_range_scale_tbl[st->range][1];
893cbab791cSCosmin Tanislav 			mutex_unlock(&st->lock);
894cbab791cSCosmin Tanislav 			return IIO_VAL_INT_PLUS_NANO;
895cbab791cSCosmin Tanislav 		case IIO_TEMP:
896cbab791cSCosmin Tanislav 			*val = 1000;
897cbab791cSCosmin Tanislav 			*val2 = ADXL367_TEMP_PER_C;
898cbab791cSCosmin Tanislav 			return IIO_VAL_FRACTIONAL;
899cbab791cSCosmin Tanislav 		case IIO_VOLTAGE:
900cbab791cSCosmin Tanislav 			*val = ADXL367_VOLTAGE_MAX_MV;
901cbab791cSCosmin Tanislav 			*val2 = ADXL367_VOLTAGE_MAX_RAW;
902cbab791cSCosmin Tanislav 			return IIO_VAL_FRACTIONAL;
903cbab791cSCosmin Tanislav 		default:
904cbab791cSCosmin Tanislav 			return -EINVAL;
905cbab791cSCosmin Tanislav 		}
906cbab791cSCosmin Tanislav 	case IIO_CHAN_INFO_OFFSET:
907cbab791cSCosmin Tanislav 		switch (chan->type) {
908cbab791cSCosmin Tanislav 		case IIO_TEMP:
909cbab791cSCosmin Tanislav 			*val = 25 * ADXL367_TEMP_PER_C - ADXL367_TEMP_25C;
910cbab791cSCosmin Tanislav 			return IIO_VAL_INT;
911cbab791cSCosmin Tanislav 		case IIO_VOLTAGE:
912cbab791cSCosmin Tanislav 			*val = ADXL367_VOLTAGE_OFFSET;
913cbab791cSCosmin Tanislav 			return IIO_VAL_INT;
914cbab791cSCosmin Tanislav 		default:
915cbab791cSCosmin Tanislav 			return -EINVAL;
916cbab791cSCosmin Tanislav 		}
917cbab791cSCosmin Tanislav 	case IIO_CHAN_INFO_SAMP_FREQ:
918cbab791cSCosmin Tanislav 		mutex_lock(&st->lock);
919cbab791cSCosmin Tanislav 		*val = adxl367_samp_freq_tbl[st->odr][0];
920cbab791cSCosmin Tanislav 		*val2 = adxl367_samp_freq_tbl[st->odr][1];
921cbab791cSCosmin Tanislav 		mutex_unlock(&st->lock);
922cbab791cSCosmin Tanislav 		return IIO_VAL_INT_PLUS_MICRO;
923cbab791cSCosmin Tanislav 	default:
924cbab791cSCosmin Tanislav 		return -EINVAL;
925cbab791cSCosmin Tanislav 	}
926cbab791cSCosmin Tanislav }
927cbab791cSCosmin Tanislav 
adxl367_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long info)928cbab791cSCosmin Tanislav static int adxl367_write_raw(struct iio_dev *indio_dev,
929cbab791cSCosmin Tanislav 			     struct iio_chan_spec const *chan,
930cbab791cSCosmin Tanislav 			     int val, int val2, long info)
931cbab791cSCosmin Tanislav {
932cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
933cbab791cSCosmin Tanislav 	int ret;
934cbab791cSCosmin Tanislav 
935cbab791cSCosmin Tanislav 	switch (info) {
936cbab791cSCosmin Tanislav 	case IIO_CHAN_INFO_SAMP_FREQ: {
937cbab791cSCosmin Tanislav 		enum adxl367_odr odr;
938cbab791cSCosmin Tanislav 
939cbab791cSCosmin Tanislav 		ret = adxl367_find_odr(st, val, val2, &odr);
940cbab791cSCosmin Tanislav 		if (ret)
941cbab791cSCosmin Tanislav 			return ret;
942cbab791cSCosmin Tanislav 
943cbab791cSCosmin Tanislav 		return adxl367_set_odr(indio_dev, odr);
944cbab791cSCosmin Tanislav 	}
945cbab791cSCosmin Tanislav 	case IIO_CHAN_INFO_SCALE: {
946cbab791cSCosmin Tanislav 		enum adxl367_range range;
947cbab791cSCosmin Tanislav 
948cbab791cSCosmin Tanislav 		ret = adxl367_find_range(st, val, val2, &range);
949cbab791cSCosmin Tanislav 		if (ret)
950cbab791cSCosmin Tanislav 			return ret;
951cbab791cSCosmin Tanislav 
952cbab791cSCosmin Tanislav 		return adxl367_set_range(indio_dev, range);
953cbab791cSCosmin Tanislav 	}
954cbab791cSCosmin Tanislav 	default:
955cbab791cSCosmin Tanislav 		return -EINVAL;
956cbab791cSCosmin Tanislav 	}
957cbab791cSCosmin Tanislav }
958cbab791cSCosmin Tanislav 
adxl367_write_raw_get_fmt(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,long info)959cbab791cSCosmin Tanislav static int adxl367_write_raw_get_fmt(struct iio_dev *indio_dev,
960cbab791cSCosmin Tanislav 				     struct iio_chan_spec const *chan,
961cbab791cSCosmin Tanislav 				     long info)
962cbab791cSCosmin Tanislav {
963cbab791cSCosmin Tanislav 	switch (info) {
964cbab791cSCosmin Tanislav 	case IIO_CHAN_INFO_SCALE:
965cbab791cSCosmin Tanislav 		if (chan->type != IIO_ACCEL)
966cbab791cSCosmin Tanislav 			return -EINVAL;
967cbab791cSCosmin Tanislav 
968cbab791cSCosmin Tanislav 		return IIO_VAL_INT_PLUS_NANO;
969cbab791cSCosmin Tanislav 	default:
970cbab791cSCosmin Tanislav 		return IIO_VAL_INT_PLUS_MICRO;
971cbab791cSCosmin Tanislav 	}
972cbab791cSCosmin Tanislav }
973cbab791cSCosmin Tanislav 
adxl367_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long info)974cbab791cSCosmin Tanislav static int adxl367_read_avail(struct iio_dev *indio_dev,
975cbab791cSCosmin Tanislav 			      struct iio_chan_spec const *chan,
976cbab791cSCosmin Tanislav 			      const int **vals, int *type, int *length,
977cbab791cSCosmin Tanislav 			      long info)
978cbab791cSCosmin Tanislav {
979cbab791cSCosmin Tanislav 	switch (info) {
980cbab791cSCosmin Tanislav 	case IIO_CHAN_INFO_SCALE:
981cbab791cSCosmin Tanislav 		if (chan->type != IIO_ACCEL)
982cbab791cSCosmin Tanislav 			return -EINVAL;
983cbab791cSCosmin Tanislav 
984cbab791cSCosmin Tanislav 		*vals = (int *)adxl367_range_scale_tbl;
985cbab791cSCosmin Tanislav 		*type = IIO_VAL_INT_PLUS_NANO;
986cbab791cSCosmin Tanislav 		*length = ARRAY_SIZE(adxl367_range_scale_tbl) * 2;
987cbab791cSCosmin Tanislav 		return IIO_AVAIL_LIST;
988cbab791cSCosmin Tanislav 	case IIO_CHAN_INFO_SAMP_FREQ:
989cbab791cSCosmin Tanislav 		*vals = (int *)adxl367_samp_freq_tbl;
990cbab791cSCosmin Tanislav 		*type = IIO_VAL_INT_PLUS_MICRO;
991cbab791cSCosmin Tanislav 		*length = ARRAY_SIZE(adxl367_samp_freq_tbl) * 2;
992cbab791cSCosmin Tanislav 		return IIO_AVAIL_LIST;
993cbab791cSCosmin Tanislav 	default:
994cbab791cSCosmin Tanislav 		return -EINVAL;
995cbab791cSCosmin Tanislav 	}
996cbab791cSCosmin Tanislav }
997cbab791cSCosmin Tanislav 
adxl367_read_event_value(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)998cbab791cSCosmin Tanislav static int adxl367_read_event_value(struct iio_dev *indio_dev,
999cbab791cSCosmin Tanislav 				    const struct iio_chan_spec *chan,
1000cbab791cSCosmin Tanislav 				    enum iio_event_type type,
1001cbab791cSCosmin Tanislav 				    enum iio_event_direction dir,
1002cbab791cSCosmin Tanislav 				    enum iio_event_info info,
1003cbab791cSCosmin Tanislav 				    int *val, int *val2)
1004cbab791cSCosmin Tanislav {
1005cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
1006cbab791cSCosmin Tanislav 
1007cbab791cSCosmin Tanislav 	switch (info) {
1008cbab791cSCosmin Tanislav 	case IIO_EV_INFO_VALUE: {
1009cbab791cSCosmin Tanislav 		switch (dir) {
1010cbab791cSCosmin Tanislav 		case IIO_EV_DIR_RISING:
1011cbab791cSCosmin Tanislav 			mutex_lock(&st->lock);
1012cbab791cSCosmin Tanislav 			*val = st->act_threshold;
1013cbab791cSCosmin Tanislav 			mutex_unlock(&st->lock);
1014cbab791cSCosmin Tanislav 			return IIO_VAL_INT;
1015cbab791cSCosmin Tanislav 		case IIO_EV_DIR_FALLING:
1016cbab791cSCosmin Tanislav 			mutex_lock(&st->lock);
1017cbab791cSCosmin Tanislav 			*val = st->inact_threshold;
1018cbab791cSCosmin Tanislav 			mutex_unlock(&st->lock);
1019cbab791cSCosmin Tanislav 			return IIO_VAL_INT;
1020cbab791cSCosmin Tanislav 		default:
1021cbab791cSCosmin Tanislav 			return -EINVAL;
1022cbab791cSCosmin Tanislav 		}
1023cbab791cSCosmin Tanislav 	}
1024cbab791cSCosmin Tanislav 	case IIO_EV_INFO_PERIOD:
1025cbab791cSCosmin Tanislav 		switch (dir) {
1026cbab791cSCosmin Tanislav 		case IIO_EV_DIR_RISING:
1027cbab791cSCosmin Tanislav 			mutex_lock(&st->lock);
1028cbab791cSCosmin Tanislav 			*val = st->act_time_ms;
1029cbab791cSCosmin Tanislav 			mutex_unlock(&st->lock);
1030cbab791cSCosmin Tanislav 			*val2 = 1000;
1031cbab791cSCosmin Tanislav 			return IIO_VAL_FRACTIONAL;
1032cbab791cSCosmin Tanislav 		case IIO_EV_DIR_FALLING:
1033cbab791cSCosmin Tanislav 			mutex_lock(&st->lock);
1034cbab791cSCosmin Tanislav 			*val = st->inact_time_ms;
1035cbab791cSCosmin Tanislav 			mutex_unlock(&st->lock);
1036cbab791cSCosmin Tanislav 			*val2 = 1000;
1037cbab791cSCosmin Tanislav 			return IIO_VAL_FRACTIONAL;
1038cbab791cSCosmin Tanislav 		default:
1039cbab791cSCosmin Tanislav 			return -EINVAL;
1040cbab791cSCosmin Tanislav 		}
1041cbab791cSCosmin Tanislav 	default:
1042cbab791cSCosmin Tanislav 		return -EINVAL;
1043cbab791cSCosmin Tanislav 	}
1044cbab791cSCosmin Tanislav }
1045cbab791cSCosmin Tanislav 
adxl367_write_event_value(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)1046cbab791cSCosmin Tanislav static int adxl367_write_event_value(struct iio_dev *indio_dev,
1047cbab791cSCosmin Tanislav 				     const struct iio_chan_spec *chan,
1048cbab791cSCosmin Tanislav 				     enum iio_event_type type,
1049cbab791cSCosmin Tanislav 				     enum iio_event_direction dir,
1050cbab791cSCosmin Tanislav 				     enum iio_event_info info,
1051cbab791cSCosmin Tanislav 				     int val, int val2)
1052cbab791cSCosmin Tanislav {
1053cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
1054cbab791cSCosmin Tanislav 
1055cbab791cSCosmin Tanislav 	switch (info) {
1056cbab791cSCosmin Tanislav 	case IIO_EV_INFO_VALUE:
1057cbab791cSCosmin Tanislav 		if (val < 0)
1058cbab791cSCosmin Tanislav 			return -EINVAL;
1059cbab791cSCosmin Tanislav 
1060cbab791cSCosmin Tanislav 		switch (dir) {
1061cbab791cSCosmin Tanislav 		case IIO_EV_DIR_RISING:
1062cbab791cSCosmin Tanislav 			return adxl367_set_act_threshold(st, ADXL367_ACTIVITY, val);
1063cbab791cSCosmin Tanislav 		case IIO_EV_DIR_FALLING:
1064cbab791cSCosmin Tanislav 			return adxl367_set_act_threshold(st, ADXL367_INACTIVITY, val);
1065cbab791cSCosmin Tanislav 		default:
1066cbab791cSCosmin Tanislav 			return -EINVAL;
1067cbab791cSCosmin Tanislav 		}
1068cbab791cSCosmin Tanislav 	case IIO_EV_INFO_PERIOD:
1069cbab791cSCosmin Tanislav 		if (val < 0)
1070cbab791cSCosmin Tanislav 			return -EINVAL;
1071cbab791cSCosmin Tanislav 
1072cbab791cSCosmin Tanislav 		val = val * 1000 + DIV_ROUND_UP(val2, 1000);
1073cbab791cSCosmin Tanislav 		switch (dir) {
1074cbab791cSCosmin Tanislav 		case IIO_EV_DIR_RISING:
1075cbab791cSCosmin Tanislav 			return adxl367_set_act_time_ms(st, ADXL367_ACTIVITY, val);
1076cbab791cSCosmin Tanislav 		case IIO_EV_DIR_FALLING:
1077cbab791cSCosmin Tanislav 			return adxl367_set_act_time_ms(st, ADXL367_INACTIVITY, val);
1078cbab791cSCosmin Tanislav 		default:
1079cbab791cSCosmin Tanislav 			return -EINVAL;
1080cbab791cSCosmin Tanislav 		}
1081cbab791cSCosmin Tanislav 	default:
1082cbab791cSCosmin Tanislav 		return -EINVAL;
1083cbab791cSCosmin Tanislav 	}
1084cbab791cSCosmin Tanislav }
1085cbab791cSCosmin Tanislav 
adxl367_read_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir)1086cbab791cSCosmin Tanislav static int adxl367_read_event_config(struct iio_dev *indio_dev,
1087cbab791cSCosmin Tanislav 				     const struct iio_chan_spec *chan,
1088cbab791cSCosmin Tanislav 				     enum iio_event_type type,
1089cbab791cSCosmin Tanislav 				     enum iio_event_direction dir)
1090cbab791cSCosmin Tanislav {
1091cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
1092cbab791cSCosmin Tanislav 	bool en;
1093cbab791cSCosmin Tanislav 	int ret;
1094cbab791cSCosmin Tanislav 
1095cbab791cSCosmin Tanislav 	switch (dir) {
1096cbab791cSCosmin Tanislav 	case IIO_EV_DIR_RISING:
1097cbab791cSCosmin Tanislav 		ret = adxl367_get_act_interrupt_en(st, ADXL367_ACTIVITY, &en);
1098cbab791cSCosmin Tanislav 		return ret ?: en;
1099cbab791cSCosmin Tanislav 	case IIO_EV_DIR_FALLING:
1100cbab791cSCosmin Tanislav 		ret = adxl367_get_act_interrupt_en(st, ADXL367_INACTIVITY, &en);
1101cbab791cSCosmin Tanislav 		return ret ?: en;
1102cbab791cSCosmin Tanislav 	default:
1103cbab791cSCosmin Tanislav 		return -EINVAL;
1104cbab791cSCosmin Tanislav 	}
1105cbab791cSCosmin Tanislav }
1106cbab791cSCosmin Tanislav 
adxl367_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)1107cbab791cSCosmin Tanislav static int adxl367_write_event_config(struct iio_dev *indio_dev,
1108cbab791cSCosmin Tanislav 				      const struct iio_chan_spec *chan,
1109cbab791cSCosmin Tanislav 				      enum iio_event_type type,
1110cbab791cSCosmin Tanislav 				      enum iio_event_direction dir,
1111cbab791cSCosmin Tanislav 				      int state)
1112cbab791cSCosmin Tanislav {
1113cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
1114cbab791cSCosmin Tanislav 	enum adxl367_activity_type act;
1115cbab791cSCosmin Tanislav 	int ret;
1116cbab791cSCosmin Tanislav 
1117cbab791cSCosmin Tanislav 	switch (dir) {
1118cbab791cSCosmin Tanislav 	case IIO_EV_DIR_RISING:
1119cbab791cSCosmin Tanislav 		act = ADXL367_ACTIVITY;
1120cbab791cSCosmin Tanislav 		break;
1121cbab791cSCosmin Tanislav 	case IIO_EV_DIR_FALLING:
1122cbab791cSCosmin Tanislav 		act = ADXL367_INACTIVITY;
1123cbab791cSCosmin Tanislav 		break;
1124cbab791cSCosmin Tanislav 	default:
1125cbab791cSCosmin Tanislav 		return -EINVAL;
1126cbab791cSCosmin Tanislav 	}
1127cbab791cSCosmin Tanislav 
1128cbab791cSCosmin Tanislav 	ret = iio_device_claim_direct_mode(indio_dev);
1129cbab791cSCosmin Tanislav 	if (ret)
1130cbab791cSCosmin Tanislav 		return ret;
1131cbab791cSCosmin Tanislav 
1132cbab791cSCosmin Tanislav 	mutex_lock(&st->lock);
1133cbab791cSCosmin Tanislav 
1134cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, false);
1135cbab791cSCosmin Tanislav 	if (ret)
1136cbab791cSCosmin Tanislav 		goto out;
1137cbab791cSCosmin Tanislav 
1138cbab791cSCosmin Tanislav 	ret = adxl367_set_act_interrupt_en(st, act, state);
1139cbab791cSCosmin Tanislav 	if (ret)
1140cbab791cSCosmin Tanislav 		goto out;
1141cbab791cSCosmin Tanislav 
1142cbab791cSCosmin Tanislav 	ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED
1143cbab791cSCosmin Tanislav 						: ADXL367_ACT_DISABLED);
1144cbab791cSCosmin Tanislav 	if (ret)
1145cbab791cSCosmin Tanislav 		goto out;
1146cbab791cSCosmin Tanislav 
1147cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, true);
1148cbab791cSCosmin Tanislav 
1149cbab791cSCosmin Tanislav out:
1150cbab791cSCosmin Tanislav 	mutex_unlock(&st->lock);
1151cbab791cSCosmin Tanislav 
1152cbab791cSCosmin Tanislav 	iio_device_release_direct_mode(indio_dev);
1153cbab791cSCosmin Tanislav 
1154cbab791cSCosmin Tanislav 	return ret;
1155cbab791cSCosmin Tanislav }
1156cbab791cSCosmin Tanislav 
adxl367_get_fifo_enabled(struct device * dev,struct device_attribute * attr,char * buf)1157cbab791cSCosmin Tanislav static ssize_t adxl367_get_fifo_enabled(struct device *dev,
1158cbab791cSCosmin Tanislav 					struct device_attribute *attr,
1159cbab791cSCosmin Tanislav 					char *buf)
1160cbab791cSCosmin Tanislav {
1161cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev));
1162cbab791cSCosmin Tanislav 	enum adxl367_fifo_mode fifo_mode;
1163cbab791cSCosmin Tanislav 	int ret;
1164cbab791cSCosmin Tanislav 
1165cbab791cSCosmin Tanislav 	ret = adxl367_get_fifo_mode(st, &fifo_mode);
1166cbab791cSCosmin Tanislav 	if (ret)
1167cbab791cSCosmin Tanislav 		return ret;
1168cbab791cSCosmin Tanislav 
1169cbab791cSCosmin Tanislav 	return sysfs_emit(buf, "%d\n", fifo_mode != ADXL367_FIFO_MODE_DISABLED);
1170cbab791cSCosmin Tanislav }
1171cbab791cSCosmin Tanislav 
adxl367_get_fifo_watermark(struct device * dev,struct device_attribute * attr,char * buf)1172cbab791cSCosmin Tanislav static ssize_t adxl367_get_fifo_watermark(struct device *dev,
1173cbab791cSCosmin Tanislav 					  struct device_attribute *attr,
1174cbab791cSCosmin Tanislav 					  char *buf)
1175cbab791cSCosmin Tanislav {
1176cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev));
1177cbab791cSCosmin Tanislav 	unsigned int fifo_watermark;
1178cbab791cSCosmin Tanislav 
1179cbab791cSCosmin Tanislav 	mutex_lock(&st->lock);
1180cbab791cSCosmin Tanislav 	fifo_watermark = st->fifo_watermark;
1181cbab791cSCosmin Tanislav 	mutex_unlock(&st->lock);
1182cbab791cSCosmin Tanislav 
1183cbab791cSCosmin Tanislav 	return sysfs_emit(buf, "%d\n", fifo_watermark);
1184cbab791cSCosmin Tanislav }
1185cbab791cSCosmin Tanislav 
1186f0ab171bSMatti Vaittinen IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1");
1187f0ab171bSMatti Vaittinen IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max,
1188f0ab171bSMatti Vaittinen 			     __stringify(ADXL367_FIFO_MAX_WATERMARK));
1189cbab791cSCosmin Tanislav static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
1190cbab791cSCosmin Tanislav 		       adxl367_get_fifo_watermark, NULL, 0);
1191cbab791cSCosmin Tanislav static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
1192cbab791cSCosmin Tanislav 		       adxl367_get_fifo_enabled, NULL, 0);
1193cbab791cSCosmin Tanislav 
11940a33755cSMatti Vaittinen static const struct iio_dev_attr *adxl367_fifo_attributes[] = {
11950a33755cSMatti Vaittinen 	&iio_dev_attr_hwfifo_watermark_min,
11960a33755cSMatti Vaittinen 	&iio_dev_attr_hwfifo_watermark_max,
11970a33755cSMatti Vaittinen 	&iio_dev_attr_hwfifo_watermark,
11980a33755cSMatti Vaittinen 	&iio_dev_attr_hwfifo_enabled,
1199cbab791cSCosmin Tanislav 	NULL,
1200cbab791cSCosmin Tanislav };
1201cbab791cSCosmin Tanislav 
adxl367_set_watermark(struct iio_dev * indio_dev,unsigned int val)1202cbab791cSCosmin Tanislav static int adxl367_set_watermark(struct iio_dev *indio_dev, unsigned int val)
1203cbab791cSCosmin Tanislav {
1204cbab791cSCosmin Tanislav 	struct adxl367_state *st  = iio_priv(indio_dev);
1205cbab791cSCosmin Tanislav 	int ret;
1206cbab791cSCosmin Tanislav 
1207cbab791cSCosmin Tanislav 	if (val > ADXL367_FIFO_MAX_WATERMARK)
1208cbab791cSCosmin Tanislav 		return -EINVAL;
1209cbab791cSCosmin Tanislav 
1210cbab791cSCosmin Tanislav 	mutex_lock(&st->lock);
1211cbab791cSCosmin Tanislav 
1212cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, false);
1213cbab791cSCosmin Tanislav 	if (ret)
1214cbab791cSCosmin Tanislav 		goto out;
1215cbab791cSCosmin Tanislav 
1216cbab791cSCosmin Tanislav 	ret = adxl367_set_fifo_watermark(st, val);
1217cbab791cSCosmin Tanislav 	if (ret)
1218cbab791cSCosmin Tanislav 		goto out;
1219cbab791cSCosmin Tanislav 
1220cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, true);
1221cbab791cSCosmin Tanislav 
1222cbab791cSCosmin Tanislav out:
1223cbab791cSCosmin Tanislav 	mutex_unlock(&st->lock);
1224cbab791cSCosmin Tanislav 
1225cbab791cSCosmin Tanislav 	return ret;
1226cbab791cSCosmin Tanislav }
1227cbab791cSCosmin Tanislav 
adxl367_find_mask_fifo_format(const unsigned long * scan_mask,enum adxl367_fifo_format * fifo_format)1228cbab791cSCosmin Tanislav static bool adxl367_find_mask_fifo_format(const unsigned long *scan_mask,
1229cbab791cSCosmin Tanislav 					  enum adxl367_fifo_format *fifo_format)
1230cbab791cSCosmin Tanislav {
1231cbab791cSCosmin Tanislav 	size_t size = ARRAY_SIZE(adxl367_fifo_formats);
1232cbab791cSCosmin Tanislav 	int i;
1233cbab791cSCosmin Tanislav 
1234cbab791cSCosmin Tanislav 	for (i = 0; i < size; i++)
1235cbab791cSCosmin Tanislav 		if (*scan_mask == adxl367_channel_masks[i])
1236cbab791cSCosmin Tanislav 			break;
1237cbab791cSCosmin Tanislav 
1238cbab791cSCosmin Tanislav 	if (i == size)
1239cbab791cSCosmin Tanislav 		return false;
1240cbab791cSCosmin Tanislav 
1241cbab791cSCosmin Tanislav 	*fifo_format = adxl367_fifo_formats[i];
1242cbab791cSCosmin Tanislav 
1243cbab791cSCosmin Tanislav 	return true;
1244cbab791cSCosmin Tanislav }
1245cbab791cSCosmin Tanislav 
adxl367_update_scan_mode(struct iio_dev * indio_dev,const unsigned long * active_scan_mask)1246cbab791cSCosmin Tanislav static int adxl367_update_scan_mode(struct iio_dev *indio_dev,
1247cbab791cSCosmin Tanislav 				    const unsigned long *active_scan_mask)
1248cbab791cSCosmin Tanislav {
1249cbab791cSCosmin Tanislav 	struct adxl367_state *st  = iio_priv(indio_dev);
1250cbab791cSCosmin Tanislav 	enum adxl367_fifo_format fifo_format;
1251cbab791cSCosmin Tanislav 	int ret;
1252cbab791cSCosmin Tanislav 
1253cbab791cSCosmin Tanislav 	if (!adxl367_find_mask_fifo_format(active_scan_mask, &fifo_format))
1254cbab791cSCosmin Tanislav 		return -EINVAL;
1255cbab791cSCosmin Tanislav 
1256cbab791cSCosmin Tanislav 	mutex_lock(&st->lock);
1257cbab791cSCosmin Tanislav 
1258cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, false);
1259cbab791cSCosmin Tanislav 	if (ret)
1260cbab791cSCosmin Tanislav 		goto out;
1261cbab791cSCosmin Tanislav 
1262cbab791cSCosmin Tanislav 	ret = adxl367_set_fifo_format(st, fifo_format);
1263cbab791cSCosmin Tanislav 	if (ret)
1264cbab791cSCosmin Tanislav 		goto out;
1265cbab791cSCosmin Tanislav 
12660bd0bb1fSCosmin Tanislav 	ret = adxl367_set_measure_en(st, true);
1267cbab791cSCosmin Tanislav 	if (ret)
1268cbab791cSCosmin Tanislav 		goto out;
1269cbab791cSCosmin Tanislav 
12700bd0bb1fSCosmin Tanislav 	st->fifo_set_size = bitmap_weight(active_scan_mask,
12710bd0bb1fSCosmin Tanislav 					  indio_dev->masklength);
1272cbab791cSCosmin Tanislav 
1273cbab791cSCosmin Tanislav out:
1274cbab791cSCosmin Tanislav 	mutex_unlock(&st->lock);
1275cbab791cSCosmin Tanislav 
1276cbab791cSCosmin Tanislav 	return ret;
1277cbab791cSCosmin Tanislav }
1278cbab791cSCosmin Tanislav 
adxl367_buffer_postenable(struct iio_dev * indio_dev)1279cbab791cSCosmin Tanislav static int adxl367_buffer_postenable(struct iio_dev *indio_dev)
1280cbab791cSCosmin Tanislav {
1281cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
1282cbab791cSCosmin Tanislav 	int ret;
1283cbab791cSCosmin Tanislav 
1284cbab791cSCosmin Tanislav 	mutex_lock(&st->lock);
1285cbab791cSCosmin Tanislav 
1286cbab791cSCosmin Tanislav 	ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
1287cbab791cSCosmin Tanislav 					   true);
1288cbab791cSCosmin Tanislav 	if (ret)
1289cbab791cSCosmin Tanislav 		goto out;
1290cbab791cSCosmin Tanislav 
1291cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, false);
1292cbab791cSCosmin Tanislav 	if (ret)
1293cbab791cSCosmin Tanislav 		goto out;
1294cbab791cSCosmin Tanislav 
1295cbab791cSCosmin Tanislav 	ret = adxl367_set_fifo_watermark_interrupt_en(st, true);
1296cbab791cSCosmin Tanislav 	if (ret)
1297cbab791cSCosmin Tanislav 		goto out;
1298cbab791cSCosmin Tanislav 
1299cbab791cSCosmin Tanislav 	ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_STREAM);
1300cbab791cSCosmin Tanislav 	if (ret)
1301cbab791cSCosmin Tanislav 		goto out;
1302cbab791cSCosmin Tanislav 
1303cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, true);
1304cbab791cSCosmin Tanislav 
1305cbab791cSCosmin Tanislav out:
1306cbab791cSCosmin Tanislav 	mutex_unlock(&st->lock);
1307cbab791cSCosmin Tanislav 
1308cbab791cSCosmin Tanislav 	return ret;
1309cbab791cSCosmin Tanislav }
1310cbab791cSCosmin Tanislav 
adxl367_buffer_predisable(struct iio_dev * indio_dev)1311cbab791cSCosmin Tanislav static int adxl367_buffer_predisable(struct iio_dev *indio_dev)
1312cbab791cSCosmin Tanislav {
1313cbab791cSCosmin Tanislav 	struct adxl367_state *st = iio_priv(indio_dev);
1314cbab791cSCosmin Tanislav 	int ret;
1315cbab791cSCosmin Tanislav 
1316cbab791cSCosmin Tanislav 	mutex_lock(&st->lock);
1317cbab791cSCosmin Tanislav 
1318cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, false);
1319cbab791cSCosmin Tanislav 	if (ret)
1320cbab791cSCosmin Tanislav 		goto out;
1321cbab791cSCosmin Tanislav 
1322cbab791cSCosmin Tanislav 	ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_DISABLED);
1323cbab791cSCosmin Tanislav 	if (ret)
1324cbab791cSCosmin Tanislav 		goto out;
1325cbab791cSCosmin Tanislav 
1326cbab791cSCosmin Tanislav 	ret = adxl367_set_fifo_watermark_interrupt_en(st, false);
1327cbab791cSCosmin Tanislav 	if (ret)
1328cbab791cSCosmin Tanislav 		goto out;
1329cbab791cSCosmin Tanislav 
1330cbab791cSCosmin Tanislav 	ret = adxl367_set_measure_en(st, true);
1331cbab791cSCosmin Tanislav 	if (ret)
13327948d301SDan Carpenter 		goto out;
1333cbab791cSCosmin Tanislav 
1334cbab791cSCosmin Tanislav 	ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
1335cbab791cSCosmin Tanislav 					   false);
1336cbab791cSCosmin Tanislav 
1337cbab791cSCosmin Tanislav out:
1338cbab791cSCosmin Tanislav 	mutex_unlock(&st->lock);
1339cbab791cSCosmin Tanislav 
1340cbab791cSCosmin Tanislav 	return ret;
1341cbab791cSCosmin Tanislav }
1342cbab791cSCosmin Tanislav 
1343cbab791cSCosmin Tanislav static const struct iio_buffer_setup_ops adxl367_buffer_ops = {
1344cbab791cSCosmin Tanislav 	.postenable = adxl367_buffer_postenable,
1345cbab791cSCosmin Tanislav 	.predisable = adxl367_buffer_predisable,
1346cbab791cSCosmin Tanislav };
1347cbab791cSCosmin Tanislav 
1348cbab791cSCosmin Tanislav static const struct iio_info adxl367_info = {
1349cbab791cSCosmin Tanislav 	.read_raw = adxl367_read_raw,
1350cbab791cSCosmin Tanislav 	.write_raw = adxl367_write_raw,
1351cbab791cSCosmin Tanislav 	.write_raw_get_fmt = adxl367_write_raw_get_fmt,
1352cbab791cSCosmin Tanislav 	.read_avail = adxl367_read_avail,
1353cbab791cSCosmin Tanislav 	.read_event_config = adxl367_read_event_config,
1354cbab791cSCosmin Tanislav 	.write_event_config = adxl367_write_event_config,
1355cbab791cSCosmin Tanislav 	.read_event_value = adxl367_read_event_value,
1356cbab791cSCosmin Tanislav 	.write_event_value = adxl367_write_event_value,
1357cbab791cSCosmin Tanislav 	.debugfs_reg_access = adxl367_reg_access,
1358cbab791cSCosmin Tanislav 	.hwfifo_set_watermark = adxl367_set_watermark,
1359cbab791cSCosmin Tanislav 	.update_scan_mode = adxl367_update_scan_mode,
1360cbab791cSCosmin Tanislav };
1361cbab791cSCosmin Tanislav 
1362cbab791cSCosmin Tanislav static const struct iio_event_spec adxl367_events[] = {
1363cbab791cSCosmin Tanislav 	{
1364cbab791cSCosmin Tanislav 		.type = IIO_EV_TYPE_MAG_REFERENCED,
1365cbab791cSCosmin Tanislav 		.dir = IIO_EV_DIR_RISING,
1366cbab791cSCosmin Tanislav 		.mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
1367cbab791cSCosmin Tanislav 				       BIT(IIO_EV_INFO_PERIOD) |
1368cbab791cSCosmin Tanislav 				       BIT(IIO_EV_INFO_VALUE),
1369cbab791cSCosmin Tanislav 	},
1370cbab791cSCosmin Tanislav 	{
1371cbab791cSCosmin Tanislav 		.type = IIO_EV_TYPE_MAG_REFERENCED,
1372cbab791cSCosmin Tanislav 		.dir = IIO_EV_DIR_FALLING,
1373cbab791cSCosmin Tanislav 		.mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
1374cbab791cSCosmin Tanislav 				       BIT(IIO_EV_INFO_PERIOD) |
1375cbab791cSCosmin Tanislav 				       BIT(IIO_EV_INFO_VALUE),
1376cbab791cSCosmin Tanislav 	},
1377cbab791cSCosmin Tanislav };
1378cbab791cSCosmin Tanislav 
1379cbab791cSCosmin Tanislav #define ADXL367_ACCEL_CHANNEL(index, reg, axis) {			\
1380cbab791cSCosmin Tanislav 	.type = IIO_ACCEL,						\
1381cbab791cSCosmin Tanislav 	.address = (reg),						\
1382cbab791cSCosmin Tanislav 	.modified = 1,							\
1383cbab791cSCosmin Tanislav 	.channel2 = IIO_MOD_##axis,					\
1384cbab791cSCosmin Tanislav 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\
1385cbab791cSCosmin Tanislav 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),		\
1386cbab791cSCosmin Tanislav 	.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),	\
1387cbab791cSCosmin Tanislav 	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
1388cbab791cSCosmin Tanislav 	.info_mask_shared_by_all_available =				\
1389cbab791cSCosmin Tanislav 			BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
1390cbab791cSCosmin Tanislav 	.event_spec = adxl367_events,					\
1391cbab791cSCosmin Tanislav 	.num_event_specs = ARRAY_SIZE(adxl367_events),			\
1392cbab791cSCosmin Tanislav 	.scan_index = (index),						\
1393cbab791cSCosmin Tanislav 	.scan_type = {							\
1394cbab791cSCosmin Tanislav 		.sign = 's',						\
1395cbab791cSCosmin Tanislav 		.realbits = 14,						\
1396cbab791cSCosmin Tanislav 		.storagebits = 16,					\
1397cbab791cSCosmin Tanislav 		.endianness = IIO_BE,					\
1398cbab791cSCosmin Tanislav 	},								\
1399cbab791cSCosmin Tanislav }
1400cbab791cSCosmin Tanislav 
1401cbab791cSCosmin Tanislav #define ADXL367_CHANNEL(index, reg, _type) {				\
1402cbab791cSCosmin Tanislav 	.type = (_type),						\
1403cbab791cSCosmin Tanislav 	.address = (reg),						\
1404cbab791cSCosmin Tanislav 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
1405cbab791cSCosmin Tanislav 			      BIT(IIO_CHAN_INFO_OFFSET) |		\
1406cbab791cSCosmin Tanislav 			      BIT(IIO_CHAN_INFO_SCALE),			\
1407cbab791cSCosmin Tanislav 	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
1408cbab791cSCosmin Tanislav 	.scan_index = (index),						\
1409cbab791cSCosmin Tanislav 	.scan_type = {							\
1410cbab791cSCosmin Tanislav 		.sign = 's',						\
1411cbab791cSCosmin Tanislav 		.realbits = 14,						\
1412cbab791cSCosmin Tanislav 		.storagebits = 16,					\
1413cbab791cSCosmin Tanislav 		.endianness = IIO_BE,					\
1414cbab791cSCosmin Tanislav 	},								\
1415cbab791cSCosmin Tanislav }
1416cbab791cSCosmin Tanislav 
1417cbab791cSCosmin Tanislav static const struct iio_chan_spec adxl367_channels[] = {
1418cbab791cSCosmin Tanislav 	ADXL367_ACCEL_CHANNEL(ADXL367_X_CHANNEL_INDEX, ADXL367_REG_X_DATA_H, X),
1419cbab791cSCosmin Tanislav 	ADXL367_ACCEL_CHANNEL(ADXL367_Y_CHANNEL_INDEX, ADXL367_REG_Y_DATA_H, Y),
1420cbab791cSCosmin Tanislav 	ADXL367_ACCEL_CHANNEL(ADXL367_Z_CHANNEL_INDEX, ADXL367_REG_Z_DATA_H, Z),
1421cbab791cSCosmin Tanislav 	ADXL367_CHANNEL(ADXL367_TEMP_CHANNEL_INDEX, ADXL367_REG_TEMP_DATA_H,
1422cbab791cSCosmin Tanislav 			IIO_TEMP),
1423cbab791cSCosmin Tanislav 	ADXL367_CHANNEL(ADXL367_EX_ADC_CHANNEL_INDEX, ADXL367_REG_EX_ADC_DATA_H,
1424cbab791cSCosmin Tanislav 			IIO_VOLTAGE),
1425cbab791cSCosmin Tanislav };
1426cbab791cSCosmin Tanislav 
adxl367_verify_devid(struct adxl367_state * st)1427cbab791cSCosmin Tanislav static int adxl367_verify_devid(struct adxl367_state *st)
1428cbab791cSCosmin Tanislav {
1429cbab791cSCosmin Tanislav 	unsigned int val;
1430cbab791cSCosmin Tanislav 	int ret;
1431cbab791cSCosmin Tanislav 
143273d42ed4SCosmin Tanislav 	ret = regmap_read(st->regmap, ADXL367_REG_DEVID, &val);
1433cbab791cSCosmin Tanislav 	if (ret)
143473d42ed4SCosmin Tanislav 		return dev_err_probe(st->dev, ret, "Failed to read dev id\n");
143573d42ed4SCosmin Tanislav 
143673d42ed4SCosmin Tanislav 	if (val != ADXL367_DEVID_AD)
1437cbab791cSCosmin Tanislav 		return dev_err_probe(st->dev, -ENODEV,
1438cbab791cSCosmin Tanislav 				     "Invalid dev id 0x%02X, expected 0x%02X\n",
1439cbab791cSCosmin Tanislav 				     val, ADXL367_DEVID_AD);
1440cbab791cSCosmin Tanislav 
1441cbab791cSCosmin Tanislav 	return 0;
1442cbab791cSCosmin Tanislav }
1443cbab791cSCosmin Tanislav 
adxl367_setup(struct adxl367_state * st)1444cbab791cSCosmin Tanislav static int adxl367_setup(struct adxl367_state *st)
1445cbab791cSCosmin Tanislav {
1446cbab791cSCosmin Tanislav 	int ret;
1447cbab791cSCosmin Tanislav 
1448cbab791cSCosmin Tanislav 	ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY,
1449cbab791cSCosmin Tanislav 					 ADXL367_2G_RANGE_1G);
1450cbab791cSCosmin Tanislav 	if (ret)
1451cbab791cSCosmin Tanislav 		return ret;
1452cbab791cSCosmin Tanislav 
1453cbab791cSCosmin Tanislav 	ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY,
1454cbab791cSCosmin Tanislav 					 ADXL367_2G_RANGE_100MG);
1455cbab791cSCosmin Tanislav 	if (ret)
1456cbab791cSCosmin Tanislav 		return ret;
1457cbab791cSCosmin Tanislav 
1458cbab791cSCosmin Tanislav 	ret = adxl367_set_act_proc_mode(st, ADXL367_LOOPED);
1459cbab791cSCosmin Tanislav 	if (ret)
1460cbab791cSCosmin Tanislav 		return ret;
1461cbab791cSCosmin Tanislav 
1462cbab791cSCosmin Tanislav 	ret = _adxl367_set_odr(st, ADXL367_ODR_400HZ);
1463cbab791cSCosmin Tanislav 	if (ret)
1464cbab791cSCosmin Tanislav 		return ret;
1465cbab791cSCosmin Tanislav 
1466cbab791cSCosmin Tanislav 	ret = _adxl367_set_act_time_ms(st, 10);
1467cbab791cSCosmin Tanislav 	if (ret)
1468cbab791cSCosmin Tanislav 		return ret;
1469cbab791cSCosmin Tanislav 
1470cbab791cSCosmin Tanislav 	ret = _adxl367_set_inact_time_ms(st, 10000);
1471cbab791cSCosmin Tanislav 	if (ret)
1472cbab791cSCosmin Tanislav 		return ret;
1473cbab791cSCosmin Tanislav 
1474cbab791cSCosmin Tanislav 	return adxl367_set_measure_en(st, true);
1475cbab791cSCosmin Tanislav }
1476cbab791cSCosmin Tanislav 
adxl367_probe(struct device * dev,const struct adxl367_ops * ops,void * context,struct regmap * regmap,int irq)1477cbab791cSCosmin Tanislav int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
1478cbab791cSCosmin Tanislav 		  void *context, struct regmap *regmap, int irq)
1479cbab791cSCosmin Tanislav {
1480e9b96e18SJonathan Cameron 	static const char * const regulator_names[] = { "vdd", "vddio" };
1481cbab791cSCosmin Tanislav 	struct iio_dev *indio_dev;
1482cbab791cSCosmin Tanislav 	struct adxl367_state *st;
1483cbab791cSCosmin Tanislav 	int ret;
1484cbab791cSCosmin Tanislav 
1485cbab791cSCosmin Tanislav 	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
1486cbab791cSCosmin Tanislav 	if (!indio_dev)
1487cbab791cSCosmin Tanislav 		return -ENOMEM;
1488cbab791cSCosmin Tanislav 
1489cbab791cSCosmin Tanislav 	st = iio_priv(indio_dev);
1490cbab791cSCosmin Tanislav 	st->dev = dev;
1491cbab791cSCosmin Tanislav 	st->regmap = regmap;
1492cbab791cSCosmin Tanislav 	st->context = context;
1493cbab791cSCosmin Tanislav 	st->ops = ops;
1494cbab791cSCosmin Tanislav 
1495cbab791cSCosmin Tanislav 	mutex_init(&st->lock);
1496cbab791cSCosmin Tanislav 
1497cbab791cSCosmin Tanislav 	indio_dev->channels = adxl367_channels;
1498cbab791cSCosmin Tanislav 	indio_dev->num_channels = ARRAY_SIZE(adxl367_channels);
1499cbab791cSCosmin Tanislav 	indio_dev->available_scan_masks = adxl367_channel_masks;
1500cbab791cSCosmin Tanislav 	indio_dev->name = "adxl367";
1501cbab791cSCosmin Tanislav 	indio_dev->info = &adxl367_info;
1502cbab791cSCosmin Tanislav 	indio_dev->modes = INDIO_DIRECT_MODE;
1503cbab791cSCosmin Tanislav 
1504e9b96e18SJonathan Cameron 	ret = devm_regulator_bulk_get_enable(st->dev,
1505e9b96e18SJonathan Cameron 					     ARRAY_SIZE(regulator_names),
1506e9b96e18SJonathan Cameron 					     regulator_names);
1507cbab791cSCosmin Tanislav 	if (ret)
1508cbab791cSCosmin Tanislav 		return dev_err_probe(st->dev, ret,
1509cbab791cSCosmin Tanislav 				     "Failed to get regulators\n");
1510cbab791cSCosmin Tanislav 
1511cbab791cSCosmin Tanislav 	ret = regmap_write(st->regmap, ADXL367_REG_RESET, ADXL367_RESET_CODE);
1512cbab791cSCosmin Tanislav 	if (ret)
1513cbab791cSCosmin Tanislav 		return ret;
1514cbab791cSCosmin Tanislav 
151573d42ed4SCosmin Tanislav 	fsleep(15000);
151673d42ed4SCosmin Tanislav 
1517cbab791cSCosmin Tanislav 	ret = adxl367_verify_devid(st);
1518cbab791cSCosmin Tanislav 	if (ret)
1519cbab791cSCosmin Tanislav 		return ret;
1520cbab791cSCosmin Tanislav 
1521cbab791cSCosmin Tanislav 	ret = adxl367_setup(st);
1522cbab791cSCosmin Tanislav 	if (ret)
1523cbab791cSCosmin Tanislav 		return ret;
1524cbab791cSCosmin Tanislav 
1525cbab791cSCosmin Tanislav 	ret = devm_iio_kfifo_buffer_setup_ext(st->dev, indio_dev,
1526cbab791cSCosmin Tanislav 					      &adxl367_buffer_ops,
1527cbab791cSCosmin Tanislav 					      adxl367_fifo_attributes);
1528cbab791cSCosmin Tanislav 	if (ret)
1529cbab791cSCosmin Tanislav 		return ret;
1530cbab791cSCosmin Tanislav 
1531cbab791cSCosmin Tanislav 	ret = devm_request_threaded_irq(st->dev, irq, NULL,
1532cbab791cSCosmin Tanislav 					adxl367_irq_handler, IRQF_ONESHOT,
1533cbab791cSCosmin Tanislav 					indio_dev->name, indio_dev);
1534cbab791cSCosmin Tanislav 	if (ret)
1535cbab791cSCosmin Tanislav 		return dev_err_probe(st->dev, ret, "Failed to request irq\n");
1536cbab791cSCosmin Tanislav 
1537cbab791cSCosmin Tanislav 	return devm_iio_device_register(dev, indio_dev);
1538cbab791cSCosmin Tanislav }
1539cbab791cSCosmin Tanislav EXPORT_SYMBOL_NS_GPL(adxl367_probe, IIO_ADXL367);
1540cbab791cSCosmin Tanislav 
1541cbab791cSCosmin Tanislav MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>");
1542cbab791cSCosmin Tanislav MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer driver");
1543cbab791cSCosmin Tanislav MODULE_LICENSE("GPL");
1544