/*
 * Copyright (c) 2018 Analog Devices Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT adi_adxl372

#include <zephyr/drivers/sensor.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <string.h>
#include <zephyr/init.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/__assert.h>
#include <stdlib.h>
#include <zephyr/logging/log.h>

#include "adxl372.h"

LOG_MODULE_REGISTER(ADXL372, CONFIG_SENSOR_LOG_LEVEL);

/**
 * Set the threshold for activity detection for a single axis
 * @param dev - The device structure.
 * @param axis_reg_h - The high part of the activity register.
 * @param act - The activity config structure.
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_activity_threshold(const struct device *dev,
					  uint8_t axis_reg_h,
					  const struct adxl372_activity_threshold *act)
{
	int ret;
	uint8_t val;
	struct adxl372_data *data = dev->data;

	ret = data->hw_tf->write_reg(dev, axis_reg_h++, act->thresh >> 3);
	if (ret) {
		return ret;
	}

	switch (axis_reg_h) {
	case ADXL372_X_THRESH_ACT_L:
	case ADXL372_X_THRESH_INACT_L:
	case ADXL372_X_THRESH_ACT2_L:
		val = (act->thresh << 5) | (act->referenced << 1) | act->enable;
		break;
	default:
		val = (act->thresh << 5) | act->enable;
	}

	return data->hw_tf->write_reg(dev, axis_reg_h, val);
}

/**
 * Set the threshold for activity detection for all 3-axis
 * @param dev - The device structure.
 * @param axis_reg_h - The high part of the activity register.
 * @param act - The activity config structure.
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_activity_threshold_xyz(const struct device *dev,
					      uint8_t axis_reg_h,
					      const struct adxl372_activity_threshold *act)
{
	int i, ret;

	for (i = 0; i < 3; i++) {
		ret = adxl372_set_activity_threshold(dev, axis_reg_h, act);
		if (ret) {
			return ret;
		}
		axis_reg_h += 2U;
	}

	return 0;
}

/**
 * Set the mode of operation.
 * @param dev - The device structure.
 * @param op_mode - Mode of operation.
 *		Accepted values: ADXL372_STANDBY
 *				 ADXL372_WAKE_UP
 *				 ADXL372_INSTANT_ON
 *				 ADXL372_FULL_BW_MEASUREMENT
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_op_mode(const struct device *dev,
			       enum adxl372_op_mode op_mode)
{
	struct adxl372_data *data = dev->data;

	return data->hw_tf->write_reg_mask(dev, ADXL372_POWER_CTL,
					   ADXL372_POWER_CTL_MODE_MSK,
					   ADXL372_POWER_CTL_MODE(op_mode));
}

/**
 * Autosleep. When set to 1, autosleep is enabled, and the device enters
 * wake-up mode automatically upon detection of inactivity.
 * @param dev - The device structure.
 * @param enable - Accepted values: true
 *				    false
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_autosleep(const struct device *dev, bool enable)
{
	struct adxl372_data *data = dev->data;

	return data->hw_tf->write_reg_mask(dev, ADXL372_MEASURE,
					   ADXL372_MEASURE_AUTOSLEEP_MSK,
					   ADXL372_MEASURE_AUTOSLEEP_MODE(enable));
}

/**
 * Select the desired output signal bandwidth.
 * @param dev - The device structure.
 * @param bw - bandwidth.
 *		Accepted values: ADXL372_BW_200HZ
 *				 ADXL372_BW_400HZ
 *				 ADXL372_BW_800HZ
 *				 ADXL372_BW_1600HZ
 *				 ADXL372_BW_3200HZ
 *				 ADXL372_BW_LPF_DISABLED
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_bandwidth(const struct device *dev,
				 enum adxl372_bandwidth bw)
{
	int ret;
	uint8_t mask;
	struct adxl372_data *data = dev->data;

	if (bw == ADXL372_BW_LPF_DISABLED) {
		mask = ADXL372_POWER_CTL_LPF_DIS_MSK;
	} else {
		mask = 0U;
	}

	ret = data->hw_tf->write_reg_mask(dev, ADXL372_POWER_CTL,
					  ADXL372_POWER_CTL_LPF_DIS_MSK, mask);
	if (ret) {
		return ret;
	}

	return data->hw_tf->write_reg_mask(dev, ADXL372_MEASURE,
					   ADXL372_MEASURE_BANDWIDTH_MSK,
					   ADXL372_MEASURE_BANDWIDTH_MODE(bw));
}

/**
 * Select the desired high-pass filter corner.
 * @param dev - The device structure.
 * @param c - bandwidth.
 *		Accepted values: ADXL372_HPF_CORNER_0
 *				 ADXL372_HPF_CORNER_1
 *				 ADXL372_HPF_CORNER_2
 *				 ADXL372_HPF_CORNER_3
 *				 ADXL372_HPF_DISABLED
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_hpf_corner(const struct device *dev,
				  enum adxl372_hpf_corner c)
{

	int ret;
	uint8_t mask;
	struct adxl372_data *data = dev->data;

	if (c == ADXL372_HPF_DISABLED) {
		mask = ADXL372_POWER_CTL_HPF_DIS_MSK;
	} else {
		mask = 0U;
	}

	ret = data->hw_tf->write_reg_mask(dev, ADXL372_POWER_CTL,
					  ADXL372_POWER_CTL_HPF_DIS_MSK, mask);
	if (ret) {
		return ret;
	}

	return data->hw_tf->write_reg(dev, ADXL372_HPF, ADXL372_HPF_CORNER(c));
}


/**
 * Link/Loop Activity Processing.
 * @param dev - The device structure.
 * @param mode - Mode of operation.
 *		Accepted values: ADXL372_DEFAULT
 *				 ADXL372_LINKED
 *				 ADXL372_LOOPED
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_act_proc_mode(const struct device *dev,
				     enum adxl372_act_proc_mode mode)
{
	struct adxl372_data *data = dev->data;

	return data->hw_tf->write_reg_mask(dev, ADXL372_MEASURE,
					   ADXL372_MEASURE_LINKLOOP_MSK,
					   ADXL372_MEASURE_LINKLOOP_MODE(mode));
}

/**
 * Set Output data rate.
 * @param dev - The device structure.
 * @param odr - Output data rate.
 *		Accepted values: ADXL372_ODR_400HZ
 *				 ADXL372_ODR_800HZ
 *				 ADXL372_ODR_1600HZ
 *				 ADXL372_ODR_3200HZ
 *				 ADXL372_ODR_6400HZ
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_odr(const struct device *dev, enum adxl372_odr odr)
{
	struct adxl372_data *data = dev->data;

	return data->hw_tf->write_reg_mask(dev, ADXL372_TIMING,
					   ADXL372_TIMING_ODR_MSK,
					   ADXL372_TIMING_ODR_MODE(odr));
}

/**
 * Select instant on threshold
 * @param dev - The device structure.
 * @param mode - 0 = low threshold, 1 = high threshold.
 *		Accepted values: ADXL372_INSTANT_ON_LOW_TH
 *				 ADXL372_INSTANT_ON_HIGH_TH
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_instant_on_th(const struct device *dev,
				     enum adxl372_instant_on_th_mode mode)
{
	struct adxl372_data *data = dev->data;

	return data->hw_tf->write_reg_mask(dev, ADXL372_POWER_CTL,
					   ADXL372_POWER_CTL_INSTANT_ON_TH_MSK,
					   ADXL372_POWER_CTL_INSTANT_ON_TH_MODE(mode));
}

/**
 * Set the Timer Rate for Wake-Up Mode.
 * @param dev - The device structure.
 * @param wur - wake up mode rate
 *		Accepted values: ADXL372_WUR_52ms
 *				 ADXL372_WUR_104ms
 *				 ADXL372_WUR_208ms
 *				 ADXL372_WUR_512ms
 *				 ADXL372_WUR_2048ms
 *				 ADXL372_WUR_4096ms
 *				 ADXL372_WUR_8192ms
 *				 ADXL372_WUR_24576ms
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_wakeup_rate(const struct device *dev,
				   enum adxl372_wakeup_rate wur)
{
	struct adxl372_data *data = dev->data;

	return data->hw_tf->write_reg_mask(dev, ADXL372_TIMING,
					   ADXL372_TIMING_WAKE_UP_RATE_MSK,
					   ADXL372_TIMING_WAKE_UP_RATE_MODE(wur));
}

/**
 * Set the activity timer
 * @param dev - The device structure.
 * @param time - The value set in this register.
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_activity_time(const struct device *dev, uint8_t time)
{
	struct adxl372_data *data = dev->data;

	return data->hw_tf->write_reg(dev, ADXL372_TIME_ACT, time);
}

/**
 * Set the inactivity timer
 * @param dev - The device structure.
 * @param time - is the 16-bit value set by the TIME_INACT_L register
 *		 (eight LSBs) and the TIME_INACT_H register (eight MSBs).
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_inactivity_time(const struct device *dev,
				       uint16_t time)
{
	int ret;
	struct adxl372_data *data = dev->data;

	ret = data->hw_tf->write_reg(dev, ADXL372_TIME_INACT_H, time >> 8);
	if (ret) {
		return ret;
	}

	return data->hw_tf->write_reg(dev, ADXL372_TIME_INACT_L, time & 0xFF);
}

/**
 * Set the filter settling period.
 * @param dev - The device structure.
 * @param mode - settle period
 *		Accepted values: ADXL372_FILTER_SETTLE_370
 *				 ADXL372_FILTER_SETTLE_16
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_set_filter_settle(const struct device *dev,
				     enum adxl372_filter_settle mode)
{
	struct adxl372_data *data = dev->data;

	return data->hw_tf->write_reg_mask(dev, ADXL372_POWER_CTL,
					   ADXL372_POWER_CTL_FIL_SETTLE_MSK,
					   ADXL372_POWER_CTL_FIL_SETTLE_MODE(mode));
}

/**
 * Configure the INT1 and INT2 interrupt pins.
 * @param dev - The device structure.
 * @param int1 -  INT1 interrupt pins.
 * @param int2 -  INT2 interrupt pins.
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_interrupt_config(const struct device *dev,
				    uint8_t int1,
				    uint8_t int2)
{
	int ret;
	struct adxl372_data *data = dev->data;

	ret = data->hw_tf->write_reg(dev, ADXL372_INT1_MAP, int1);
	if (ret) {
		return ret;
	}

	return  data->hw_tf->write_reg(dev, ADXL372_INT2_MAP, int2);

}

/**
 * Get the STATUS, STATUS2, FIFO_ENTRIES and FIFO_ENTRIES2 registers data
 * @param dev - The device structure.
 * @param status1 - Data stored in the STATUS1 register
 * @param status2 - Data stored in the STATUS2 register
 * @param fifo_entries - Number of valid data samples present in the
 *			 FIFO buffer (0 to 512)
 * @return 0 in case of success, negative error code otherwise.
 */
