root/drivers/iio/accel/adxl367.c
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2021 Analog Devices, Inc.
 * Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
 */

#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/sysfs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/unaligned.h>

#include "adxl367.h"

#define ADXL367_REG_DEVID               0x00
#define ADXL367_DEVID_AD                0xAD

#define ADXL367_REG_STATUS              0x0B
#define ADXL367_STATUS_INACT_MASK       BIT(5)
#define ADXL367_STATUS_ACT_MASK         BIT(4)
#define ADXL367_STATUS_FIFO_FULL_MASK   BIT(2)

#define ADXL367_FIFO_ENT_H_MASK         GENMASK(1, 0)

#define ADXL367_REG_X_DATA_H            0x0E
#define ADXL367_REG_Y_DATA_H            0x10
#define ADXL367_REG_Z_DATA_H            0x12
#define ADXL367_REG_TEMP_DATA_H         0x14
#define ADXL367_REG_EX_ADC_DATA_H       0x16
#define ADXL367_DATA_MASK               GENMASK(15, 2)

#define ADXL367_TEMP_25C                165
#define ADXL367_TEMP_PER_C              54

#define ADXL367_VOLTAGE_OFFSET          8192
#define ADXL367_VOLTAGE_MAX_MV          1000
#define ADXL367_VOLTAGE_MAX_RAW         GENMASK(13, 0)

#define ADXL367_REG_RESET               0x1F
#define ADXL367_RESET_CODE              0x52

#define ADXL367_REG_THRESH_ACT_H        0x20
#define ADXL367_REG_THRESH_INACT_H      0x23
#define ADXL367_THRESH_MAX              GENMASK(12, 0)
#define ADXL367_THRESH_VAL_H_MASK       GENMASK(12, 6)
#define ADXL367_THRESH_H_MASK           GENMASK(6, 0)
#define ADXL367_THRESH_VAL_L_MASK       GENMASK(5, 0)
#define ADXL367_THRESH_L_MASK           GENMASK(7, 2)

#define ADXL367_REG_TIME_ACT            0x22
#define ADXL367_REG_TIME_INACT_H        0x25
#define ADXL367_TIME_ACT_MAX            GENMASK(7, 0)
#define ADXL367_TIME_INACT_MAX          GENMASK(15, 0)
#define ADXL367_TIME_INACT_VAL_H_MASK   GENMASK(15, 8)
#define ADXL367_TIME_INACT_H_MASK       GENMASK(7, 0)
#define ADXL367_TIME_INACT_VAL_L_MASK   GENMASK(7, 0)
#define ADXL367_TIME_INACT_L_MASK       GENMASK(7, 0)

#define ADXL367_REG_ACT_INACT_CTL       0x27
#define ADXL367_ACT_EN_MASK             GENMASK(1, 0)
#define ADXL367_ACT_LINKLOOP_MASK       GENMASK(5, 4)

#define ADXL367_REG_FIFO_CTL            0x28
#define ADXL367_FIFO_CTL_FORMAT_MASK    GENMASK(6, 3)
#define ADXL367_FIFO_CTL_MODE_MASK      GENMASK(1, 0)

#define ADXL367_REG_FIFO_SAMPLES        0x29
#define ADXL367_FIFO_SIZE               512
#define ADXL367_FIFO_MAX_WATERMARK      511

#define ADXL367_SAMPLES_VAL_H_MASK      BIT(8)
#define ADXL367_SAMPLES_H_MASK          BIT(2)
#define ADXL367_SAMPLES_VAL_L_MASK      GENMASK(7, 0)
#define ADXL367_SAMPLES_L_MASK          GENMASK(7, 0)

#define ADXL367_REG_INT1_MAP            0x2A
#define ADXL367_INT_INACT_MASK          BIT(5)
#define ADXL367_INT_ACT_MASK            BIT(4)
#define ADXL367_INT_FIFO_WATERMARK_MASK BIT(2)

#define ADXL367_REG_FILTER_CTL          0x2C
#define ADXL367_FILTER_CTL_RANGE_MASK   GENMASK(7, 6)
#define ADXL367_2G_RANGE_1G             4095
#define ADXL367_2G_RANGE_100MG          409
#define ADXL367_FILTER_CTL_ODR_MASK     GENMASK(2, 0)

#define ADXL367_REG_POWER_CTL           0x2D
#define ADXL367_POWER_CTL_MODE_MASK     GENMASK(1, 0)

#define ADXL367_REG_ADC_CTL             0x3C
#define ADXL367_REG_TEMP_CTL            0x3D
#define ADXL367_ADC_EN_MASK             BIT(0)

enum adxl367_range {
        ADXL367_2G_RANGE,
        ADXL367_4G_RANGE,
        ADXL367_8G_RANGE,
};

enum adxl367_fifo_mode {
        ADXL367_FIFO_MODE_DISABLED = 0b00,
        ADXL367_FIFO_MODE_STREAM = 0b10,
};

enum adxl367_fifo_format {
        ADXL367_FIFO_FORMAT_XYZ,
        ADXL367_FIFO_FORMAT_X,
        ADXL367_FIFO_FORMAT_Y,
        ADXL367_FIFO_FORMAT_Z,
        ADXL367_FIFO_FORMAT_XYZT,
        ADXL367_FIFO_FORMAT_XT,
        ADXL367_FIFO_FORMAT_YT,
        ADXL367_FIFO_FORMAT_ZT,
        ADXL367_FIFO_FORMAT_XYZA,
        ADXL367_FIFO_FORMAT_XA,
        ADXL367_FIFO_FORMAT_YA,
        ADXL367_FIFO_FORMAT_ZA,
};

enum adxl367_op_mode {
        ADXL367_OP_STANDBY = 0b00,
        ADXL367_OP_MEASURE = 0b10,
};

enum adxl367_act_proc_mode {
        ADXL367_LOOPED = 0b11,
};

enum adxl367_act_en_mode {
        ADXL367_ACT_DISABLED = 0b00,
        ADCL367_ACT_REF_ENABLED = 0b11,
};

