xref: /linux/drivers/iio/accel/adxl355_core.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
112ed2786SPuranjay Mohan // SPDX-License-Identifier: GPL-2.0-only
212ed2786SPuranjay Mohan /*
312ed2786SPuranjay Mohan  * ADXL355 3-Axis Digital Accelerometer IIO core driver
412ed2786SPuranjay Mohan  *
512ed2786SPuranjay Mohan  * Copyright (c) 2021 Puranjay Mohan <puranjay12@gmail.com>
612ed2786SPuranjay Mohan  *
712ed2786SPuranjay Mohan  * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/adxl354_adxl355.pdf
812ed2786SPuranjay Mohan  */
912ed2786SPuranjay Mohan 
1012ed2786SPuranjay Mohan #include <linux/bits.h>
1112ed2786SPuranjay Mohan #include <linux/bitfield.h>
12327a0eafSPuranjay Mohan #include <linux/iio/buffer.h>
1312ed2786SPuranjay Mohan #include <linux/iio/iio.h>
14327a0eafSPuranjay Mohan #include <linux/iio/trigger.h>
15327a0eafSPuranjay Mohan #include <linux/iio/triggered_buffer.h>
16327a0eafSPuranjay Mohan #include <linux/iio/trigger_consumer.h>
1712ed2786SPuranjay Mohan #include <linux/limits.h>
1812ed2786SPuranjay Mohan #include <linux/math64.h>
1912ed2786SPuranjay Mohan #include <linux/module.h>
2012ed2786SPuranjay Mohan #include <linux/mod_devicetable.h>
21d1100dd9SPuranjay Mohan #include <linux/property.h>
2212ed2786SPuranjay Mohan #include <linux/regmap.h>
2308f5fbf0SAndy Shevchenko #include <linux/units.h>
2408f5fbf0SAndy Shevchenko 
255f60d5f6SAl Viro #include <linux/unaligned.h>
2612ed2786SPuranjay Mohan 
2712ed2786SPuranjay Mohan #include "adxl355.h"
2812ed2786SPuranjay Mohan 
2912ed2786SPuranjay Mohan /* ADXL355 Register Definitions */
3012ed2786SPuranjay Mohan #define ADXL355_DEVID_AD_REG		0x00
3112ed2786SPuranjay Mohan #define ADXL355_DEVID_MST_REG		0x01
3212ed2786SPuranjay Mohan #define ADXL355_PARTID_REG		0x02
3312ed2786SPuranjay Mohan #define ADXL355_STATUS_REG		0x04
3412ed2786SPuranjay Mohan #define ADXL355_FIFO_ENTRIES_REG	0x05
3512ed2786SPuranjay Mohan #define ADXL355_TEMP2_REG		0x06
3612ed2786SPuranjay Mohan #define ADXL355_XDATA3_REG		0x08
3712ed2786SPuranjay Mohan #define ADXL355_YDATA3_REG		0x0B
3812ed2786SPuranjay Mohan #define ADXL355_ZDATA3_REG		0x0E
3912ed2786SPuranjay Mohan #define ADXL355_FIFO_DATA_REG		0x11
4012ed2786SPuranjay Mohan #define ADXL355_OFFSET_X_H_REG		0x1E
4112ed2786SPuranjay Mohan #define ADXL355_OFFSET_Y_H_REG		0x20
4212ed2786SPuranjay Mohan #define ADXL355_OFFSET_Z_H_REG		0x22
4312ed2786SPuranjay Mohan #define ADXL355_ACT_EN_REG		0x24
4412ed2786SPuranjay Mohan #define ADXL355_ACT_THRESH_H_REG	0x25
4512ed2786SPuranjay Mohan #define ADXL355_ACT_THRESH_L_REG	0x26
4612ed2786SPuranjay Mohan #define ADXL355_ACT_COUNT_REG		0x27
4712ed2786SPuranjay Mohan #define ADXL355_FILTER_REG		0x28
4812ed2786SPuranjay Mohan #define  ADXL355_FILTER_ODR_MSK GENMASK(3, 0)
4912ed2786SPuranjay Mohan #define  ADXL355_FILTER_HPF_MSK	GENMASK(6, 4)
5012ed2786SPuranjay Mohan #define ADXL355_FIFO_SAMPLES_REG	0x29
5112ed2786SPuranjay Mohan #define ADXL355_INT_MAP_REG		0x2A
5212ed2786SPuranjay Mohan #define ADXL355_SYNC_REG		0x2B
5312ed2786SPuranjay Mohan #define ADXL355_RANGE_REG		0x2C
5412ed2786SPuranjay Mohan #define ADXL355_POWER_CTL_REG		0x2D
5512ed2786SPuranjay Mohan #define  ADXL355_POWER_CTL_MODE_MSK	GENMASK(1, 0)
56327a0eafSPuranjay Mohan #define  ADXL355_POWER_CTL_DRDY_MSK	BIT(2)
5712ed2786SPuranjay Mohan #define ADXL355_SELF_TEST_REG		0x2E
5812ed2786SPuranjay Mohan #define ADXL355_RESET_REG		0x2F
5912ed2786SPuranjay Mohan 
6012ed2786SPuranjay Mohan #define ADXL355_DEVID_AD_VAL		0xAD
6112ed2786SPuranjay Mohan #define ADXL355_DEVID_MST_VAL		0x1D
6212ed2786SPuranjay Mohan #define ADXL355_PARTID_VAL		0xED
63d3532d69SRamona Bolboaca #define ADXL359_PARTID_VAL		0xE9
6412ed2786SPuranjay Mohan #define ADXL355_RESET_CODE		0x52
6512ed2786SPuranjay Mohan 
6612ed2786SPuranjay Mohan static const struct regmap_range adxl355_read_reg_range[] = {
6712ed2786SPuranjay Mohan 	regmap_reg_range(ADXL355_DEVID_AD_REG, ADXL355_FIFO_DATA_REG),
6812ed2786SPuranjay Mohan 	regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_SELF_TEST_REG),
6912ed2786SPuranjay Mohan };
7012ed2786SPuranjay Mohan 
7112ed2786SPuranjay Mohan const struct regmap_access_table adxl355_readable_regs_tbl = {
7212ed2786SPuranjay Mohan 	.yes_ranges = adxl355_read_reg_range,
7312ed2786SPuranjay Mohan 	.n_yes_ranges = ARRAY_SIZE(adxl355_read_reg_range),
7412ed2786SPuranjay Mohan };
75cdd30ebbSPeter Zijlstra EXPORT_SYMBOL_NS_GPL(adxl355_readable_regs_tbl, "IIO_ADXL355");
7612ed2786SPuranjay Mohan 
7712ed2786SPuranjay Mohan static const struct regmap_range adxl355_write_reg_range[] = {
7812ed2786SPuranjay Mohan 	regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_RESET_REG),
7912ed2786SPuranjay Mohan };
8012ed2786SPuranjay Mohan 
8112ed2786SPuranjay Mohan const struct regmap_access_table adxl355_writeable_regs_tbl = {
8212ed2786SPuranjay Mohan 	.yes_ranges = adxl355_write_reg_range,
8312ed2786SPuranjay Mohan 	.n_yes_ranges = ARRAY_SIZE(adxl355_write_reg_range),
8412ed2786SPuranjay Mohan };
85cdd30ebbSPeter Zijlstra EXPORT_SYMBOL_NS_GPL(adxl355_writeable_regs_tbl, "IIO_ADXL355");
8612ed2786SPuranjay Mohan 
87d3532d69SRamona Bolboaca const struct adxl355_chip_info adxl35x_chip_info[] = {
88d3532d69SRamona Bolboaca 	[ADXL355] = {
89d3532d69SRamona Bolboaca 		.name = "adxl355",
90d3532d69SRamona Bolboaca 		.part_id = ADXL355_PARTID_VAL,
91d3532d69SRamona Bolboaca 		/*
92d3532d69SRamona Bolboaca 		 * At +/- 2g with 20-bit resolution, scale is given in datasheet
93d3532d69SRamona Bolboaca 		 * as 3.9ug/LSB = 0.0000039 * 9.80665 = 0.00003824593 m/s^2.
94d3532d69SRamona Bolboaca 		 */
95d3532d69SRamona Bolboaca 		.accel_scale = {
96d3532d69SRamona Bolboaca 			.integer = 0,
97d3532d69SRamona Bolboaca 			.decimal = 38245,
98d3532d69SRamona Bolboaca 		},
99d3532d69SRamona Bolboaca 		/*
100d3532d69SRamona Bolboaca 		 * The datasheet defines an intercept of 1885 LSB at 25 degC
101d3532d69SRamona Bolboaca 		 * and a slope of -9.05 LSB/C. The following formula can be used
102d3532d69SRamona Bolboaca 		 * to find the temperature:
103d3532d69SRamona Bolboaca 		 * Temp = ((RAW - 1885)/(-9.05)) + 25 but this doesn't follow
104d3532d69SRamona Bolboaca 		 * the format of the IIO which is Temp = (RAW + OFFSET) * SCALE.
105d3532d69SRamona Bolboaca 		 * Hence using some rearranging we get the scale as -110.497238
106d3532d69SRamona Bolboaca 		 * and offset as -2111.25.
107d3532d69SRamona Bolboaca 		 */
108d3532d69SRamona Bolboaca 		.temp_offset = {
109d3532d69SRamona Bolboaca 			.integer =  -2111,
110d3532d69SRamona Bolboaca 			.decimal = 250000,
111d3532d69SRamona Bolboaca 		},
112d3532d69SRamona Bolboaca 	},
113d3532d69SRamona Bolboaca 	[ADXL359] = {
114d3532d69SRamona Bolboaca 		.name = "adxl359",
115d3532d69SRamona Bolboaca 		.part_id = ADXL359_PARTID_VAL,
116d3532d69SRamona Bolboaca 		/*
117d3532d69SRamona Bolboaca 		 * At +/- 10g with 20-bit resolution, scale is given in datasheet
118d3532d69SRamona Bolboaca 		 * as 19.5ug/LSB = 0.0000195 * 9.80665 = 0.0.00019122967 m/s^2.
119d3532d69SRamona Bolboaca 		 */
120d3532d69SRamona Bolboaca 		.accel_scale = {
121d3532d69SRamona Bolboaca 			.integer = 0,
122d3532d69SRamona Bolboaca 			.decimal = 191229,
123d3532d69SRamona Bolboaca 		},
124d3532d69SRamona Bolboaca 		/*
125d3532d69SRamona Bolboaca 		 * The datasheet defines an intercept of 1852 LSB at 25 degC
126d3532d69SRamona Bolboaca 		 * and a slope of -9.05 LSB/C. The following formula can be used
127d3532d69SRamona Bolboaca 		 * to find the temperature:
128d3532d69SRamona Bolboaca 		 * Temp = ((RAW - 1852)/(-9.05)) + 25 but this doesn't follow
129d3532d69SRamona Bolboaca 		 * the format of the IIO which is Temp = (RAW + OFFSET) * SCALE.
130d3532d69SRamona Bolboaca 		 * Hence using some rearranging we get the scale as -110.497238
131d3532d69SRamona Bolboaca 		 * and offset as -2079.25.
132d3532d69SRamona Bolboaca 		 */
133d3532d69SRamona Bolboaca 		.temp_offset = {
134d3532d69SRamona Bolboaca 			.integer = -2079,
135d3532d69SRamona Bolboaca 			.decimal = 250000,
136d3532d69SRamona Bolboaca 		},
137d3532d69SRamona Bolboaca 	},
138d3532d69SRamona Bolboaca };
139cdd30ebbSPeter Zijlstra EXPORT_SYMBOL_NS_GPL(adxl35x_chip_info, "IIO_ADXL355");
140d3532d69SRamona Bolboaca 
14112ed2786SPuranjay Mohan enum adxl355_op_mode {
14212ed2786SPuranjay Mohan 	ADXL355_MEASUREMENT,
14312ed2786SPuranjay Mohan 	ADXL355_STANDBY,
14412ed2786SPuranjay Mohan 	ADXL355_TEMP_OFF,
14512ed2786SPuranjay Mohan };
14612ed2786SPuranjay Mohan 
14712ed2786SPuranjay Mohan enum adxl355_odr {
14812ed2786SPuranjay Mohan 	ADXL355_ODR_4000HZ,
14912ed2786SPuranjay Mohan 	ADXL355_ODR_2000HZ,
15012ed2786SPuranjay Mohan 	ADXL355_ODR_1000HZ,
15112ed2786SPuranjay Mohan 	ADXL355_ODR_500HZ,
15212ed2786SPuranjay Mohan 	ADXL355_ODR_250HZ,
15312ed2786SPuranjay Mohan 	ADXL355_ODR_125HZ,
15412ed2786SPuranjay Mohan 	ADXL355_ODR_62_5HZ,
15512ed2786SPuranjay Mohan 	ADXL355_ODR_31_25HZ,
15612ed2786SPuranjay Mohan 	ADXL355_ODR_15_625HZ,
15712ed2786SPuranjay Mohan 	ADXL355_ODR_7_813HZ,
15812ed2786SPuranjay Mohan 	ADXL355_ODR_3_906HZ,
15912ed2786SPuranjay Mohan };
16012ed2786SPuranjay Mohan 
16112ed2786SPuranjay Mohan enum adxl355_hpf_3db {
16212ed2786SPuranjay Mohan 	ADXL355_HPF_OFF,
16312ed2786SPuranjay Mohan 	ADXL355_HPF_24_7,
16412ed2786SPuranjay Mohan 	ADXL355_HPF_6_2084,
16512ed2786SPuranjay Mohan 	ADXL355_HPF_1_5545,
16612ed2786SPuranjay Mohan 	ADXL355_HPF_0_3862,
16712ed2786SPuranjay Mohan 	ADXL355_HPF_0_0954,
16812ed2786SPuranjay Mohan 	ADXL355_HPF_0_0238,
16912ed2786SPuranjay Mohan };
17012ed2786SPuranjay Mohan 
17112ed2786SPuranjay Mohan static const int adxl355_odr_table[][2] = {
17212ed2786SPuranjay Mohan 	[0] = {4000, 0},
17312ed2786SPuranjay Mohan 	[1] = {2000, 0},
17412ed2786SPuranjay Mohan 	[2] = {1000, 0},
17512ed2786SPuranjay Mohan 	[3] = {500, 0},
17612ed2786SPuranjay Mohan 	[4] = {250, 0},
17712ed2786SPuranjay Mohan 	[5] = {125, 0},
17812ed2786SPuranjay Mohan 	[6] = {62, 500000},
17912ed2786SPuranjay Mohan 	[7] = {31, 250000},
18012ed2786SPuranjay Mohan 	[8] = {15, 625000},
18112ed2786SPuranjay Mohan 	[9] = {7, 813000},
18212ed2786SPuranjay Mohan 	[10] = {3, 906000},
18312ed2786SPuranjay Mohan };
18412ed2786SPuranjay Mohan 
18512ed2786SPuranjay Mohan static const int adxl355_hpf_3db_multipliers[] = {
18612ed2786SPuranjay Mohan 	0,
18712ed2786SPuranjay Mohan 	247000,
18812ed2786SPuranjay Mohan 	62084,
18912ed2786SPuranjay Mohan 	15545,
19012ed2786SPuranjay Mohan 	3862,
19112ed2786SPuranjay Mohan 	954,
19212ed2786SPuranjay Mohan 	238,
19312ed2786SPuranjay Mohan };
19412ed2786SPuranjay Mohan 
19512ed2786SPuranjay Mohan enum adxl355_chans {
19612ed2786SPuranjay Mohan 	chan_x, chan_y, chan_z,
19712ed2786SPuranjay Mohan };
19812ed2786SPuranjay Mohan 
19912ed2786SPuranjay Mohan struct adxl355_chan_info {
20012ed2786SPuranjay Mohan 	u8 data_reg;
20112ed2786SPuranjay Mohan 	u8 offset_reg;
20212ed2786SPuranjay Mohan };
20312ed2786SPuranjay Mohan 
20412ed2786SPuranjay Mohan static const struct adxl355_chan_info adxl355_chans[] = {
20512ed2786SPuranjay Mohan 	[chan_x] = {
20612ed2786SPuranjay Mohan 		.data_reg = ADXL355_XDATA3_REG,
20712ed2786SPuranjay Mohan 		.offset_reg = ADXL355_OFFSET_X_H_REG
20812ed2786SPuranjay Mohan 	},
20912ed2786SPuranjay Mohan 	[chan_y] = {
21012ed2786SPuranjay Mohan 		.data_reg = ADXL355_YDATA3_REG,
21112ed2786SPuranjay Mohan 		.offset_reg = ADXL355_OFFSET_Y_H_REG
21212ed2786SPuranjay Mohan 	},
21312ed2786SPuranjay Mohan 	[chan_z] = {
21412ed2786SPuranjay Mohan 		.data_reg = ADXL355_ZDATA3_REG,
21512ed2786SPuranjay Mohan 		.offset_reg = ADXL355_OFFSET_Z_H_REG
21612ed2786SPuranjay Mohan 	},
21712ed2786SPuranjay Mohan };
21812ed2786SPuranjay Mohan 
21912ed2786SPuranjay Mohan struct adxl355_data {
220d3532d69SRamona Bolboaca 	const struct adxl355_chip_info *chip_info;
22112ed2786SPuranjay Mohan 	struct regmap *regmap;
22212ed2786SPuranjay Mohan 	struct device *dev;
22312ed2786SPuranjay Mohan 	struct mutex lock; /* lock to protect op_mode */
22412ed2786SPuranjay Mohan 	enum adxl355_op_mode op_mode;
22512ed2786SPuranjay Mohan 	enum adxl355_odr odr;
22612ed2786SPuranjay Mohan 	enum adxl355_hpf_3db hpf_3db;
22712ed2786SPuranjay Mohan 	int calibbias[3];
22812ed2786SPuranjay Mohan 	int adxl355_hpf_3db_table[7][2];
229327a0eafSPuranjay Mohan 	struct iio_trigger *dready_trig;
230327a0eafSPuranjay Mohan 	union {
231327a0eafSPuranjay Mohan 		u8 transf_buf[3];
232327a0eafSPuranjay Mohan 		struct {
233327a0eafSPuranjay Mohan 			u8 buf[14];
2341bb94228SJonathan Cameron 			aligned_s64 ts;
235327a0eafSPuranjay Mohan 		} buffer;
23646403dcfSJonathan Cameron 	} __aligned(IIO_DMA_MINALIGN);
23712ed2786SPuranjay Mohan };
23812ed2786SPuranjay Mohan 
adxl355_set_op_mode(struct adxl355_data * data,enum adxl355_op_mode op_mode)23912ed2786SPuranjay Mohan static int adxl355_set_op_mode(struct adxl355_data *data,
24012ed2786SPuranjay Mohan 			       enum adxl355_op_mode op_mode)
24112ed2786SPuranjay Mohan {
24212ed2786SPuranjay Mohan 	int ret;
24312ed2786SPuranjay Mohan 
24412ed2786SPuranjay Mohan 	if (data->op_mode == op_mode)
24512ed2786SPuranjay Mohan 		return 0;
24612ed2786SPuranjay Mohan 
24712ed2786SPuranjay Mohan 	ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG,
24812ed2786SPuranjay Mohan 				 ADXL355_POWER_CTL_MODE_MSK, op_mode);
24912ed2786SPuranjay Mohan 	if (ret)
25012ed2786SPuranjay Mohan 		return ret;
25112ed2786SPuranjay Mohan 
25212ed2786SPuranjay Mohan 	data->op_mode = op_mode;
25312ed2786SPuranjay Mohan 
25412ed2786SPuranjay Mohan 	return ret;
25512ed2786SPuranjay Mohan }
25612ed2786SPuranjay Mohan 
adxl355_data_rdy_trigger_set_state(struct iio_trigger * trig,bool state)257327a0eafSPuranjay Mohan static int adxl355_data_rdy_trigger_set_state(struct iio_trigger *trig,
258327a0eafSPuranjay Mohan 					      bool state)
259327a0eafSPuranjay Mohan {
260327a0eafSPuranjay Mohan 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
261327a0eafSPuranjay Mohan 	struct adxl355_data *data = iio_priv(indio_dev);
262327a0eafSPuranjay Mohan 	int ret;
263327a0eafSPuranjay Mohan 
264327a0eafSPuranjay Mohan 	mutex_lock(&data->lock);
265327a0eafSPuranjay Mohan 	ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG,
266327a0eafSPuranjay Mohan 				 ADXL355_POWER_CTL_DRDY_MSK,
267327a0eafSPuranjay Mohan 				 FIELD_PREP(ADXL355_POWER_CTL_DRDY_MSK,
268327a0eafSPuranjay Mohan 					    state ? 0 : 1));
269327a0eafSPuranjay Mohan 	mutex_unlock(&data->lock);
270327a0eafSPuranjay Mohan 
271327a0eafSPuranjay Mohan 	return ret;
272327a0eafSPuranjay Mohan }
273327a0eafSPuranjay Mohan 
adxl355_fill_3db_frequency_table(struct adxl355_data * data)27412ed2786SPuranjay Mohan static void adxl355_fill_3db_frequency_table(struct adxl355_data *data)
27512ed2786SPuranjay Mohan {
27612ed2786SPuranjay Mohan 	u32 multiplier;
27712ed2786SPuranjay Mohan 	u64 div, rem;
27812ed2786SPuranjay Mohan 	u64 odr;
27912ed2786SPuranjay Mohan 	int i;
28012ed2786SPuranjay Mohan 
28112ed2786SPuranjay Mohan 	odr = mul_u64_u32_shr(adxl355_odr_table[data->odr][0], MEGA, 0) +
28212ed2786SPuranjay Mohan 			      adxl355_odr_table[data->odr][1];
28312ed2786SPuranjay Mohan 
28412ed2786SPuranjay Mohan 	for (i = 0; i < ARRAY_SIZE(adxl355_hpf_3db_multipliers); i++) {
28512ed2786SPuranjay Mohan 		multiplier = adxl355_hpf_3db_multipliers[i];
28612ed2786SPuranjay Mohan 		div = div64_u64_rem(mul_u64_u32_shr(odr, multiplier, 0),
28712ed2786SPuranjay Mohan 				    TERA * 100, &rem);
28812ed2786SPuranjay Mohan 
28912ed2786SPuranjay Mohan 		data->adxl355_hpf_3db_table[i][0] = div;
29012ed2786SPuranjay Mohan 		data->adxl355_hpf_3db_table[i][1] = div_u64(rem, MEGA * 100);
29112ed2786SPuranjay Mohan 	}
29212ed2786SPuranjay Mohan }
29312ed2786SPuranjay Mohan 
adxl355_setup(struct adxl355_data * data)29412ed2786SPuranjay Mohan static int adxl355_setup(struct adxl355_data *data)
29512ed2786SPuranjay Mohan {
29612ed2786SPuranjay Mohan 	unsigned int regval;
29712ed2786SPuranjay Mohan 	int ret;
29812ed2786SPuranjay Mohan 
29912ed2786SPuranjay Mohan 	ret = regmap_read(data->regmap, ADXL355_DEVID_AD_REG, &regval);
30012ed2786SPuranjay Mohan 	if (ret)
30112ed2786SPuranjay Mohan 		return ret;
30212ed2786SPuranjay Mohan 
30312ed2786SPuranjay Mohan 	if (regval != ADXL355_DEVID_AD_VAL) {
30412ed2786SPuranjay Mohan 		dev_err(data->dev, "Invalid ADI ID 0x%02x\n", regval);
30512ed2786SPuranjay Mohan 		return -ENODEV;
30612ed2786SPuranjay Mohan 	}
30712ed2786SPuranjay Mohan 
30812ed2786SPuranjay Mohan 	ret = regmap_read(data->regmap, ADXL355_DEVID_MST_REG, &regval);
30912ed2786SPuranjay Mohan 	if (ret)
31012ed2786SPuranjay Mohan 		return ret;
31112ed2786SPuranjay Mohan 
31212ed2786SPuranjay Mohan 	if (regval != ADXL355_DEVID_MST_VAL) {
31312ed2786SPuranjay Mohan 		dev_err(data->dev, "Invalid MEMS ID 0x%02x\n", regval);
31412ed2786SPuranjay Mohan 		return -ENODEV;
31512ed2786SPuranjay Mohan 	}
31612ed2786SPuranjay Mohan 
31712ed2786SPuranjay Mohan 	ret = regmap_read(data->regmap, ADXL355_PARTID_REG, &regval);
31812ed2786SPuranjay Mohan 	if (ret)
31912ed2786SPuranjay Mohan 		return ret;
32012ed2786SPuranjay Mohan 
32175347e30SRamona Bolboaca 	if (regval != ADXL355_PARTID_VAL)
32275347e30SRamona Bolboaca 		dev_warn(data->dev, "Invalid DEV ID 0x%02x\n", regval);
32312ed2786SPuranjay Mohan 
32412ed2786SPuranjay Mohan 	/*
32512ed2786SPuranjay Mohan 	 * Perform a software reset to make sure the device is in a consistent
32612ed2786SPuranjay Mohan 	 * state after start-up.
32712ed2786SPuranjay Mohan 	 */
32812ed2786SPuranjay Mohan 	ret = regmap_write(data->regmap, ADXL355_RESET_REG, ADXL355_RESET_CODE);
32912ed2786SPuranjay Mohan 	if (ret)
33012ed2786SPuranjay Mohan 		return ret;
33112ed2786SPuranjay Mohan 
332327a0eafSPuranjay Mohan 	ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG,
333327a0eafSPuranjay Mohan 				 ADXL355_POWER_CTL_DRDY_MSK,
334327a0eafSPuranjay Mohan 				 FIELD_PREP(ADXL355_POWER_CTL_DRDY_MSK, 1));
335327a0eafSPuranjay Mohan 	if (ret)
336327a0eafSPuranjay Mohan 		return ret;
337327a0eafSPuranjay Mohan 
33812ed2786SPuranjay Mohan 	adxl355_fill_3db_frequency_table(data);
33912ed2786SPuranjay Mohan 
34012ed2786SPuranjay Mohan 	return adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
34112ed2786SPuranjay Mohan }
34212ed2786SPuranjay Mohan 
adxl355_get_temp_data(struct adxl355_data * data,u8 addr)34312ed2786SPuranjay Mohan static int adxl355_get_temp_data(struct adxl355_data *data, u8 addr)
34412ed2786SPuranjay Mohan {
34512ed2786SPuranjay Mohan 	return regmap_bulk_read(data->regmap, addr, data->transf_buf, 2);
34612ed2786SPuranjay Mohan }
34712ed2786SPuranjay Mohan 
adxl355_read_axis(struct adxl355_data * data,u8 addr)34812ed2786SPuranjay Mohan static int adxl355_read_axis(struct adxl355_data *data, u8 addr)
34912ed2786SPuranjay Mohan {
35012ed2786SPuranjay Mohan 	int ret;
35112ed2786SPuranjay Mohan 
35212ed2786SPuranjay Mohan 	ret = regmap_bulk_read(data->regmap, addr, data->transf_buf,
35312ed2786SPuranjay Mohan 			       ARRAY_SIZE(data->transf_buf));
35486ff6cb1SPuranjay Mohan 	if (ret)
35512ed2786SPuranjay Mohan 		return ret;
35612ed2786SPuranjay Mohan 
35712ed2786SPuranjay Mohan 	return get_unaligned_be24(data->transf_buf);
35812ed2786SPuranjay Mohan }
35912ed2786SPuranjay Mohan 
adxl355_find_match(const int (* freq_tbl)[2],const int n,const int val,const int val2)36012ed2786SPuranjay Mohan static int adxl355_find_match(const int (*freq_tbl)[2], const int n,
36112ed2786SPuranjay Mohan 			      const int val, const int val2)
36212ed2786SPuranjay Mohan {
36312ed2786SPuranjay Mohan 	int i;
36412ed2786SPuranjay Mohan 
36512ed2786SPuranjay Mohan 	for (i = 0; i < n; i++) {
36612ed2786SPuranjay Mohan 		if (freq_tbl[i][0] == val && freq_tbl[i][1] == val2)
36712ed2786SPuranjay Mohan 			return i;
36812ed2786SPuranjay Mohan 	}
36912ed2786SPuranjay Mohan 
37012ed2786SPuranjay Mohan 	return -EINVAL;
37112ed2786SPuranjay Mohan }
37212ed2786SPuranjay Mohan 
adxl355_set_odr(struct adxl355_data * data,enum adxl355_odr odr)37312ed2786SPuranjay Mohan static int adxl355_set_odr(struct adxl355_data *data,
37412ed2786SPuranjay Mohan 			   enum adxl355_odr odr)
37512ed2786SPuranjay Mohan {
37612ed2786SPuranjay Mohan 	int ret;
37712ed2786SPuranjay Mohan 
37812ed2786SPuranjay Mohan 	mutex_lock(&data->lock);
37912ed2786SPuranjay Mohan 
38012ed2786SPuranjay Mohan 	if (data->odr == odr) {
38112ed2786SPuranjay Mohan 		mutex_unlock(&data->lock);
38212ed2786SPuranjay Mohan 		return 0;
38312ed2786SPuranjay Mohan 	}
38412ed2786SPuranjay Mohan 
38512ed2786SPuranjay Mohan 	ret = adxl355_set_op_mode(data, ADXL355_STANDBY);
38686ff6cb1SPuranjay Mohan 	if (ret)
38712ed2786SPuranjay Mohan 		goto err_unlock;
38812ed2786SPuranjay Mohan 
38912ed2786SPuranjay Mohan 	ret = regmap_update_bits(data->regmap, ADXL355_FILTER_REG,
39012ed2786SPuranjay Mohan 				 ADXL355_FILTER_ODR_MSK,
39112ed2786SPuranjay Mohan 				 FIELD_PREP(ADXL355_FILTER_ODR_MSK, odr));
39286ff6cb1SPuranjay Mohan 	if (ret)
39312ed2786SPuranjay Mohan 		goto err_set_opmode;
39412ed2786SPuranjay Mohan 
39512ed2786SPuranjay Mohan 	data->odr = odr;
39612ed2786SPuranjay Mohan 	adxl355_fill_3db_frequency_table(data);
39712ed2786SPuranjay Mohan 
39812ed2786SPuranjay Mohan 	ret = adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
39912ed2786SPuranjay Mohan 	if (ret)
40012ed2786SPuranjay Mohan 		goto err_set_opmode;
40112ed2786SPuranjay Mohan 
40212ed2786SPuranjay Mohan 	mutex_unlock(&data->lock);
40312ed2786SPuranjay Mohan 	return 0;
40412ed2786SPuranjay Mohan 
40512ed2786SPuranjay Mohan err_set_opmode:
40612ed2786SPuranjay Mohan 	adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
40712ed2786SPuranjay Mohan err_unlock:
40812ed2786SPuranjay Mohan 	mutex_unlock(&data->lock);
40912ed2786SPuranjay Mohan 	return ret;
41012ed2786SPuranjay Mohan }
41112ed2786SPuranjay Mohan 
adxl355_set_hpf_3db(struct adxl355_data * data,enum adxl355_hpf_3db hpf)41212ed2786SPuranjay Mohan static int adxl355_set_hpf_3db(struct adxl355_data *data,
41312ed2786SPuranjay Mohan 			       enum adxl355_hpf_3db hpf)
41412ed2786SPuranjay Mohan {
41512ed2786SPuranjay Mohan 	int ret;
41612ed2786SPuranjay Mohan 
41712ed2786SPuranjay Mohan 	mutex_lock(&data->lock);
41812ed2786SPuranjay Mohan 
41912ed2786SPuranjay Mohan 	if (data->hpf_3db == hpf) {
42012ed2786SPuranjay Mohan 		mutex_unlock(&data->lock);
42112ed2786SPuranjay Mohan 		return 0;
42212ed2786SPuranjay Mohan 	}
42312ed2786SPuranjay Mohan 
42412ed2786SPuranjay Mohan 	ret = adxl355_set_op_mode(data, ADXL355_STANDBY);
42586ff6cb1SPuranjay Mohan 	if (ret)
42612ed2786SPuranjay Mohan 		goto err_unlock;
42712ed2786SPuranjay Mohan 
42812ed2786SPuranjay Mohan 	ret = regmap_update_bits(data->regmap, ADXL355_FILTER_REG,
42912ed2786SPuranjay Mohan 				 ADXL355_FILTER_HPF_MSK,
43012ed2786SPuranjay Mohan 				 FIELD_PREP(ADXL355_FILTER_HPF_MSK, hpf));
43112ed2786SPuranjay Mohan 	if (ret)
43212ed2786SPuranjay Mohan 		goto err_set_opmode;
43312ed2786SPuranjay Mohan 
43412ed2786SPuranjay Mohan 	data->hpf_3db = hpf;
43512ed2786SPuranjay Mohan 
43612ed2786SPuranjay Mohan 	ret = adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
43712ed2786SPuranjay Mohan 	if (ret)
43812ed2786SPuranjay Mohan 		goto err_set_opmode;
43912ed2786SPuranjay Mohan 
44012ed2786SPuranjay Mohan 	mutex_unlock(&data->lock);
44112ed2786SPuranjay Mohan 	return 0;
44212ed2786SPuranjay Mohan 
44312ed2786SPuranjay Mohan err_set_opmode:
44412ed2786SPuranjay Mohan 	adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
44512ed2786SPuranjay Mohan err_unlock:
44612ed2786SPuranjay Mohan 	mutex_unlock(&data->lock);
44712ed2786SPuranjay Mohan 	return ret;
44812ed2786SPuranjay Mohan }
44912ed2786SPuranjay Mohan 
adxl355_set_calibbias(struct adxl355_data * data,enum adxl355_chans chan,int calibbias)45012ed2786SPuranjay Mohan static int adxl355_set_calibbias(struct adxl355_data *data,
45112ed2786SPuranjay Mohan 				 enum adxl355_chans chan, int calibbias)
45212ed2786SPuranjay Mohan {
45312ed2786SPuranjay Mohan 	int ret;
45412ed2786SPuranjay Mohan 
45512ed2786SPuranjay Mohan 	mutex_lock(&data->lock);
45612ed2786SPuranjay Mohan 
45712ed2786SPuranjay Mohan 	ret = adxl355_set_op_mode(data, ADXL355_STANDBY);
45886ff6cb1SPuranjay Mohan 	if (ret)
45912ed2786SPuranjay Mohan 		goto err_unlock;
46012ed2786SPuranjay Mohan 
46112ed2786SPuranjay Mohan 	put_unaligned_be16(calibbias, data->transf_buf);
46212ed2786SPuranjay Mohan 	ret = regmap_bulk_write(data->regmap,
46312ed2786SPuranjay Mohan 				adxl355_chans[chan].offset_reg,
46412ed2786SPuranjay Mohan 				data->transf_buf, 2);
46512ed2786SPuranjay Mohan 	if (ret)
46612ed2786SPuranjay Mohan 		goto err_set_opmode;
46712ed2786SPuranjay Mohan 
46812ed2786SPuranjay Mohan 	data->calibbias[chan] = calibbias;
46912ed2786SPuranjay Mohan 
47012ed2786SPuranjay Mohan 	ret = adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
47112ed2786SPuranjay Mohan 	if (ret)
47212ed2786SPuranjay Mohan 		goto err_set_opmode;
47312ed2786SPuranjay Mohan 
47412ed2786SPuranjay Mohan 	mutex_unlock(&data->lock);
47512ed2786SPuranjay Mohan 	return 0;
47612ed2786SPuranjay Mohan 
47712ed2786SPuranjay Mohan err_set_opmode:
47812ed2786SPuranjay Mohan 	adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
47912ed2786SPuranjay Mohan err_unlock:
48012ed2786SPuranjay Mohan 	mutex_unlock(&data->lock);
48112ed2786SPuranjay Mohan 	return ret;
48212ed2786SPuranjay Mohan }
48312ed2786SPuranjay Mohan 
adxl355_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)48412ed2786SPuranjay Mohan static int adxl355_read_raw(struct iio_dev *indio_dev,
48512ed2786SPuranjay Mohan 			    struct iio_chan_spec const *chan,
48612ed2786SPuranjay Mohan 			    int *val, int *val2, long mask)
48712ed2786SPuranjay Mohan {
48812ed2786SPuranjay Mohan 	struct adxl355_data *data = iio_priv(indio_dev);
48912ed2786SPuranjay Mohan 	int ret;
49012ed2786SPuranjay Mohan 
49112ed2786SPuranjay Mohan 	switch (mask) {
49212ed2786SPuranjay Mohan 	case IIO_CHAN_INFO_RAW:
49312ed2786SPuranjay Mohan 		switch (chan->type) {
49412ed2786SPuranjay Mohan 		case IIO_TEMP:
49512ed2786SPuranjay Mohan 			ret = adxl355_get_temp_data(data, chan->address);
49612ed2786SPuranjay Mohan 			if (ret < 0)
49712ed2786SPuranjay Mohan 				return ret;
49812ed2786SPuranjay Mohan 			*val = get_unaligned_be16(data->transf_buf);
49912ed2786SPuranjay Mohan 
50012ed2786SPuranjay Mohan 			return IIO_VAL_INT;
50112ed2786SPuranjay Mohan 		case IIO_ACCEL:
50212ed2786SPuranjay Mohan 			ret = adxl355_read_axis(data, adxl355_chans[
50312ed2786SPuranjay Mohan 						chan->address].data_reg);
50412ed2786SPuranjay Mohan 			if (ret < 0)
50512ed2786SPuranjay Mohan 				return ret;
50612ed2786SPuranjay Mohan 			*val = sign_extend32(ret >> chan->scan_type.shift,
50712ed2786SPuranjay Mohan 					     chan->scan_type.realbits - 1);
50812ed2786SPuranjay Mohan 			return IIO_VAL_INT;
50912ed2786SPuranjay Mohan 		default:
51012ed2786SPuranjay Mohan 			return -EINVAL;
51112ed2786SPuranjay Mohan 		}
51212ed2786SPuranjay Mohan 
51312ed2786SPuranjay Mohan 	case IIO_CHAN_INFO_SCALE:
51412ed2786SPuranjay Mohan 		switch (chan->type) {
51512ed2786SPuranjay Mohan 		case IIO_TEMP:
516d3532d69SRamona Bolboaca 			/*
517d3532d69SRamona Bolboaca 			 * Temperature scale is -110.497238.
518d3532d69SRamona Bolboaca 			 * See the detailed explanation in adxl35x_chip_info
519d3532d69SRamona Bolboaca 			 * definition above.
520d3532d69SRamona Bolboaca 			 */
52112ed2786SPuranjay Mohan 			*val = -110;
52212ed2786SPuranjay Mohan 			*val2 = 497238;
52312ed2786SPuranjay Mohan 			return IIO_VAL_INT_PLUS_MICRO;
52412ed2786SPuranjay Mohan 		case IIO_ACCEL:
525d3532d69SRamona Bolboaca 			*val = data->chip_info->accel_scale.integer;
526d3532d69SRamona Bolboaca 			*val2 = data->chip_info->accel_scale.decimal;
52712ed2786SPuranjay Mohan 			return IIO_VAL_INT_PLUS_NANO;
52812ed2786SPuranjay Mohan 		default:
52912ed2786SPuranjay Mohan 			return -EINVAL;
53012ed2786SPuranjay Mohan 		}
53112ed2786SPuranjay Mohan 	case IIO_CHAN_INFO_OFFSET:
532d3532d69SRamona Bolboaca 		*val = data->chip_info->temp_offset.integer;
533d3532d69SRamona Bolboaca 		*val2 = data->chip_info->temp_offset.decimal;
53412ed2786SPuranjay Mohan 		return IIO_VAL_INT_PLUS_MICRO;
53512ed2786SPuranjay Mohan 	case IIO_CHAN_INFO_CALIBBIAS:
53612ed2786SPuranjay Mohan 		*val = sign_extend32(data->calibbias[chan->address], 15);
53712ed2786SPuranjay Mohan 		return IIO_VAL_INT;
53812ed2786SPuranjay Mohan 	case IIO_CHAN_INFO_SAMP_FREQ:
53912ed2786SPuranjay Mohan 		*val = adxl355_odr_table[data->odr][0];
54012ed2786SPuranjay Mohan 		*val2 = adxl355_odr_table[data->odr][1];
54112ed2786SPuranjay Mohan 		return IIO_VAL_INT_PLUS_MICRO;
54212ed2786SPuranjay Mohan 	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
54312ed2786SPuranjay Mohan 		*val = data->adxl355_hpf_3db_table[data->hpf_3db][0];
54412ed2786SPuranjay Mohan 		*val2 = data->adxl355_hpf_3db_table[data->hpf_3db][1];
54512ed2786SPuranjay Mohan 		return IIO_VAL_INT_PLUS_MICRO;
54612ed2786SPuranjay Mohan 	default:
54712ed2786SPuranjay Mohan 		return -EINVAL;
54812ed2786SPuranjay Mohan 	}
54912ed2786SPuranjay Mohan }
55012ed2786SPuranjay Mohan 
adxl355_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)55112ed2786SPuranjay Mohan static int adxl355_write_raw(struct iio_dev *indio_dev,
55212ed2786SPuranjay Mohan 			     struct iio_chan_spec const *chan,
55312ed2786SPuranjay Mohan 			     int val, int val2, long mask)
55412ed2786SPuranjay Mohan {
55512ed2786SPuranjay Mohan 	struct adxl355_data *data = iio_priv(indio_dev);
55612ed2786SPuranjay Mohan 	int odr_idx, hpf_idx, calibbias;
55712ed2786SPuranjay Mohan 
55812ed2786SPuranjay Mohan 	switch (mask) {
55912ed2786SPuranjay Mohan 	case IIO_CHAN_INFO_SAMP_FREQ:
56012ed2786SPuranjay Mohan 		odr_idx = adxl355_find_match(adxl355_odr_table,
56112ed2786SPuranjay Mohan 					     ARRAY_SIZE(adxl355_odr_table),
56212ed2786SPuranjay Mohan 					     val, val2);
56312ed2786SPuranjay Mohan 		if (odr_idx < 0)
56412ed2786SPuranjay Mohan 			return odr_idx;
56512ed2786SPuranjay Mohan 
56612ed2786SPuranjay Mohan 		return adxl355_set_odr(data, odr_idx);
56712ed2786SPuranjay Mohan 	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
56812ed2786SPuranjay Mohan 		hpf_idx = adxl355_find_match(data->adxl355_hpf_3db_table,
56912ed2786SPuranjay Mohan 					ARRAY_SIZE(data->adxl355_hpf_3db_table),
57012ed2786SPuranjay Mohan 					     val, val2);
57112ed2786SPuranjay Mohan 		if (hpf_idx < 0)
57212ed2786SPuranjay Mohan 			return hpf_idx;
57312ed2786SPuranjay Mohan 
57412ed2786SPuranjay Mohan 		return adxl355_set_hpf_3db(data, hpf_idx);
57512ed2786SPuranjay Mohan 	case IIO_CHAN_INFO_CALIBBIAS:
57612ed2786SPuranjay Mohan 		calibbias = clamp_t(int, val, S16_MIN, S16_MAX);
57712ed2786SPuranjay Mohan 
57812ed2786SPuranjay Mohan 		return adxl355_set_calibbias(data, chan->address, calibbias);
57912ed2786SPuranjay Mohan 	default:
58012ed2786SPuranjay Mohan 		return -EINVAL;
58112ed2786SPuranjay Mohan 	}
58212ed2786SPuranjay Mohan }
58312ed2786SPuranjay Mohan 
adxl355_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)58412ed2786SPuranjay Mohan static int adxl355_read_avail(struct iio_dev *indio_dev,
58512ed2786SPuranjay Mohan 			      struct iio_chan_spec const *chan,
58612ed2786SPuranjay Mohan 			      const int **vals, int *type, int *length,
58712ed2786SPuranjay Mohan 			      long mask)
58812ed2786SPuranjay Mohan {
58912ed2786SPuranjay Mohan 	struct adxl355_data *data = iio_priv(indio_dev);
59012ed2786SPuranjay Mohan 
59112ed2786SPuranjay Mohan 	switch (mask) {
59212ed2786SPuranjay Mohan 	case IIO_CHAN_INFO_SAMP_FREQ:
59312ed2786SPuranjay Mohan 		*vals = (const int *)adxl355_odr_table;
59412ed2786SPuranjay Mohan 		*type = IIO_VAL_INT_PLUS_MICRO;
59512ed2786SPuranjay Mohan 		/* Values are stored in a 2D matrix */
59612ed2786SPuranjay Mohan 		*length = ARRAY_SIZE(adxl355_odr_table) * 2;
59712ed2786SPuranjay Mohan 
59812ed2786SPuranjay Mohan 		return IIO_AVAIL_LIST;
59912ed2786SPuranjay Mohan 	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
60012ed2786SPuranjay Mohan 		*vals = (const int *)data->adxl355_hpf_3db_table;
60112ed2786SPuranjay Mohan 		*type = IIO_VAL_INT_PLUS_MICRO;
60212ed2786SPuranjay Mohan 		/* Values are stored in a 2D matrix */
60312ed2786SPuranjay Mohan 		*length = ARRAY_SIZE(data->adxl355_hpf_3db_table) * 2;
60412ed2786SPuranjay Mohan 
60512ed2786SPuranjay Mohan 		return IIO_AVAIL_LIST;
60612ed2786SPuranjay Mohan 	default:
60712ed2786SPuranjay Mohan 		return -EINVAL;
60812ed2786SPuranjay Mohan 	}
60912ed2786SPuranjay Mohan }
61012ed2786SPuranjay Mohan 
611327a0eafSPuranjay Mohan static const unsigned long adxl355_avail_scan_masks[] = {
612327a0eafSPuranjay Mohan 	GENMASK(3, 0),
613327a0eafSPuranjay Mohan 	0
614327a0eafSPuranjay Mohan };
615327a0eafSPuranjay Mohan 
61612ed2786SPuranjay Mohan static const struct iio_info adxl355_info = {
61712ed2786SPuranjay Mohan 	.read_raw	= adxl355_read_raw,
61812ed2786SPuranjay Mohan 	.write_raw	= adxl355_write_raw,
61912ed2786SPuranjay Mohan 	.read_avail	= &adxl355_read_avail,
62012ed2786SPuranjay Mohan };
62112ed2786SPuranjay Mohan 
622327a0eafSPuranjay Mohan static const struct iio_trigger_ops adxl355_trigger_ops = {
623327a0eafSPuranjay Mohan 	.set_trigger_state = &adxl355_data_rdy_trigger_set_state,
624327a0eafSPuranjay Mohan 	.validate_device = &iio_trigger_validate_own_device,
625327a0eafSPuranjay Mohan };
626327a0eafSPuranjay Mohan 
adxl355_trigger_handler(int irq,void * p)627327a0eafSPuranjay Mohan static irqreturn_t adxl355_trigger_handler(int irq, void *p)
628327a0eafSPuranjay Mohan {
629327a0eafSPuranjay Mohan 	struct iio_poll_func *pf = p;
630327a0eafSPuranjay Mohan 	struct iio_dev *indio_dev = pf->indio_dev;
631327a0eafSPuranjay Mohan 	struct adxl355_data *data = iio_priv(indio_dev);
632327a0eafSPuranjay Mohan 	int ret;
633327a0eafSPuranjay Mohan 
634327a0eafSPuranjay Mohan 	mutex_lock(&data->lock);
635327a0eafSPuranjay Mohan 
636327a0eafSPuranjay Mohan 	/*
637327a0eafSPuranjay Mohan 	 * data->buffer is used both for triggered buffer support
638327a0eafSPuranjay Mohan 	 * and read/write_raw(), hence, it has to be zeroed here before usage.
639327a0eafSPuranjay Mohan 	 */
640327a0eafSPuranjay Mohan 	data->buffer.buf[0] = 0;
641327a0eafSPuranjay Mohan 
642327a0eafSPuranjay Mohan 	/*
643327a0eafSPuranjay Mohan 	 * The acceleration data is 24 bits and big endian. It has to be saved
644327a0eafSPuranjay Mohan 	 * in 32 bits, hence, it is saved in the 2nd byte of the 4 byte buffer.
645327a0eafSPuranjay Mohan 	 * The buf array is 14 bytes as it includes 3x4=12 bytes for
646640e9838SWangYuli 	 * acceleration data of x, y, and z axis. It also includes 2 bytes for
647327a0eafSPuranjay Mohan 	 * temperature data.
648327a0eafSPuranjay Mohan 	 */
649327a0eafSPuranjay Mohan 	ret = regmap_bulk_read(data->regmap, ADXL355_XDATA3_REG,
650327a0eafSPuranjay Mohan 			       &data->buffer.buf[1], 3);
651327a0eafSPuranjay Mohan 	if (ret)
652327a0eafSPuranjay Mohan 		goto out_unlock_notify;
653327a0eafSPuranjay Mohan 
654327a0eafSPuranjay Mohan 	ret = regmap_bulk_read(data->regmap, ADXL355_YDATA3_REG,
655327a0eafSPuranjay Mohan 			       &data->buffer.buf[5], 3);
656327a0eafSPuranjay Mohan 	if (ret)
657327a0eafSPuranjay Mohan 		goto out_unlock_notify;
658327a0eafSPuranjay Mohan 
659327a0eafSPuranjay Mohan 	ret = regmap_bulk_read(data->regmap, ADXL355_ZDATA3_REG,
660327a0eafSPuranjay Mohan 			       &data->buffer.buf[9], 3);
661327a0eafSPuranjay Mohan 	if (ret)
662327a0eafSPuranjay Mohan 		goto out_unlock_notify;
663327a0eafSPuranjay Mohan 
664327a0eafSPuranjay Mohan 	ret = regmap_bulk_read(data->regmap, ADXL355_TEMP2_REG,
665327a0eafSPuranjay Mohan 			       &data->buffer.buf[12], 2);
666327a0eafSPuranjay Mohan 	if (ret)
667327a0eafSPuranjay Mohan 		goto out_unlock_notify;
668327a0eafSPuranjay Mohan 
669*edfafbd8SJonathan Cameron 	iio_push_to_buffers_with_ts(indio_dev, &data->buffer,
670*edfafbd8SJonathan Cameron 				    sizeof(data->buffer), pf->timestamp);
671327a0eafSPuranjay Mohan 
672327a0eafSPuranjay Mohan out_unlock_notify:
673327a0eafSPuranjay Mohan 	mutex_unlock(&data->lock);
674327a0eafSPuranjay Mohan 	iio_trigger_notify_done(indio_dev->trig);
675327a0eafSPuranjay Mohan 
676327a0eafSPuranjay Mohan 	return IRQ_HANDLED;
677327a0eafSPuranjay Mohan }
678327a0eafSPuranjay Mohan 
67912ed2786SPuranjay Mohan #define ADXL355_ACCEL_CHANNEL(index, reg, axis) {			\
68012ed2786SPuranjay Mohan 	.type = IIO_ACCEL,						\
68112ed2786SPuranjay Mohan 	.address = reg,							\
68212ed2786SPuranjay Mohan 	.modified = 1,							\
68312ed2786SPuranjay Mohan 	.channel2 = IIO_MOD_##axis,					\
68412ed2786SPuranjay Mohan 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
68512ed2786SPuranjay Mohan 			      BIT(IIO_CHAN_INFO_CALIBBIAS),		\
68612ed2786SPuranjay Mohan 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |		\
68712ed2786SPuranjay Mohan 				    BIT(IIO_CHAN_INFO_SAMP_FREQ) |	\
68812ed2786SPuranjay Mohan 		BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY),	\
68912ed2786SPuranjay Mohan 	.info_mask_shared_by_type_available =				\
69012ed2786SPuranjay Mohan 		BIT(IIO_CHAN_INFO_SAMP_FREQ) |				\
69112ed2786SPuranjay Mohan 		BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY),	\
692327a0eafSPuranjay Mohan 	.scan_index = index,						\
69312ed2786SPuranjay Mohan 	.scan_type = {							\
69412ed2786SPuranjay Mohan 		.sign = 's',						\
69512ed2786SPuranjay Mohan 		.realbits = 20,						\
69612ed2786SPuranjay Mohan 		.storagebits = 32,					\
69712ed2786SPuranjay Mohan 		.shift = 4,						\
69812ed2786SPuranjay Mohan 		.endianness = IIO_BE,					\
69912ed2786SPuranjay Mohan 	}								\
70012ed2786SPuranjay Mohan }
70112ed2786SPuranjay Mohan 
70212ed2786SPuranjay Mohan static const struct iio_chan_spec adxl355_channels[] = {
70312ed2786SPuranjay Mohan 	ADXL355_ACCEL_CHANNEL(0, chan_x, X),
70412ed2786SPuranjay Mohan 	ADXL355_ACCEL_CHANNEL(1, chan_y, Y),
70512ed2786SPuranjay Mohan 	ADXL355_ACCEL_CHANNEL(2, chan_z, Z),
70612ed2786SPuranjay Mohan 	{
70712ed2786SPuranjay Mohan 		.type = IIO_TEMP,
70812ed2786SPuranjay Mohan 		.address = ADXL355_TEMP2_REG,
70912ed2786SPuranjay Mohan 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
71012ed2786SPuranjay Mohan 				      BIT(IIO_CHAN_INFO_SCALE) |
71112ed2786SPuranjay Mohan 				      BIT(IIO_CHAN_INFO_OFFSET),
712327a0eafSPuranjay Mohan 		.scan_index = 3,
71312ed2786SPuranjay Mohan 		.scan_type = {
71412ed2786SPuranjay Mohan 			.sign = 's',
71512ed2786SPuranjay Mohan 			.realbits = 12,
71612ed2786SPuranjay Mohan 			.storagebits = 16,
71712ed2786SPuranjay Mohan 			.endianness = IIO_BE,
71812ed2786SPuranjay Mohan 		},
71912ed2786SPuranjay Mohan 	},
720327a0eafSPuranjay Mohan 	IIO_CHAN_SOFT_TIMESTAMP(4),
72112ed2786SPuranjay Mohan };
72212ed2786SPuranjay Mohan 
adxl355_probe_trigger(struct iio_dev * indio_dev,int irq)723327a0eafSPuranjay Mohan static int adxl355_probe_trigger(struct iio_dev *indio_dev, int irq)
724327a0eafSPuranjay Mohan {
725327a0eafSPuranjay Mohan 	struct adxl355_data *data = iio_priv(indio_dev);
726327a0eafSPuranjay Mohan 	int ret;
727327a0eafSPuranjay Mohan 
728327a0eafSPuranjay Mohan 	data->dready_trig = devm_iio_trigger_alloc(data->dev, "%s-dev%d",
729327a0eafSPuranjay Mohan 						   indio_dev->name,
730327a0eafSPuranjay Mohan 						   iio_device_id(indio_dev));
731327a0eafSPuranjay Mohan 	if (!data->dready_trig)
732327a0eafSPuranjay Mohan 		return -ENOMEM;
733327a0eafSPuranjay Mohan 
734327a0eafSPuranjay Mohan 	data->dready_trig->ops = &adxl355_trigger_ops;
735327a0eafSPuranjay Mohan 	iio_trigger_set_drvdata(data->dready_trig, indio_dev);
736327a0eafSPuranjay Mohan 
737327a0eafSPuranjay Mohan 	ret = devm_request_irq(data->dev, irq,
738327a0eafSPuranjay Mohan 			       &iio_trigger_generic_data_rdy_poll,
739327a0eafSPuranjay Mohan 			       IRQF_ONESHOT, "adxl355_irq", data->dready_trig);
740327a0eafSPuranjay Mohan 	if (ret)
741327a0eafSPuranjay Mohan 		return dev_err_probe(data->dev, ret, "request irq %d failed\n",
742327a0eafSPuranjay Mohan 				     irq);
743327a0eafSPuranjay Mohan 
744327a0eafSPuranjay Mohan 	ret = devm_iio_trigger_register(data->dev, data->dready_trig);
745327a0eafSPuranjay Mohan 	if (ret) {
746327a0eafSPuranjay Mohan 		dev_err(data->dev, "iio trigger register failed\n");
747327a0eafSPuranjay Mohan 		return ret;
748327a0eafSPuranjay Mohan 	}
749327a0eafSPuranjay Mohan 
750327a0eafSPuranjay Mohan 	indio_dev->trig = iio_trigger_get(data->dready_trig);
751327a0eafSPuranjay Mohan 
752327a0eafSPuranjay Mohan 	return 0;
753327a0eafSPuranjay Mohan }
754327a0eafSPuranjay Mohan 
adxl355_core_probe(struct device * dev,struct regmap * regmap,const struct adxl355_chip_info * chip_info)75512ed2786SPuranjay Mohan int adxl355_core_probe(struct device *dev, struct regmap *regmap,
756d3532d69SRamona Bolboaca 		       const struct adxl355_chip_info *chip_info)
75712ed2786SPuranjay Mohan {
75812ed2786SPuranjay Mohan 	struct adxl355_data *data;
75912ed2786SPuranjay Mohan 	struct iio_dev *indio_dev;
76012ed2786SPuranjay Mohan 	int ret;
761327a0eafSPuranjay Mohan 	int irq;
76212ed2786SPuranjay Mohan 
76312ed2786SPuranjay Mohan 	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
76412ed2786SPuranjay Mohan 	if (!indio_dev)
76512ed2786SPuranjay Mohan 		return -ENOMEM;
76612ed2786SPuranjay Mohan 
76712ed2786SPuranjay Mohan 	data = iio_priv(indio_dev);
76812ed2786SPuranjay Mohan 	data->regmap = regmap;
76912ed2786SPuranjay Mohan 	data->dev = dev;
77012ed2786SPuranjay Mohan 	data->op_mode = ADXL355_STANDBY;
771d3532d69SRamona Bolboaca 	data->chip_info = chip_info;
77212ed2786SPuranjay Mohan 	mutex_init(&data->lock);
77312ed2786SPuranjay Mohan 
774d3532d69SRamona Bolboaca 	indio_dev->name = chip_info->name;
77512ed2786SPuranjay Mohan 	indio_dev->info = &adxl355_info;
77612ed2786SPuranjay Mohan 	indio_dev->modes = INDIO_DIRECT_MODE;
77712ed2786SPuranjay Mohan 	indio_dev->channels = adxl355_channels;
77812ed2786SPuranjay Mohan 	indio_dev->num_channels = ARRAY_SIZE(adxl355_channels);
779327a0eafSPuranjay Mohan 	indio_dev->available_scan_masks = adxl355_avail_scan_masks;
78012ed2786SPuranjay Mohan 
78112ed2786SPuranjay Mohan 	ret = adxl355_setup(data);
78286ff6cb1SPuranjay Mohan 	if (ret) {
78312ed2786SPuranjay Mohan 		dev_err(dev, "ADXL355 setup failed\n");
78412ed2786SPuranjay Mohan 		return ret;
78512ed2786SPuranjay Mohan 	}
78612ed2786SPuranjay Mohan 
787327a0eafSPuranjay Mohan 	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
788327a0eafSPuranjay Mohan 					      &iio_pollfunc_store_time,
789327a0eafSPuranjay Mohan 					      &adxl355_trigger_handler, NULL);
790327a0eafSPuranjay Mohan 	if (ret) {
791327a0eafSPuranjay Mohan 		dev_err(dev, "iio triggered buffer setup failed\n");
792327a0eafSPuranjay Mohan 		return ret;
793327a0eafSPuranjay Mohan 	}
794327a0eafSPuranjay Mohan 
795d1100dd9SPuranjay Mohan 	irq = fwnode_irq_get_byname(dev_fwnode(dev), "DRDY");
796327a0eafSPuranjay Mohan 	if (irq > 0) {
797327a0eafSPuranjay Mohan 		ret = adxl355_probe_trigger(indio_dev, irq);
798327a0eafSPuranjay Mohan 		if (ret)
799327a0eafSPuranjay Mohan 			return ret;
800327a0eafSPuranjay Mohan 	}
801327a0eafSPuranjay Mohan 
80212ed2786SPuranjay Mohan 	return devm_iio_device_register(dev, indio_dev);
80312ed2786SPuranjay Mohan }
804cdd30ebbSPeter Zijlstra EXPORT_SYMBOL_NS_GPL(adxl355_core_probe, "IIO_ADXL355");
80512ed2786SPuranjay Mohan 
80612ed2786SPuranjay Mohan MODULE_AUTHOR("Puranjay Mohan <puranjay12@gmail.com>");
80712ed2786SPuranjay Mohan MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer core driver");
80812ed2786SPuranjay Mohan MODULE_LICENSE("GPL v2");
809