int adxl372_get_status(const struct device *dev,
			   uint8_t *status1,
			   uint8_t *status2,
			   uint16_t *fifo_entries)
{
	struct adxl372_data *data = dev->data;
	uint8_t buf[4], length = 1U;
	int ret;

	if (status2) {
		length++;
	}

	if (fifo_entries) {
		length += 2U;
	}

	ret = data->hw_tf->read_reg_multiple(dev, ADXL372_STATUS_1, buf, length);

	*status1 = buf[0];

	if (status2) {
		*status2 = buf[1];
	}

	if (fifo_entries) {
		*fifo_entries = ((buf[2] & 0x3) << 8) | buf[3];
	}

	return ret;
}

/**
 * Software reset.
 * @param dev - The device structure.
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_reset(const struct device *dev)
{
	int ret;
	struct adxl372_data *data = dev->data;

	ret = adxl372_set_op_mode(dev, ADXL372_STANDBY);
	if (ret) {
		return ret;
	}
	/* Writing code 0x52 resets the device */
	ret = data->hw_tf->write_reg(dev, ADXL372_RESET, ADXL372_RESET_CODE);
	k_sleep(K_MSEC(1));

	return ret;
}

/**
 * Configure the operating parameters for the FIFO.
 * @param dev - The device structure.
 * @param mode - FIFO Mode. Specifies FIFO operating mode.
 *		Accepted values: ADXL372_FIFO_BYPASSED
 *				 ADXL372_FIFO_STREAMED
 *				 ADXL372_FIFO_TRIGGERED
 *				 ADXL372_FIFO_OLD_SAVED
 * @param format - FIFO Format. Specifies the data is stored in the FIFO buffer.
 *		Accepted values: ADXL372_XYZ_FIFO
 *				 ADXL372_X_FIFO
 *				 ADXL372_Y_FIFO
 *				 ADXL372_XY_FIFO
 *				 ADXL372_Z_FIFO
 *				 ADXL372_XZ_FIFO
 *				 ADXL372_YZ_FIFO
 *				 ADXL372_XYZ_PEAK_FIFO
 * @param fifo_samples - FIFO Samples. Watermark number of FIFO samples that
 *			triggers a FIFO_FULL condition when reached.
 *			Values range from 0 to 512.

 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_configure_fifo(const struct device *dev,
				  enum adxl372_fifo_mode mode,
				  enum adxl372_fifo_format format,
				  uint16_t fifo_samples)
{
	struct adxl372_data *data = dev->data;
	uint8_t fifo_config;
	int ret;

	if (fifo_samples > 512) {
		return -EINVAL;
	}

	/*
	 * All FIFO modes must be configured while in standby mode.
	 */
	ret = adxl372_set_op_mode(dev, ADXL372_STANDBY);
	if (ret) {
		return ret;
	}

	fifo_config = (ADXL372_FIFO_CTL_FORMAT_MODE(format) |
		       ADXL372_FIFO_CTL_MODE_MODE(mode) |
		       ADXL372_FIFO_CTL_SAMPLES_MODE(fifo_samples));

	ret = data->hw_tf->write_reg(dev, ADXL372_FIFO_CTL, fifo_config);
	if (ret) {
		return ret;
	}
	ret = data->hw_tf->write_reg(dev, ADXL372_FIFO_SAMPLES, fifo_samples & 0xFF);
	if (ret) {
		return ret;
	}

	data->fifo_config.fifo_format = format;
	data->fifo_config.fifo_mode = mode;
	data->fifo_config.fifo_samples = fifo_samples;

	return 0;
}