enum adxl367_activity_type {
        ADXL367_ACTIVITY,
        ADXL367_INACTIVITY,
};

enum adxl367_odr {
        ADXL367_ODR_12P5HZ,
        ADXL367_ODR_25HZ,
        ADXL367_ODR_50HZ,
        ADXL367_ODR_100HZ,
        ADXL367_ODR_200HZ,
        ADXL367_ODR_400HZ,
};

struct adxl367_state {
        const struct adxl367_ops        *ops;
        void                            *context;

        struct device                   *dev;
        struct regmap                   *regmap;

        /*
         * Synchronize access to members of driver state, and ensure atomicity
         * of consecutive regmap operations.
         */
        struct mutex            lock;

        enum adxl367_odr        odr;
        enum adxl367_range      range;

        unsigned int    act_threshold;
        unsigned int    act_time_ms;
        unsigned int    inact_threshold;
        unsigned int    inact_time_ms;

        unsigned int    fifo_set_size;
        unsigned int    fifo_watermark;

        __be16          fifo_buf[ADXL367_FIFO_SIZE] __aligned(IIO_DMA_MINALIGN);
        __be16          sample_buf;
        u8              act_threshold_buf[2];
        u8              inact_time_buf[2];
        u8              status_buf[3];
};

static const unsigned int adxl367_threshold_h_reg_tbl[] = {
        [ADXL367_ACTIVITY]   = ADXL367_REG_THRESH_ACT_H,
        [ADXL367_INACTIVITY] = ADXL367_REG_THRESH_INACT_H,
};

static const unsigned int adxl367_act_en_shift_tbl[] = {
        [ADXL367_ACTIVITY]   = 0,
        [ADXL367_INACTIVITY] = 2,
};

static const unsigned int adxl367_act_int_mask_tbl[] = {
        [ADXL367_ACTIVITY]   = ADXL367_INT_ACT_MASK,
        [ADXL367_INACTIVITY] = ADXL367_INT_INACT_MASK,
};

static const int adxl367_samp_freq_tbl[][2] = {
        [ADXL367_ODR_12P5HZ] = {12, 500000},
        [ADXL367_ODR_25HZ]   = {25, 0},
        [ADXL367_ODR_50HZ]   = {50, 0},
        [ADXL367_ODR_100HZ]  = {100, 0},
        [ADXL367_ODR_200HZ]  = {200, 0},
        [ADXL367_ODR_400HZ]  = {400, 0},
};

/* (g * 2) * 9.80665 * 1000000 / (2^14 - 1) */
static const int adxl367_range_scale_tbl[][2] = {
        [ADXL367_2G_RANGE] = {0, 2394347},
        [ADXL367_4G_RANGE] = {0, 4788695},
        [ADXL367_8G_RANGE] = {0, 9577391},
};

static const int adxl367_range_scale_factor_tbl[] = {
        [ADXL367_2G_RANGE] = 1,
        [ADXL367_4G_RANGE] = 2,
        [ADXL367_8G_RANGE] = 4,
};

enum {
        ADXL367_X_CHANNEL_INDEX,
        ADXL367_Y_CHANNEL_INDEX,
        ADXL367_Z_CHANNEL_INDEX,
        ADXL367_TEMP_CHANNEL_INDEX,
        ADXL367_EX_ADC_CHANNEL_INDEX
};

#define ADXL367_X_CHANNEL_MASK          BIT(ADXL367_X_CHANNEL_INDEX)
#define ADXL367_Y_CHANNEL_MASK          BIT(ADXL367_Y_CHANNEL_INDEX)
#define ADXL367_Z_CHANNEL_MASK          BIT(ADXL367_Z_CHANNEL_INDEX)
#define ADXL367_TEMP_CHANNEL_MASK       BIT(ADXL367_TEMP_CHANNEL_INDEX)
#define ADXL367_EX_ADC_CHANNEL_MASK     BIT(ADXL367_EX_ADC_CHANNEL_INDEX)

static const enum adxl367_fifo_format adxl367_fifo_formats[] = {
        ADXL367_FIFO_FORMAT_X,
        ADXL367_FIFO_FORMAT_Y,
        ADXL367_FIFO_FORMAT_Z,
        ADXL367_FIFO_FORMAT_XT,
        ADXL367_FIFO_FORMAT_YT,
        ADXL367_FIFO_FORMAT_ZT,
        ADXL367_FIFO_FORMAT_XA,
        ADXL367_FIFO_FORMAT_YA,
        ADXL367_FIFO_FORMAT_ZA,
        ADXL367_FIFO_FORMAT_XYZ,
        ADXL367_FIFO_FORMAT_XYZT,
        ADXL367_FIFO_FORMAT_XYZA,
};

static const unsigned long adxl367_channel_masks[] = {
        ADXL367_X_CHANNEL_MASK,
        ADXL367_Y_CHANNEL_MASK,
        ADXL367_Z_CHANNEL_MASK,
        ADXL367_X_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK,
        ADXL367_Y_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK,
        ADXL367_Z_CHANNEL_MASK | ADXL367_TEMP_CHANNEL_MASK,
        ADXL367_X_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK,
        ADXL367_Y_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK,
        ADXL367_Z_CHANNEL_MASK | ADXL367_EX_ADC_CHANNEL_MASK,
        ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK,
        ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK |
                ADXL367_TEMP_CHANNEL_MASK,
        ADXL367_X_CHANNEL_MASK | ADXL367_Y_CHANNEL_MASK | ADXL367_Z_CHANNEL_MASK |
                ADXL367_EX_ADC_CHANNEL_MASK,
        0,
};

static int adxl367_set_measure_en(struct adxl367_state *st, bool en)
{
        enum adxl367_op_mode op_mode = en ? ADXL367_OP_MEASURE
                                          : ADXL367_OP_STANDBY;
        int ret;

        ret = regmap_update_bits(st->regmap, ADXL367_REG_POWER_CTL,
                                 ADXL367_POWER_CTL_MODE_MASK,
                                 FIELD_PREP(ADXL367_POWER_CTL_MODE_MASK,
                                            op_mode));
        if (ret)
                return ret;

        /*
         * Wait for acceleration output to settle after entering
         * measure mode.
         */
        if (en)
                msleep(100);

        return 0;
}

