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, ®val);
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, ®val);
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, ®val);
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