/**
 * Retrieve 3-axis acceleration data
 * @param dev - The device structure.
 * @param maxpeak - Retrieve the highest magnitude (x, y, z) sample recorded
 *		    since the last read of the MAXPEAK registers
 * @param accel_data - pointer to a variable of type adxl372_xyz_accel_data
 *		      where (x, y, z) acceleration data will be stored.
 * @return 0 in case of success, negative error code otherwise.
 */
static int adxl372_get_accel_data(const struct device *dev, bool maxpeak,
				  struct adxl372_xyz_accel_data *accel_data)
{
	struct adxl372_data *data = dev->data;
	uint8_t buf[6];
	uint8_t status1;
	int ret;

	if (!IS_ENABLED(CONFIG_ADXL372_TRIGGER)) {
		do {
			adxl372_get_status(dev, &status1, NULL, NULL);
		} while (!(ADXL372_STATUS_1_DATA_RDY(status1)));
	}

	ret = data->hw_tf->read_reg_multiple(dev, maxpeak ? ADXL372_X_MAXPEAK_H :
					     ADXL372_X_DATA_H, buf, 6);

	accel_data->x = (buf[0] << 8) | (buf[1] & 0xF0);
	accel_data->y = (buf[2] << 8) | (buf[3] & 0xF0);
	accel_data->z = (buf[4] << 8) | (buf[5] & 0xF0);