static void adxl367_scale_act_thresholds(struct adxl367_state *st,
                                         enum adxl367_range old_range,
                                         enum adxl367_range new_range)
{
        st->act_threshold = st->act_threshold
                            * adxl367_range_scale_factor_tbl[old_range]
                            / adxl367_range_scale_factor_tbl[new_range];
        st->inact_threshold = st->inact_threshold
                              * adxl367_range_scale_factor_tbl[old_range]
                              / adxl367_range_scale_factor_tbl[new_range];
}

static int _adxl367_set_act_threshold(struct adxl367_state *st,
                                      enum adxl367_activity_type act,
                                      unsigned int threshold)
{
        u8 reg = adxl367_threshold_h_reg_tbl[act];
        int ret;

        if (threshold > ADXL367_THRESH_MAX)
                return -EINVAL;

        st->act_threshold_buf[0] = FIELD_PREP(ADXL367_THRESH_H_MASK,
                                              FIELD_GET(ADXL367_THRESH_VAL_H_MASK,
                                                        threshold));
        st->act_threshold_buf[1] = FIELD_PREP(ADXL367_THRESH_L_MASK,
                                              FIELD_GET(ADXL367_THRESH_VAL_L_MASK,
                                                        threshold));

        ret = regmap_bulk_write(st->regmap, reg, st->act_threshold_buf,
                                sizeof(st->act_threshold_buf));
        if (ret)
                return ret;

        if (act == ADXL367_ACTIVITY)
                st->act_threshold = threshold;
        else
                st->inact_threshold = threshold;

        return 0;
}

static int adxl367_set_act_threshold(struct adxl367_state *st,
                                     enum adxl367_activity_type act,
                                     unsigned int threshold)
{
        int ret;

        guard(mutex)(&st->lock);

        ret = adxl367_set_measure_en(st, false);
        if (ret)
                return ret;

        ret = _adxl367_set_act_threshold(st, act, threshold);
        if (ret)
                return ret;

        return adxl367_set_measure_en(st, true);
}

static int adxl367_set_act_proc_mode(struct adxl367_state *st,
                                     enum adxl367_act_proc_mode mode)
{
        return regmap_update_bits(st->regmap, ADXL367_REG_ACT_INACT_CTL,
                                  ADXL367_ACT_LINKLOOP_MASK,
                                  FIELD_PREP(ADXL367_ACT_LINKLOOP_MASK,
                                             mode));
}

static int adxl367_set_act_interrupt_en(struct adxl367_state *st,
                                        enum adxl367_activity_type act,
                                        bool en)
{
        unsigned int mask = adxl367_act_int_mask_tbl[act];

        return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP,
                                  mask, en ? mask : 0);
}

static int adxl367_get_act_interrupt_en(struct adxl367_state *st,
                                        enum adxl367_activity_type act,
                                        bool *en)
{
        unsigned int mask = adxl367_act_int_mask_tbl[act];
        unsigned int val;
        int ret;

        ret = regmap_read(st->regmap, ADXL367_REG_INT1_MAP, &val);
        if (ret)
                return ret;

        *en = !!(val & mask);

        return 0;
}

static int adxl367_set_act_en(struct adxl367_state *st,
                              enum adxl367_activity_type act,
                              enum adxl367_act_en_mode en)
{
        unsigned int ctl_shift = adxl367_act_en_shift_tbl[act];

        return regmap_update_bits(st->regmap, ADXL367_REG_ACT_INACT_CTL,
                                  ADXL367_ACT_EN_MASK << ctl_shift,
                                  en << ctl_shift);
}

static int adxl367_set_fifo_watermark_interrupt_en(struct adxl367_state *st,
                                                   bool en)
{
        return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP,
                                  ADXL367_INT_FIFO_WATERMARK_MASK,
                                  en ? ADXL367_INT_FIFO_WATERMARK_MASK : 0);
}

static int adxl367_get_fifo_mode(struct adxl367_state *st,
                                 enum adxl367_fifo_mode *fifo_mode)
{
        unsigned int val;
        int ret;

        ret = regmap_read(st->regmap, ADXL367_REG_FIFO_CTL, &val);
        if (ret)
                return ret;

        *fifo_mode = FIELD_GET(ADXL367_FIFO_CTL_MODE_MASK, val);

        return 0;
}

static int adxl367_set_fifo_mode(struct adxl367_state *st,
                                 enum adxl367_fifo_mode fifo_mode)
{
        return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL,
                                  ADXL367_FIFO_CTL_MODE_MASK,
                                  FIELD_PREP(ADXL367_FIFO_CTL_MODE_MASK,
                                             fifo_mode));
}

static int adxl367_set_fifo_format(struct adxl367_state *st,
                                   enum adxl367_fifo_format fifo_format)
{
        return regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL,
                                  ADXL367_FIFO_CTL_FORMAT_MASK,
                                  FIELD_PREP(ADXL367_FIFO_CTL_FORMAT_MASK,
                                             fifo_format));
}

static int adxl367_set_fifo_watermark(struct adxl367_state *st,
                                      unsigned int fifo_watermark)
{
        unsigned int fifo_samples = fifo_watermark * st->fifo_set_size;
        unsigned int fifo_samples_h, fifo_samples_l;
        int ret;

        if (fifo_samples > ADXL367_FIFO_MAX_WATERMARK)
                fifo_samples = ADXL367_FIFO_MAX_WATERMARK;

        fifo_samples /= st->fifo_set_size;

        fifo_samples_h = FIELD_PREP(ADXL367_SAMPLES_H_MASK,
                                    FIELD_GET(ADXL367_SAMPLES_VAL_H_MASK,
                                              fifo_samples));
        fifo_samples_l = FIELD_PREP(ADXL367_SAMPLES_L_MASK,
                                    FIELD_GET(ADXL367_SAMPLES_VAL_L_MASK,
                                              fifo_samples));

        ret = regmap_update_bits(st->regmap, ADXL367_REG_FIFO_CTL,
                                 ADXL367_SAMPLES_H_MASK, fifo_samples_h);
        if (ret)
                return ret;

        ret = regmap_update_bits(st->regmap, ADXL367_REG_FIFO_SAMPLES,
                                 ADXL367_SAMPLES_L_MASK, fifo_samples_l);
        if (ret)
                return ret;

        st->fifo_watermark = fifo_watermark;

        return 0;
}