	return ret;
}

static int adxl372_attr_set_odr(const struct device *dev,
				enum sensor_channel chan,
				enum sensor_attribute attr,
				const struct sensor_value *val)
{
	enum adxl372_odr odr;

	switch (val->val1) {
	case 400:
		odr = ADXL372_ODR_400HZ;
		break;
	case 800:
		odr = ADXL372_ODR_800HZ;
		break;
	case 1600:
		odr = ADXL372_ODR_1600HZ;
		break;
	case 3200:
		odr = ADXL372_ODR_3200HZ;
		break;
	case 6400:
		odr = ADXL372_ODR_6400HZ;
		break;
	default:
		return -EINVAL;
	}

	return adxl372_set_odr(dev, odr);
}

static int adxl372_attr_set_thresh(const struct device *dev,
				   enum sensor_channel chan,
				   enum sensor_attribute attr,
				   const struct sensor_value *val)
{
	const struct adxl372_dev_config *cfg = dev->config;
	struct adxl372_activity_threshold threshold;
	int64_t llvalue;
	int32_t value;
	int64_t micro_ms2 = val->val1 * 1000000LL + val->val2;
	uint8_t reg;

	llvalue = llabs((micro_ms2 * 10) / SENSOR_G);

	if (llvalue > 2047) {
		return -EINVAL;
	}

	value = (int32_t) llvalue;

	threshold.thresh = value;
	threshold.enable = cfg->activity_th.enable;
	threshold.referenced = cfg->activity_th.referenced;

	if (attr ==  SENSOR_ATTR_UPPER_THRESH) {
		reg = ADXL372_X_THRESH_ACT_H;
	} else {
		reg = ADXL372_X_THRESH_INACT_H;
	}

	switch (chan) {
	case SENSOR_CHAN_ACCEL_X:
		return adxl372_set_activity_threshold(dev, reg, &threshold);
	case SENSOR_CHAN_ACCEL_Y:
		return adxl372_set_activity_threshold(dev, reg + 2, &threshold);
	case SENSOR_CHAN_ACCEL_Z:
		return adxl372_set_activity_threshold(dev, reg + 4, &threshold);
	case SENSOR_CHAN_ACCEL_XYZ:
		return adxl372_set_activity_threshold_xyz(dev, reg, &threshold);
	default:
		LOG_ERR("attr_set() not supported on this channel");
		return -ENOTSUP;
	}
}

static int adxl372_attr_set(const struct device *dev,
			    enum sensor_channel chan,
			    enum sensor_attribute attr,
			    const struct sensor_value *val)
{
	switch (attr) {
	case SENSOR_ATTR_SAMPLING_FREQUENCY:
		return adxl372_attr_set_odr(dev, chan, attr, val);
	case SENSOR_ATTR_UPPER_THRESH:
	case SENSOR_ATTR_LOWER_THRESH:
		return adxl372_attr_set_thresh(dev, chan, attr, val);
	default:
		return -ENOTSUP;
	}
}

static int adxl372_sample_fetch(const struct device *dev,
				enum sensor_channel chan)
{
	const struct adxl372_dev_config *cfg = dev->config;
	struct adxl372_data *data = dev->data;

	return adxl372_get_accel_data(dev, cfg->max_peak_detect_mode,
				      &data->sample);
}

static void adxl372_accel_convert(struct sensor_value *val, int16_t value)
{
	/*
	 * Sensor resolution is 100mg/LSB, 12-bit value needs to be right
	 * shifted by 4 or divided by 16. Overall this results in a scale of 160
	 */
	int32_t micro_ms2 = value * (SENSOR_G / (16 * 1000 / 100));

	val->val1 = micro_ms2 / 1000000;
	val->val2 = micro_ms2 % 1000000;
}

static int adxl372_channel_get(const struct device *dev,
			       enum sensor_channel chan,
			       struct sensor_value *val)
{
	struct adxl372_data *data = dev->data;

	switch (chan) {
	case SENSOR_CHAN_ACCEL_X:
		adxl372_accel_convert(val, data->sample.x);
		break;
	case SENSOR_CHAN_ACCEL_Y:
		adxl372_accel_convert(val, data->sample.y);
		break;
	case SENSOR_CHAN_ACCEL_Z:
		adxl372_accel_convert(val, data->sample.z);
		break;
	case SENSOR_CHAN_ACCEL_XYZ:
		adxl372_accel_convert(val++, data->sample.x);
		adxl372_accel_convert(val++, data->sample.y);
		adxl372_accel_convert(val, data->sample.z);
		break;
	default:
		return -ENOTSUP;
	}