static int adxl367_set_range(struct iio_dev *indio_dev,
                             enum adxl367_range range)
{
        struct adxl367_state *st = iio_priv(indio_dev);
        int ret;

        guard(mutex)(&st->lock);

        ret = adxl367_set_measure_en(st, false);
        if (ret)
                return ret;

        ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL,
                                 ADXL367_FILTER_CTL_RANGE_MASK,
                                 FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK,
                                            range));
        if (ret)
                return ret;

        adxl367_scale_act_thresholds(st, st->range, range);

        /* Activity thresholds depend on range */
        ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY,
                                         st->act_threshold);
        if (ret)
                return ret;

        ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY,
                                         st->inact_threshold);
        if (ret)
                return ret;

        ret = adxl367_set_measure_en(st, true);
        if (ret)
                return ret;

        st->range = range;

        return 0;
}

static int adxl367_time_ms_to_samples(struct adxl367_state *st, unsigned int ms)
{
        int freq_hz = adxl367_samp_freq_tbl[st->odr][0];
        int freq_microhz = adxl367_samp_freq_tbl[st->odr][1];
        /* Scale to decihertz to prevent precision loss in 12.5Hz case. */
        int freq_dhz = freq_hz * 10 + freq_microhz / 100000;

        return DIV_ROUND_CLOSEST(ms * freq_dhz, 10000);
}

static int _adxl367_set_act_time_ms(struct adxl367_state *st, unsigned int ms)
{
        unsigned int val = adxl367_time_ms_to_samples(st, ms);
        int ret;

        if (val > ADXL367_TIME_ACT_MAX)
                val = ADXL367_TIME_ACT_MAX;

        ret = regmap_write(st->regmap, ADXL367_REG_TIME_ACT, val);
        if (ret)
                return ret;

        st->act_time_ms = ms;

        return 0;
}

static int _adxl367_set_inact_time_ms(struct adxl367_state *st, unsigned int ms)
{
        unsigned int val = adxl367_time_ms_to_samples(st, ms);
        int ret;

        if (val > ADXL367_TIME_INACT_MAX)
                val = ADXL367_TIME_INACT_MAX;

        st->inact_time_buf[0] = FIELD_PREP(ADXL367_TIME_INACT_H_MASK,
                                           FIELD_GET(ADXL367_TIME_INACT_VAL_H_MASK,
                                                     val));
        st->inact_time_buf[1] = FIELD_PREP(ADXL367_TIME_INACT_L_MASK,
                                           FIELD_GET(ADXL367_TIME_INACT_VAL_L_MASK,
                                                     val));

        ret = regmap_bulk_write(st->regmap, ADXL367_REG_TIME_INACT_H,
                                st->inact_time_buf, sizeof(st->inact_time_buf));
        if (ret)
                return ret;

        st->inact_time_ms = ms;

        return 0;
}

static int adxl367_set_act_time_ms(struct adxl367_state *st,
                                   enum adxl367_activity_type act,
                                   unsigned int ms)
{
        int ret;

        guard(mutex)(&st->lock);

        ret = adxl367_set_measure_en(st, false);
        if (ret)
                return ret;

        if (act == ADXL367_ACTIVITY)
                ret = _adxl367_set_act_time_ms(st, ms);
        else
                ret = _adxl367_set_inact_time_ms(st, ms);

        if (ret)
                return ret;

        return adxl367_set_measure_en(st, true);
}

static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr)
{
        int ret;

        ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL,
                                 ADXL367_FILTER_CTL_ODR_MASK,
                                 FIELD_PREP(ADXL367_FILTER_CTL_ODR_MASK,
                                            odr));
        if (ret)
                return ret;

        st->odr = odr;

        /* Activity timers depend on ODR */
        ret = _adxl367_set_act_time_ms(st, st->act_time_ms);
        if (ret)
                return ret;

        return _adxl367_set_inact_time_ms(st, st->inact_time_ms);
}

static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr)
{
        struct adxl367_state *st = iio_priv(indio_dev);
        int ret;

        guard(mutex)(&st->lock);

        ret = adxl367_set_measure_en(st, false);
        if (ret)
                return ret;

        ret = _adxl367_set_odr(st, odr);
        if (ret)
                return ret;

        return adxl367_set_measure_en(st, true);
}

static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg,
                                   bool en)
{
        return regmap_update_bits(st->regmap, reg, ADXL367_ADC_EN_MASK,
                                  en ? ADXL367_ADC_EN_MASK : 0);
}

static int adxl367_set_temp_adc_reg_en(struct adxl367_state *st,
                                       unsigned int reg, bool en)
{
        int ret;

        switch (reg) {
        case ADXL367_REG_TEMP_DATA_H:
                ret = adxl367_set_temp_adc_en(st, ADXL367_REG_TEMP_CTL, en);
                break;
        case ADXL367_REG_EX_ADC_DATA_H:
                ret = adxl367_set_temp_adc_en(st, ADXL367_REG_ADC_CTL, en);
                break;
        default:
                return 0;
        }

        if (ret)
                return ret;

        if (en)
                msleep(100);

        return 0;
}

static int adxl367_set_temp_adc_mask_en(struct adxl367_state *st,
                                        const unsigned long *active_scan_mask,
                                        bool en)
{
        if (*active_scan_mask & ADXL367_TEMP_CHANNEL_MASK)
                return adxl367_set_temp_adc_en(st, ADXL367_REG_TEMP_CTL, en);
        else if (*active_scan_mask & ADXL367_EX_ADC_CHANNEL_MASK)
                return adxl367_set_temp_adc_en(st, ADXL367_REG_ADC_CTL, en);

        return 0;
}