	return 0;
}

static const struct sensor_driver_api adxl372_api_funcs = {
	.attr_set     = adxl372_attr_set,
	.sample_fetch = adxl372_sample_fetch,
	.channel_get  = adxl372_channel_get,
#ifdef CONFIG_ADXL372_TRIGGER
	.trigger_set = adxl372_trigger_set,
#endif

};

static int adxl372_probe(const struct device *dev)
{
	const struct adxl372_dev_config *cfg = dev->config;
	struct adxl372_data *data = dev->data;
	uint8_t dev_id, part_id;
	int ret;

	ret = data->hw_tf->read_reg(dev, ADXL372_DEVID, &dev_id);
	if (ret) {
		return ret;
	}
	ret = data->hw_tf->read_reg(dev, ADXL372_PARTID, &part_id);
	if (ret) {
		return ret;
	}

	if (dev_id != ADXL372_DEVID_VAL || part_id != ADXL372_PARTID_VAL) {
		LOG_ERR("failed to read id (0x%X:0x%X)", dev_id, part_id);
		return -ENODEV;
	}

#ifdef CONFIG_ADXL372_TRIGGER
	data->act_proc_mode = ADXL372_LINKED,
#else
	data->act_proc_mode = ADXL372_LOOPED,
#endif

	/* Device settings */
	ret = adxl372_set_op_mode(dev, ADXL372_STANDBY);
	if (ret) {
		return ret;
	}

	ret = adxl372_reset(dev);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_hpf_corner(dev, cfg->hpf);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_bandwidth(dev, cfg->bw);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_odr(dev, cfg->odr);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_wakeup_rate(dev, cfg->wur);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_autosleep(dev, cfg->autosleep);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_instant_on_th(dev, cfg->th_mode);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_activity_threshold_xyz(dev, ADXL372_X_THRESH_ACT_H,
						 &cfg->activity_th);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_activity_threshold_xyz(dev, ADXL372_X_THRESH_INACT_H,
						 &cfg->inactivity_th);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_activity_time(dev, cfg->activity_time);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_inactivity_time(dev, cfg->inactivity_time);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_filter_settle(dev, cfg->filter_settle);
	if (ret) {
		return ret;
	}

	ret = adxl372_configure_fifo(dev, cfg->fifo_config.fifo_mode,
				     cfg->fifo_config.fifo_format,
				     cfg->fifo_config.fifo_samples);
	if (ret) {
		return ret;
	}

#ifdef CONFIG_ADXL372_TRIGGER
	if (adxl372_init_interrupt(dev) < 0) {
		LOG_ERR("Failed to initialize interrupt!");
		return -EIO;
	}
#endif

	ret = adxl372_interrupt_config(dev, cfg->int1_config, cfg->int2_config);
	if (ret) {
		return ret;
	}

	ret = adxl372_set_op_mode(dev, cfg->op_mode);
	if (ret) {
		return ret;
	}

	return adxl372_set_act_proc_mode(dev, data->act_proc_mode);
}

static int adxl372_init(const struct device *dev)
{
	int ret;
	const struct adxl372_dev_config *cfg = dev->config;

	ret = cfg->bus_init(dev);
	if (ret < 0) {
		LOG_ERR("Failed to initialize sensor bus");
		return ret;
	}

	if (adxl372_probe(dev) < 0) {
		return -ENODEV;
	}

	return 0;
}

#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
#warning "ADXL372 driver enabled without any devices"
#endif

/*
 * Device creation macro, shared by ADXL372_DEFINE_SPI() and
 * ADXL372_DEFINE_I2C().
 */

#define ADXL372_DEVICE_INIT(inst)					\
	SENSOR_DEVICE_DT_INST_DEFINE(inst,				\
			      adxl372_init,				\
			      NULL,					\
			      &adxl372_data_##inst,			\
			      &adxl372_config_##inst,			\
			      POST_KERNEL,				\
			      CONFIG_SENSOR_INIT_PRIORITY,		\
			      &adxl372_api_funcs);