static int adxl367_find_odr(struct adxl367_state *st, int val, int val2,
                            enum adxl367_odr *odr)
{
        size_t size = ARRAY_SIZE(adxl367_samp_freq_tbl);
        int i;

        for (i = 0; i < size; i++)
                if (val == adxl367_samp_freq_tbl[i][0] &&
                    val2 == adxl367_samp_freq_tbl[i][1])
                        break;

        if (i == size)
                return -EINVAL;

        *odr = i;

        return 0;
}

static int adxl367_find_range(struct adxl367_state *st, int val, int val2,
                              enum adxl367_range *range)
{
        size_t size = ARRAY_SIZE(adxl367_range_scale_tbl);
        int i;

        for (i = 0; i < size; i++)
                if (val == adxl367_range_scale_tbl[i][0] &&
                    val2 == adxl367_range_scale_tbl[i][1])
                        break;

        if (i == size)
                return -EINVAL;

        *range = i;

        return 0;
}

static int adxl367_read_sample(struct iio_dev *indio_dev,
                               struct iio_chan_spec const *chan,
                               int *val)
{
        struct adxl367_state *st = iio_priv(indio_dev);
        u16 sample;
        int ret;

        guard(mutex)(&st->lock);

        ret = adxl367_set_temp_adc_reg_en(st, chan->address, true);
        if (ret)
                return ret;

        ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf,
                               sizeof(st->sample_buf));
        if (ret)
                return ret;

        sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf));
        *val = sign_extend32(sample, chan->scan_type.realbits - 1);

        ret = adxl367_set_temp_adc_reg_en(st, chan->address, false);
        if (ret)
                return ret;

        return IIO_VAL_INT;
}

static int adxl367_get_status(struct adxl367_state *st, u8 *status,
                              u16 *fifo_entries)
{
        int ret;

        /* Read STATUS, FIFO_ENT_L and FIFO_ENT_H */
        ret = regmap_bulk_read(st->regmap, ADXL367_REG_STATUS,
                               st->status_buf, sizeof(st->status_buf));
        if (ret)
                return ret;

        st->status_buf[2] &= ADXL367_FIFO_ENT_H_MASK;

        *status = st->status_buf[0];
        *fifo_entries = get_unaligned_le16(&st->status_buf[1]);

        return 0;
}

static bool adxl367_push_event(struct iio_dev *indio_dev, u8 status)
{
        unsigned int ev_dir;

        if (FIELD_GET(ADXL367_STATUS_ACT_MASK, status))
                ev_dir = IIO_EV_DIR_RISING;
        else if (FIELD_GET(ADXL367_STATUS_INACT_MASK, status))
                ev_dir = IIO_EV_DIR_FALLING;
        else
                return false;

        iio_push_event(indio_dev,
                       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z,
                                          IIO_EV_TYPE_THRESH, ev_dir),
                       iio_get_time_ns(indio_dev));

        return true;
}

static bool adxl367_push_fifo_data(struct iio_dev *indio_dev, u8 status,
                                   u16 fifo_entries)
{
        struct adxl367_state *st = iio_priv(indio_dev);
        int ret;
        int i;

        if (!FIELD_GET(ADXL367_STATUS_FIFO_FULL_MASK, status))
                return false;

        fifo_entries -= fifo_entries % st->fifo_set_size;

        ret = st->ops->read_fifo(st->context, st->fifo_buf, fifo_entries);
        if (ret) {
                dev_err(st->dev, "Failed to read FIFO: %d\n", ret);
                return true;
        }

        for (i = 0; i < fifo_entries; i += st->fifo_set_size)
                iio_push_to_buffers(indio_dev, &st->fifo_buf[i]);

        return true;
}

static irqreturn_t adxl367_irq_handler(int irq, void *private)
{
        struct iio_dev *indio_dev = private;
        struct adxl367_state *st = iio_priv(indio_dev);
        u16 fifo_entries;
        bool handled;
        u8 status;
        int ret;

        ret = adxl367_get_status(st, &status, &fifo_entries);
        if (ret)
                return IRQ_NONE;

        handled = adxl367_push_event(indio_dev, status);
        handled |= adxl367_push_fifo_data(indio_dev, status, fifo_entries);

        return handled ? IRQ_HANDLED : IRQ_NONE;
}

static int adxl367_reg_access(struct iio_dev *indio_dev,
                              unsigned int reg,
                              unsigned int writeval,
                              unsigned int *readval)
{
        struct adxl367_state *st = iio_priv(indio_dev);

        if (readval)
                return regmap_read(st->regmap, reg, readval);
        else
                return regmap_write(st->regmap, reg, writeval);
}

static int adxl367_read_raw(struct iio_dev *indio_dev,
                            struct iio_chan_spec const *chan,
                            int *val, int *val2, long info)
{
        struct adxl367_state *st = iio_priv(indio_dev);
        int ret;

        switch (info) {
        case IIO_CHAN_INFO_RAW:
                if (!iio_device_claim_direct(indio_dev))
                        return -EBUSY;
                ret = adxl367_read_sample(indio_dev, chan, val);
                iio_device_release_direct(indio_dev);
                return ret;
        case IIO_CHAN_INFO_SCALE:
                switch (chan->type) {
                case IIO_ACCEL: {
                        guard(mutex)(&st->lock);
                        *val = adxl367_range_scale_tbl[st->range][0];
                        *val2 = adxl367_range_scale_tbl[st->range][1];
                        return IIO_VAL_INT_PLUS_NANO;
                }
                case IIO_TEMP:
                        *val = 1000;
                        *val2 = ADXL367_TEMP_PER_C;
                        return IIO_VAL_FRACTIONAL;
                case IIO_VOLTAGE:
                        *val = ADXL367_VOLTAGE_MAX_MV;
                        *val2 = ADXL367_VOLTAGE_MAX_RAW;
                        return IIO_VAL_FRACTIONAL;
                default:
                        return -EINVAL;
                }
        case IIO_CHAN_INFO_OFFSET:
                switch (chan->type) {
                case IIO_TEMP:
                        *val = 25 * ADXL367_TEMP_PER_C - ADXL367_TEMP_25C;
                        return IIO_VAL_INT;
                case IIO_VOLTAGE:
                        *val = ADXL367_VOLTAGE_OFFSET;
                        return IIO_VAL_INT;
                default:
                        return -EINVAL;
                }
        case IIO_CHAN_INFO_SAMP_FREQ: {
                guard(mutex)(&st->lock);
                *val = adxl367_samp_freq_tbl[st->odr][0];
                *val2 = adxl367_samp_freq_tbl[st->odr][1];
                return IIO_VAL_INT_PLUS_MICRO;
        }
        default:
                return -EINVAL;
        }
}

static int adxl367_write_raw(struct iio_dev *indio_dev,
                             struct iio_chan_spec const *chan,
                             int val, int val2, long info)
{
        struct adxl367_state *st = iio_priv(indio_dev);
        int ret;

        switch (info) {
        case IIO_CHAN_INFO_SAMP_FREQ: {
                enum adxl367_odr odr;

                ret = adxl367_find_odr(st, val, val2, &odr);
                if (ret)
                        return ret;

                if (!iio_device_claim_direct(indio_dev))
                        return -EBUSY;

                ret = adxl367_set_odr(indio_dev, odr);
                iio_device_release_direct(indio_dev);
                return ret;
        }
        case IIO_CHAN_INFO_SCALE: {
                enum adxl367_range range;

                ret = adxl367_find_range(st, val, val2, &range);
                if (ret)
                        return ret;

                if (!iio_device_claim_direct(indio_dev))
                        return -EBUSY;

                ret = adxl367_set_range(indio_dev, range);
                iio_device_release_direct(indio_dev);
                return ret;
        }
        default:
                return -EINVAL;
        }
}

static int adxl367_write_raw_get_fmt(struct iio_dev *indio_dev,
                                     struct iio_chan_spec const *chan,
                                     long info)
{
        switch (info) {
        case IIO_CHAN_INFO_SCALE:
                if (chan->type != IIO_ACCEL)
                        return -EINVAL;

                return IIO_VAL_INT_PLUS_NANO;
        default:
                return IIO_VAL_INT_PLUS_MICRO;
        }
}

static int adxl367_read_avail(struct iio_dev *indio_dev,
                              struct iio_chan_spec const *chan,
                              const int **vals, int *type, int *length,
                              long info)
{
        switch (info) {
        case IIO_CHAN_INFO_SCALE:
                if (chan->type != IIO_ACCEL)
                        return -EINVAL;

                *vals = (int *)adxl367_range_scale_tbl;
                *type = IIO_VAL_INT_PLUS_NANO;
                *length = ARRAY_SIZE(adxl367_range_scale_tbl) * 2;
                return IIO_AVAIL_LIST;
        case IIO_CHAN_INFO_SAMP_FREQ:
                *vals = (int *)adxl367_samp_freq_tbl;
                *type = IIO_VAL_INT_PLUS_MICRO;
                *length = ARRAY_SIZE(adxl367_samp_freq_tbl) * 2;
                return IIO_AVAIL_LIST;
        default:
                return -EINVAL;
        }
}

static int 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)
{
        struct adxl367_state *st = iio_priv(indio_dev);

        guard(mutex)(&st->lock);
        switch (info) {
        case IIO_EV_INFO_VALUE: {
                switch (dir) {
                case IIO_EV_DIR_RISING:
                        *val = st->act_threshold;
                        return IIO_VAL_INT;
                case IIO_EV_DIR_FALLING:
                        *val = st->inact_threshold;
                        return IIO_VAL_INT;
                default:
                        return -EINVAL;
                }
        }
        case IIO_EV_INFO_PERIOD:
                switch (dir) {
                case IIO_EV_DIR_RISING:
                        *val = st->act_time_ms;
                        *val2 = 1000;
                        return IIO_VAL_FRACTIONAL;
                case IIO_EV_DIR_FALLING:
                        *val = st->inact_time_ms;
                        *val2 = 1000;
                        return IIO_VAL_FRACTIONAL;
                default:
                        return -EINVAL;
                }
        default:
                return -EINVAL;
        }
}

static int 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)
{
        struct adxl367_state *st = iio_priv(indio_dev);

        switch (info) {
        case IIO_EV_INFO_VALUE:
                if (val < 0)
                        return -EINVAL;

                switch (dir) {
                case IIO_EV_DIR_RISING:
                        return adxl367_set_act_threshold(st, ADXL367_ACTIVITY, val);
                case IIO_EV_DIR_FALLING:
                        return adxl367_set_act_threshold(st, ADXL367_INACTIVITY, val);
                default:
                        return -EINVAL;
                }
        case IIO_EV_INFO_PERIOD:
                if (val < 0)
                        return -EINVAL;

                val = val * 1000 + DIV_ROUND_UP(val2, 1000);
                switch (dir) {
                case IIO_EV_DIR_RISING:
                        return adxl367_set_act_time_ms(st, ADXL367_ACTIVITY, val);
                case IIO_EV_DIR_FALLING:
                        return adxl367_set_act_time_ms(st, ADXL367_INACTIVITY, val);
                default:
                        return -EINVAL;
                }
        default:
                return -EINVAL;
        }
}

static int 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)
{
        struct adxl367_state *st = iio_priv(indio_dev);
        bool en;
        int ret;

        switch (dir) {
        case IIO_EV_DIR_RISING:
                ret = adxl367_get_act_interrupt_en(st, ADXL367_ACTIVITY, &en);
                return ret ?: en;
        case IIO_EV_DIR_FALLING:
                ret = adxl367_get_act_interrupt_en(st, ADXL367_INACTIVITY, &en);
                return ret ?: en;
        default:
                return -EINVAL;
        }
}