/*
 * Instantiation macros used when a device is on a SPI bus.
 */

#ifdef CONFIG_ADXL372_TRIGGER
#define ADXL372_CFG_IRQ(inst) \
		.interrupt = GPIO_DT_SPEC_INST_GET(inst, int1_gpios),
#else
#define ADXL372_CFG_IRQ(inst)
#endif /* CONFIG_ADXL372_TRIGGER */

#define ADXL372_CONFIG(inst)								\
		.bw = DT_INST_PROP(inst, bw),						\
		.hpf = DT_INST_PROP(inst, hpf),						\
		.odr = DT_INST_PROP(inst, odr),						\
		.max_peak_detect_mode = IS_ENABLED(CONFIG_ADXL372_PEAK_DETECT_MODE),	\
		.th_mode = ADXL372_INSTANT_ON_LOW_TH,					\
		.autosleep = false,							\
		.wur = ADXL372_WUR_52ms,						\
		.activity_th.thresh = CONFIG_ADXL372_ACTIVITY_THRESHOLD / 100,		\
		.activity_th.referenced =						\
			IS_ENABLED(CONFIG_ADXL372_REFERENCED_ACTIVITY_DETECTION_MODE),	\
		.activity_th.enable = 1,						\
		.activity_time = CONFIG_ADXL372_ACTIVITY_TIME,				\
		.inactivity_th.thresh = CONFIG_ADXL372_INACTIVITY_THRESHOLD / 100,	\
		.inactivity_th.referenced =						\
			IS_ENABLED(CONFIG_ADXL372_REFERENCED_ACTIVITY_DETECTION_MODE),	\
		.inactivity_th.enable = 1,						\
		.inactivity_time = CONFIG_ADXL372_INACTIVITY_TIME,			\
		.filter_settle = ADXL372_FILTER_SETTLE_370,				\
		.fifo_config.fifo_mode = ADXL372_FIFO_STREAMED,				\
		.fifo_config.fifo_format = ADXL372_XYZ_PEAK_FIFO,			\
		.fifo_config.fifo_samples = 128,					\
		.op_mode = ADXL372_FULL_BW_MEASUREMENT,					\

#define ADXL372_CONFIG_SPI(inst)					\
	{								\
		.bus_init = adxl372_spi_init,				\
		.spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8) |	\
					SPI_TRANSFER_MSB, 0),		\
		ADXL372_CONFIG(inst)					\
		COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios),	\
		(ADXL372_CFG_IRQ(inst)), ())				\
	}

#define ADXL372_DEFINE_SPI(inst)					\
	static struct adxl372_data adxl372_data_##inst;			\
	static const struct adxl372_dev_config adxl372_config_##inst =	\
		ADXL372_CONFIG_SPI(inst);				\
	ADXL372_DEVICE_INIT(inst)

/*
 * Instantiation macros used when a device is on an I2C bus.
 */

#define ADXL372_CONFIG_I2C(inst)					\
	{								\
		.bus_init = adxl372_i2c_init,				\
		.i2c = I2C_DT_SPEC_INST_GET(inst),			\
		ADXL372_CONFIG(inst)					\
		COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios),	\
		(ADXL372_CFG_IRQ(inst)), ())				\
	}

#define ADXL372_DEFINE_I2C(inst)					\
	static struct adxl372_data adxl372_data_##inst;			\
	static const struct adxl372_dev_config adxl372_config_##inst =	\
		ADXL372_CONFIG_I2C(inst);				\
	ADXL372_DEVICE_INIT(inst)
/*
 * Main instantiation macro. Use of COND_CODE_1() selects the right
 * bus-specific macro at preprocessor time.
 */

#define ADXL372_DEFINE(inst)						\
	COND_CODE_1(DT_INST_ON_BUS(inst, spi),				\
		    (ADXL372_DEFINE_SPI(inst)),				\
		    (ADXL372_DEFINE_I2C(inst)))

DT_INST_FOREACH_STATUS_OKAY(ADXL372_DEFINE)