static int __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,
                                        bool state)
{
        struct adxl367_state *st = iio_priv(indio_dev);
        enum adxl367_activity_type act;
        int ret;

        switch (dir) {
        case IIO_EV_DIR_RISING:
                act = ADXL367_ACTIVITY;
                break;
        case IIO_EV_DIR_FALLING:
                act = ADXL367_INACTIVITY;
                break;
        default:
                return -EINVAL;
        }

        guard(mutex)(&st->lock);

        ret = adxl367_set_measure_en(st, false);
        if (ret)
                return ret;

        ret = adxl367_set_act_interrupt_en(st, act, state);
        if (ret)
                return ret;

        ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED
                                 : ADXL367_ACT_DISABLED);
        if (ret)
                return ret;

        return adxl367_set_measure_en(st, true);
}

static int 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,
                                      bool state)
{
        int ret;

        if (!iio_device_claim_direct(indio_dev))
                return -EBUSY;

        ret = __adxl367_write_event_config(indio_dev, chan, type, dir, state);
        iio_device_release_direct(indio_dev);
        return ret;
}

static ssize_t adxl367_get_fifo_enabled(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
{
        struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev));
        enum adxl367_fifo_mode fifo_mode;
        int ret;

        ret = adxl367_get_fifo_mode(st, &fifo_mode);
        if (ret)
                return ret;

        return sysfs_emit(buf, "%d\n", fifo_mode != ADXL367_FIFO_MODE_DISABLED);
}

static ssize_t adxl367_get_fifo_watermark(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf)
{
        struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev));
        unsigned int fifo_watermark;

        guard(mutex)(&st->lock);
        fifo_watermark = st->fifo_watermark;

        return sysfs_emit(buf, "%d\n", fifo_watermark);
}

IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1");
IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max,
                             __stringify(ADXL367_FIFO_MAX_WATERMARK));
static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
                       adxl367_get_fifo_watermark, NULL, 0);
static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
                       adxl367_get_fifo_enabled, NULL, 0);

static const struct iio_dev_attr *adxl367_fifo_attributes[] = {
        &iio_dev_attr_hwfifo_watermark_min,
        &iio_dev_attr_hwfifo_watermark_max,
        &iio_dev_attr_hwfifo_watermark,
        &iio_dev_attr_hwfifo_enabled,
        NULL,
};

static int adxl367_set_watermark(struct iio_dev *indio_dev, unsigned int val)
{
        struct adxl367_state *st  = iio_priv(indio_dev);
        int ret;

        if (val > ADXL367_FIFO_MAX_WATERMARK)
                return -EINVAL;

        guard(mutex)(&st->lock);

        ret = adxl367_set_measure_en(st, false);
        if (ret)
                return ret;

        ret = adxl367_set_fifo_watermark(st, val);
        if (ret)
                return ret;

        return adxl367_set_measure_en(st, true);
}

static bool adxl367_find_mask_fifo_format(const unsigned long *scan_mask,
                                          enum adxl367_fifo_format *fifo_format)
{
        size_t size = ARRAY_SIZE(adxl367_fifo_formats);
        int i;

        for (i = 0; i < size; i++)
                if (*scan_mask == adxl367_channel_masks[i])
                        break;

        if (i == size)
                return false;

        *fifo_format = adxl367_fifo_formats[i];

        return true;
}

static int adxl367_update_scan_mode(struct iio_dev *indio_dev,
                                    const unsigned long *active_scan_mask)
{
        struct adxl367_state *st  = iio_priv(indio_dev);
        enum adxl367_fifo_format fifo_format;
        int ret;

        if (!adxl367_find_mask_fifo_format(active_scan_mask, &fifo_format))
                return -EINVAL;

        guard(mutex)(&st->lock);

        ret = adxl367_set_measure_en(st, false);
        if (ret)
                return ret;

        ret = adxl367_set_fifo_format(st, fifo_format);
        if (ret)
                return ret;

        ret = adxl367_set_measure_en(st, true);
        if (ret)
                return ret;

        st->fifo_set_size = bitmap_weight(active_scan_mask,
                                          iio_get_masklength(indio_dev));

        return 0;
}

static int adxl367_buffer_postenable(struct iio_dev *indio_dev)
{
        struct adxl367_state *st = iio_priv(indio_dev);
        int ret;

        guard(mutex)(&st->lock);

        ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
                                           true);
        if (ret)
                return ret;

        ret = adxl367_set_measure_en(st, false);
        if (ret)
                return ret;

        ret = adxl367_set_fifo_watermark_interrupt_en(st, true);
        if (ret)
                return ret;

        ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_STREAM);
        if (ret)
                return ret;

        return adxl367_set_measure_en(st, true);
}

static int adxl367_buffer_predisable(struct iio_dev *indio_dev)
{
        struct adxl367_state *st = iio_priv(indio_dev);
        int ret;

        guard(mutex)(&st->lock);

        ret = adxl367_set_measure_en(st, false);
        if (ret)
                return ret;

        ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_DISABLED);
        if (ret)
                return ret;

        ret = adxl367_set_fifo_watermark_interrupt_en(st, false);
        if (ret)
                return ret;

        ret = adxl367_set_measure_en(st, true);
        if (ret)
                return ret;

        return adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
                                            false);
}

static const struct iio_buffer_setup_ops adxl367_buffer_ops = {
        .postenable = adxl367_buffer_postenable,
        .predisable = adxl367_buffer_predisable,
};

static const struct iio_info adxl367_info = {
        .read_raw = adxl367_read_raw,
        .write_raw = adxl367_write_raw,
        .write_raw_get_fmt = adxl367_write_raw_get_fmt,
        .read_avail = adxl367_read_avail,
        .read_event_config = adxl367_read_event_config,
        .write_event_config = adxl367_write_event_config,
        .read_event_value = adxl367_read_event_value,
        .write_event_value = adxl367_write_event_value,
        .debugfs_reg_access = adxl367_reg_access,
        .hwfifo_set_watermark = adxl367_set_watermark,
        .update_scan_mode = adxl367_update_scan_mode,
};

static const struct iio_event_spec adxl367_events[] = {
        {
                .type = IIO_EV_TYPE_MAG_REFERENCED,
                .dir = IIO_EV_DIR_RISING,
                .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
                                       BIT(IIO_EV_INFO_PERIOD) |
                                       BIT(IIO_EV_INFO_VALUE),
        },
        {
                .type = IIO_EV_TYPE_MAG_REFERENCED,
                .dir = IIO_EV_DIR_FALLING,
                .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
                                       BIT(IIO_EV_INFO_PERIOD) |
                                       BIT(IIO_EV_INFO_VALUE),
        },
};

#define ADXL367_ACCEL_CHANNEL(index, reg, axis) {                       \
        .type = IIO_ACCEL,                                              \
        .address = (reg),                                               \
        .modified = 1,                                                  \
        .channel2 = IIO_MOD_##axis,                                     \
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),                   \
        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),           \
        .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
        .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),        \
        .info_mask_shared_by_all_available =                            \
                        BIT(IIO_CHAN_INFO_SAMP_FREQ),                   \
        .event_spec = adxl367_events,                                   \
        .num_event_specs = ARRAY_SIZE(adxl367_events),                  \
        .scan_index = (index),                                          \
        .scan_type = {                                                  \
                .sign = 's',                                            \
                .realbits = 14,                                         \
                .storagebits = 16,                                      \
                .endianness = IIO_BE,                                   \
        },                                                              \
}

#define ADXL367_CHANNEL(index, reg, _type) {                            \
        .type = (_type),                                                \
        .address = (reg),                                               \
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                  \
                              BIT(IIO_CHAN_INFO_OFFSET) |               \
                              BIT(IIO_CHAN_INFO_SCALE),                 \
        .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),        \
        .scan_index = (index),                                          \
        .scan_type = {                                                  \
                .sign = 's',                                            \
                .realbits = 14,                                         \
                .storagebits = 16,                                      \
                .endianness = IIO_BE,                                   \
        },                                                              \
}

static const struct iio_chan_spec adxl367_channels[] = {
        ADXL367_ACCEL_CHANNEL(ADXL367_X_CHANNEL_INDEX, ADXL367_REG_X_DATA_H, X),
        ADXL367_ACCEL_CHANNEL(ADXL367_Y_CHANNEL_INDEX, ADXL367_REG_Y_DATA_H, Y),
        ADXL367_ACCEL_CHANNEL(ADXL367_Z_CHANNEL_INDEX, ADXL367_REG_Z_DATA_H, Z),
        ADXL367_CHANNEL(ADXL367_TEMP_CHANNEL_INDEX, ADXL367_REG_TEMP_DATA_H,
                        IIO_TEMP),
        ADXL367_CHANNEL(ADXL367_EX_ADC_CHANNEL_INDEX, ADXL367_REG_EX_ADC_DATA_H,
                        IIO_VOLTAGE),
};

static int adxl367_verify_devid(struct adxl367_state *st)
{
        unsigned int val;
        int ret;

        ret = regmap_read(st->regmap, ADXL367_REG_DEVID, &val);
        if (ret)
                return dev_err_probe(st->dev, ret, "Failed to read dev id\n");

        if (val != ADXL367_DEVID_AD)
                return dev_err_probe(st->dev, -ENODEV,
                                     "Invalid dev id 0x%02X, expected 0x%02X\n",
                                     val, ADXL367_DEVID_AD);

        return 0;
}

static int adxl367_setup(struct adxl367_state *st)
{
        int ret;

        ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY,
                                         ADXL367_2G_RANGE_1G);
        if (ret)
                return ret;

        ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY,
                                         ADXL367_2G_RANGE_100MG);
        if (ret)
                return ret;

        ret = adxl367_set_act_proc_mode(st, ADXL367_LOOPED);
        if (ret)
                return ret;

        ret = _adxl367_set_odr(st, ADXL367_ODR_400HZ);
        if (ret)
                return ret;

        ret = _adxl367_set_act_time_ms(st, 10);
        if (ret)
                return ret;

        ret = _adxl367_set_inact_time_ms(st, 10000);
        if (ret)
                return ret;

        return adxl367_set_measure_en(st, true);
}

int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
                  void *context, struct regmap *regmap, int irq)
{
        static const char * const regulator_names[] = { "vdd", "vddio" };
        struct iio_dev *indio_dev;
        struct adxl367_state *st;
        int ret;

        indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
        if (!indio_dev)
                return -ENOMEM;

        st = iio_priv(indio_dev);
        st->dev = dev;
        st->regmap = regmap;
        st->context = context;
        st->ops = ops;

        ret = devm_mutex_init(dev, &st->lock);
        if (ret)
                return ret;

        indio_dev->channels = adxl367_channels;
        indio_dev->num_channels = ARRAY_SIZE(adxl367_channels);
        indio_dev->available_scan_masks = adxl367_channel_masks;
        indio_dev->name = "adxl367";
        indio_dev->info = &adxl367_info;
        indio_dev->modes = INDIO_DIRECT_MODE;

        ret = devm_regulator_bulk_get_enable(st->dev,
                                             ARRAY_SIZE(regulator_names),
                                             regulator_names);
        if (ret)
                return dev_err_probe(st->dev, ret,
                                     "Failed to get regulators\n");

        ret = regmap_write(st->regmap, ADXL367_REG_RESET, ADXL367_RESET_CODE);
        if (ret)
                return ret;

        fsleep(15000);

        ret = adxl367_verify_devid(st);
        if (ret)
                return ret;

        ret = adxl367_setup(st);
        if (ret)
                return ret;

        ret = devm_iio_kfifo_buffer_setup_ext(st->dev, indio_dev,
                                              &adxl367_buffer_ops,
                                              adxl367_fifo_attributes);
        if (ret)
                return ret;

        ret = devm_request_threaded_irq(st->dev, irq, NULL,
                                        adxl367_irq_handler, IRQF_ONESHOT,
                                        indio_dev->name, indio_dev);
        if (ret)
                return dev_err_probe(st->dev, ret, "Failed to request irq\n");

        return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(adxl367_probe, "IIO_ADXL367");

MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>");
MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer driver");
MODULE_LICENSE("GPL");