/* * Copyright (c) 2023 Analog Devices Inc. * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT adi_adxl367 #include #include #include #include #include #include #include #include #include #include "adxl367.h" LOG_MODULE_REGISTER(ADXL367, CONFIG_SENSOR_LOG_LEVEL); static const uint8_t adxl367_scale_mul[3] = {1, 2, 4}; static uint8_t samples_per_set; /** * @brief Configures activity detection. * * @param dev - The device structure. * @param th - Structure holding the activity threshold information: * Enable/Disable Activity detection * Enable/Disable Referenced Activity detection * Set Threshold value * @return 0 in case of success, negative error code otherwise. */ static int adxl367_setup_activity_detection(const struct device *dev, const struct adxl367_activity_threshold *th) { struct adxl367_data *data = dev->data; int ret; ret = data->hw_tf->write_reg_mask(dev, ADXL367_ACT_INACT_CTL, ADXL367_ACT_INACT_CTL_ACT_EN_MSK | ADXL367_ACT_INACT_CTL_ACT_REF_MSK, FIELD_PREP(ADXL367_ACT_INACT_CTL_ACT_EN_MSK, th->enable) | FIELD_PREP(ADXL367_ACT_INACT_CTL_ACT_REF_MSK, th->referenced)); if (ret != 0) { return ret; } ret = data->hw_tf->write_reg_mask(dev, ADXL367_THRESH_ACT_H, ADXL367_THRESH_H_MSK, FIELD_PREP(ADXL367_THRESH_H_MSK, th->value >> 6)); if (ret != 0) { return ret; } return data->hw_tf->write_reg_mask(dev, ADXL367_THRESH_ACT_L, ADXL367_THRESH_L_MSK, FIELD_PREP(ADXL367_THRESH_L_MSK, th->value & 0x3F)); } /** * @brief Configures activity detection. * * @param dev - The device structure. * @param th - Structure holding the inactivity threshold information: * Enable/Disable inactivity detection * Enable/Disable Referenced inactivity detection * Set Threshold value * * @return 0 in case of success, negative error code otherwise. */ static int adxl367_setup_inactivity_detection(const struct device *dev, const struct adxl367_activity_threshold *th) { struct adxl367_data *data = dev->data; int ret; ret = data->hw_tf->write_reg_mask(dev, ADXL367_ACT_INACT_CTL, ADXL367_ACT_INACT_CTL_INACT_EN_MSK | ADXL367_ACT_INACT_CTL_INACT_REF_MSK, FIELD_PREP(ADXL367_ACT_INACT_CTL_INACT_EN_MSK, th->enable) | FIELD_PREP(ADXL367_ACT_INACT_CTL_INACT_REF_MSK, th->referenced)); if (ret != 0) { return ret; } ret = data->hw_tf->write_reg_mask(dev, ADXL367_THRESH_INACT_H, ADXL367_THRESH_H_MSK, FIELD_PREP(ADXL367_THRESH_H_MSK, th->value >> 6)); if (ret != 0) { return ret; } return data->hw_tf->write_reg_mask(dev, ADXL367_THRESH_INACT_L, ADXL367_THRESH_L_MSK, FIELD_PREP(ADXL367_THRESH_L_MSK, th->value & 0x3F)); } /** * @brief Set the mode of operation. * * @param dev - The device structure. * @param op_mode - Mode of operation. * Accepted values: ADXL367_STANDBY * ADXL367_MEASURE * * @return 0 in case of success, negative error code otherwise. */ static int adxl367_set_op_mode(const struct device *dev, enum adxl367_op_mode op_mode) { struct adxl367_data *data = dev->data; int ret; ret = data->hw_tf->write_reg_mask(dev, ADXL367_POWER_CTL, ADXL367_POWER_CTL_MEASURE_MSK, FIELD_PREP(ADXL367_POWER_CTL_MEASURE_MSK, op_mode)); if (ret != 0) { return ret; } if (op_mode == ADXL367_MEASURE) /* Wait 100 ms to allow the acceleration outputs to settle */ k_sleep(K_MSEC(100)); return 0; } /** * @brief 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 adxl367_set_autosleep(const struct device *dev, bool enable) { struct adxl367_data *data = dev->data; return data->hw_tf->write_reg_mask(dev, ADXL367_POWER_CTL, ADXL367_POWER_CTL_AUTOSLEEP_MSK, FIELD_PREP(ADXL367_POWER_CTL_AUTOSLEEP_MSK, enable)); } /** * @brief Noise Mode. When set to 1, low noise mode is enabled * * @param dev - The device structure. * @param enable - Accepted values: true * false * * @return 0 in case of success, negative error code otherwise. */ static int adxl367_set_low_noise(const struct device *dev, bool enable) { struct adxl367_data *data = dev->data; return data->hw_tf->write_reg_mask(dev, ADXL367_POWER_CTL, ADXL367_POWER_CTL_NOISE_MSK, FIELD_PREP(ADXL367_POWER_CTL_NOISE_MSK, enable)); } /** * @brief Link/Loop Activity Processing. * * @param dev - The device structure. * @param mode - Mode of operation. * Accepted values: ADXL367_DEFAULT * ADXL367_LINKED * ADXL367_LOOPED * * @return 0 in case of success, negative error code otherwise. */ static int adxl367_set_act_proc_mode(const struct device *dev, enum adxl367_act_proc_mode mode) { struct adxl367_data *data = dev->data; return data->hw_tf->write_reg_mask(dev, ADXL367_ACT_INACT_CTL, ADXL367_ACT_INACT_CTL_LINKLOOP_MSK, FIELD_PREP(ADXL367_ACT_INACT_CTL_LINKLOOP_MSK, mode)); } /** * @brief Selects the Output Data Rate of the device. * @param dev - The device structure. * @param odr - Output Data Rate option. * Accepted values: ADXL367_ODR_12P5HZ, * ADXL367_ODR_25HZ, * ADXL367_ODR_50HZ, * ADXL367_ODR_100HZ, * ADXL367_ODR_200HZ, * ADXL367_ODR_400HZ * @return 0 in case of success, negative error code otherwise. */ int adxl367_set_output_rate(const struct device *dev, enum adxl367_odr odr) { struct adxl367_data *data = dev->data; return data->hw_tf->write_reg_mask(dev, ADXL367_FILTER_CTL, ADXL367_FILTER_CTL_ODR_MSK, FIELD_PREP(ADXL367_FILTER_CTL_ODR_MSK, odr)); } /** * @brief Selects the measurement range. * * @param dev - The device structure. * @param range - Range option. * Accepted values: ADXL367_2G_RANGE, +/- 2g * ADXL367_4G_RANGE, +/- 4g * ADXL367_8G_RANGE +/- 8g * * @return 0 in case of success, negative error code otherwise. */ int adxl367_set_range(const struct device *dev, enum adxl367_range range) { struct adxl367_data *data = dev->data; return data->hw_tf->write_reg_mask(dev, ADXL367_FILTER_CTL, ADXL367_FILTER_CTL_RANGE_MSK, FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MSK, range)); } /** * @brief 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 adxl367_set_activity_time(const struct device *dev, uint8_t time) { struct adxl367_data *data = dev->data; return data->hw_tf->write_reg(dev, ADXL367_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 adxl367_set_inactivity_time(const struct device *dev, uint16_t time) { int ret; struct adxl367_data *data = dev->data; ret = data->hw_tf->write_reg(dev, ADXL367_TIME_INACT_H, time >> 8); if (ret != 0) { return ret; } return data->hw_tf->write_reg(dev, ADXL367_TIME_INACT_L, time & 0xFF); } /** * @brief Performs self test. * * @param dev - The device structure. * * @return 0 in case of success, negative error code otherwise. */ int adxl367_self_test(const struct device *dev) { int ret; struct adxl367_data *data = dev->data; const struct adxl367_dev_config *cfg = dev->config; int16_t x_axis_1, x_axis_2, dif, min, max; uint8_t read_val[2]; uint32_t st_delay_ms; /* 4 / ODR value in ms */ switch (cfg->odr) { case ADXL367_ODR_12P5HZ: st_delay_ms = 320; break; case ADXL367_ODR_25HZ: st_delay_ms = 160; break; case ADXL367_ODR_50HZ: st_delay_ms = 80; break; case ADXL367_ODR_100HZ: st_delay_ms = 40; break; case ADXL367_ODR_200HZ: st_delay_ms = 20; break; case ADXL367_ODR_400HZ: st_delay_ms = 10; break; default: return -EINVAL; } ret = adxl367_set_op_mode(dev, ADXL367_MEASURE); if (ret != 0) { return ret; } ret = data->hw_tf->write_reg_mask(dev, ADXL367_SELF_TEST, ADXL367_SELF_TEST_ST_MSK, FIELD_PREP(ADXL367_SELF_TEST_ST_MSK, 1)); if (ret != 0) { return ret; } /* 4 / ODR */ k_sleep(K_MSEC(st_delay_ms)); ret = data->hw_tf->read_reg_multiple(dev, ADXL367_X_DATA_H, read_val, 2); if (ret != 0) { return ret; } x_axis_1 = ((int16_t)read_val[0] << 6) + (read_val[1] >> 2); /* extend sign to 16 bits */ if ((x_axis_1 & BIT(13)) != 0) { x_axis_1 |= GENMASK(15, 14); } ret = data->hw_tf->write_reg_mask(dev, ADXL367_SELF_TEST, ADXL367_SELF_TEST_ST_FORCE_MSK, FIELD_PREP(ADXL367_SELF_TEST_ST_FORCE_MSK, 1)); if (ret != 0) { return ret; } /* 4 / ODR */ k_sleep(K_MSEC(st_delay_ms)); ret = data->hw_tf->read_reg_multiple(dev, ADXL367_X_DATA_H, read_val, 2); if (ret != 0) { return ret; } x_axis_2 = ((int16_t)read_val[0] << 6) + (read_val[1] >> 2); /* extend sign to 16 bits */ if ((x_axis_2 & BIT(13)) != 0) x_axis_2 |= GENMASK(15, 14); ret = adxl367_set_op_mode(dev, ADXL367_STANDBY); if (ret != 0) { return ret; } ret = data->hw_tf->write_reg_mask(dev, ADXL367_SELF_TEST, ADXL367_SELF_TEST_ST_FORCE_MSK | ADXL367_SELF_TEST_ST_MSK, FIELD_PREP(ADXL367_SELF_TEST_ST_FORCE_MSK, 0) | FIELD_PREP(ADXL367_SELF_TEST_ST_MSK, 0)); if (ret != 0) { return ret; } dif = x_axis_2 - x_axis_1; min = ADXL367_SELF_TEST_MIN * adxl367_scale_mul[data->range]; max = ADXL367_SELF_TEST_MAX * adxl367_scale_mul[data->range]; if ((dif >= min) && (dif <= max)) { LOG_INF("ADXL367 passed self-test\n"); ret = 0; } else { LOG_ERR("ADXL367 failed self-test\n"); ret = -EINVAL; } return ret; } /** * @brief Enables temperature reading. * * @param dev - The device structure. * @param enable - 1 - ENABLE * 2 - DISABLE * * @return 0 in case of success, negative error code otherwise. */ int adxl367_temp_read_en(const struct device *dev, bool enable) { struct adxl367_data *data = dev->data; return data->hw_tf->write_reg_mask(dev, ADXL367_TEMP_CTL, ADXL367_TEMP_EN_MSK, FIELD_PREP(ADXL367_TEMP_EN_MSK, enable)); } /** * @brief Sets the number of FIFO sample sets. * * @param dev - The device structure. * @param sets_nb - Sample sets number. For example, if ADXL367_FIFO_FORMAT_XYZ * is selected, a value of 2 will represent 6 entries. * * @return 0 in case of success, negative error code otherwise. */ int adxl367_set_fifo_sample_sets_nb(const struct device *dev, uint16_t sets_nb) { struct adxl367_data *data = dev->data; int ret; uint8_t fifo_samples_msb = sets_nb & BIT(9) ? 1U : 0U; /* bit 9 goes to FIFO_SAMPLES from ADXL367_FIFO_CONTROL */ ret = data->hw_tf->write_reg_mask(dev, ADXL367_FIFO_CONTROL, ADXL367_FIFO_CONTROL_FIFO_SAMPLES_MSK, FIELD_PREP(ADXL367_FIFO_CONTROL_FIFO_SAMPLES_MSK, fifo_samples_msb)); if (ret != 0) { return ret; } /* write last 8 bits to ADXL367_FIFO_SAMPLES */ return data->hw_tf->write_reg(dev, ADXL367_FIFO_SAMPLES, sets_nb & 0xFF); } /** * @brief Sets FIFO mode. * * @param dev - The device structure. * @param mode - FIFO mode. * Accepted values: ADXL367_FIFO_DISABLED, * ADXL367_OLDEST_SAVED, * ADXL367_STREAM_MODE, * ADXL367_TRIGGERED_MODE * * @return 0 in case of success, negative error code otherwise. */ int adxl367_set_fifo_mode(const struct device *dev, enum adxl367_fifo_mode mode) { struct adxl367_data *data = dev->data; return data->hw_tf->write_reg_mask(dev, ADXL367_FIFO_CONTROL, ADXL367_FIFO_CONTROL_FIFO_MODE_MSK, FIELD_PREP(ADXL367_FIFO_CONTROL_FIFO_MODE_MSK, mode)); } /** * @brief Sets FIFO read mode. * * @param dev - The device structure. * @param read_mode - FIFO read mode. * Accepted values: ADXL367_12B_CHID, * ADXL367_8B, * ADXL367_12B, * ADXL367_14B_CHID * * @return 0 in case of success, negative error code otherwise. */ int adxl367_set_fifo_read_mode(const struct device *dev, enum adxl367_fifo_read_mode read_mode) { struct adxl367_data *data = dev->data; return data->hw_tf->write_reg_mask(dev, ADXL367_ADC_CTL, ADXL367_FIFO_8_12BIT_MSK, FIELD_PREP(ADXL367_FIFO_8_12BIT_MSK, read_mode)); } /** * @brief Sets FIFO format. * * @param dev - The device structure. * @param format - FIFO format. * Accepted values: 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 * * @return 0 in case of success, negative error code otherwise. */ int adxl367_set_fifo_format(const struct device *dev, enum adxl367_fifo_format format) { int ret; struct adxl367_data *data = dev->data; ret = data->hw_tf->write_reg_mask(dev, ADXL367_FIFO_CONTROL, ADXL367_FIFO_CONTROL_FIFO_CHANNEL_MSK, FIELD_PREP(ADXL367_FIFO_CONTROL_FIFO_CHANNEL_MSK, format)); if (ret != 0) { return ret; } switch (format) { case ADXL367_FIFO_FORMAT_XYZ: samples_per_set = 3; break; case ADXL367_FIFO_FORMAT_X: case ADXL367_FIFO_FORMAT_Y: case ADXL367_FIFO_FORMAT_Z: samples_per_set = 1; break; case ADXL367_FIFO_FORMAT_XYZT: case ADXL367_FIFO_FORMAT_XYZA: samples_per_set = 4; break; case ADXL367_FIFO_FORMAT_XT: case ADXL367_FIFO_FORMAT_YT: case ADXL367_FIFO_FORMAT_ZT: case ADXL367_FIFO_FORMAT_XA: case ADXL367_FIFO_FORMAT_YA: case ADXL367_FIFO_FORMAT_ZA: samples_per_set = 2; break; default: return -EINVAL; } return 0; } /** * @brief Configures the FIFO feature. Uses ADXL367_14B_CHID read mode as * default. * * @param dev - The device structure. * @param mode - FIFO mode selection. * Example: ADXL367_FIFO_DISABLED, * ADXL367_OLDEST_SAVED, * ADXL367_STREAM_MODE, * ADXL367_TRIGGERED_MODE * @param format - FIFO format selection. * Example: 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 * @param read_mode - FIFO read mode. * Accepted values: ADXL367_12B_CHID, * ADXL367_8B, * ADXL367_12B, * ADXL367_14B_CHID * @param sets_nb - Specifies the number of samples sets to store in the FIFO. * * @return 0 in case of success, negative error code otherwise. */ int adxl367_fifo_setup(const struct device *dev, enum adxl367_fifo_mode mode, enum adxl367_fifo_format format, enum adxl367_fifo_read_mode read_mode, uint8_t sets_nb) { int ret; ret = adxl367_set_fifo_mode(dev, mode); if (ret != 0) { return ret; } ret = adxl367_set_fifo_format(dev, format); if (ret != 0) { return ret; } ret = adxl367_set_fifo_sample_sets_nb(dev, sets_nb); if (ret != 0) { return ret; } return adxl367_set_fifo_read_mode(dev, read_mode); } /** * @brief Software reset. * * @param dev - The device structure. * * @return 0 in case of success, negative error code otherwise. */ static int adxl367_reset(const struct device *dev) { int ret; struct adxl367_data *data = dev->data; ret = adxl367_set_op_mode(dev, ADXL367_STANDBY); if (ret != 0) { return ret; } /* Writing code 0x52 resets the device */ ret = data->hw_tf->write_reg(dev, ADXL367_SOFT_RESET, ADXL367_RESET_CODE); if (ret != 0) { return ret; } /* Delay required after performing software reset */ k_sleep(K_MSEC(8)); return ret; } /** * @brief Reads the 3-axis raw data from the accelerometer. * * @param dev - The device structure. * @param accel_data - store the XYZ axis accelerometer data. * * @return 0 in case of success, negative error code otherwise. */ int adxl367_get_accel_data(const struct device *dev, struct adxl367_xyz_accel_data *accel_data) { int ret; uint8_t xyz_values[6] = { 0 }; uint8_t reg_data, nready = 1U; struct adxl367_data *data = dev->data; while (nready != 0) { ret = data->hw_tf->read_reg(dev, ADXL367_STATUS, ®_data); if (ret != 0) { return ret; } if ((reg_data & ADXL367_STATUS_DATA_RDY) != 0) { nready = 0U; } } ret = data->hw_tf->read_reg_multiple(dev, ADXL367_X_DATA_H, xyz_values, 6); if (ret != 0) { return ret; } /* result is 14 bits long, ignore last 2 bits from low byte */ accel_data->x = ((int16_t)xyz_values[0] << 6) + (xyz_values[1] >> 2); accel_data->y = ((int16_t)xyz_values[2] << 6) + (xyz_values[3] >> 2); accel_data->z = ((int16_t)xyz_values[4] << 6) + (xyz_values[5] >> 2); /* extend sign to 16 bits */ if ((accel_data->x & BIT(13)) != 0) { accel_data->x |= GENMASK(15, 14); } if ((accel_data->y & BIT(13)) != 0) { accel_data->y |= GENMASK(15, 14); } if ((accel_data->z & BIT(13)) != 0) { accel_data->z |= GENMASK(15, 14); } return 0; } /** * @brief Reads the raw temperature of the device. If ADXL367_TEMP_EN is not * set, use adxl367_temp_read_en() first to enable temperature reading. * * @param dev - The device structure. * @param raw_temp - Raw value of temperature. * * @return 0 in case of success, negative error code otherwise. */ int adxl367_get_temp_data(const struct device *dev, int16_t *raw_temp) { int ret; uint8_t temp[2] = { 0 }; uint8_t reg_data, nready = 1U; struct adxl367_data *data = dev->data; while (nready != 0) { ret = data->hw_tf->read_reg(dev, ADXL367_STATUS, ®_data); if (ret != 0) { return ret; } if ((reg_data & ADXL367_STATUS_DATA_RDY) != 0) { nready = 0U; } } ret = data->hw_tf->read_reg_multiple(dev, ADXL367_TEMP_H, temp, 2); if (ret != 0) { return ret; } *raw_temp = ((int16_t)temp[0] << 6) + (temp[1] >> 2); /* extend sign to 16 bits */ if ((*raw_temp & BIT(13)) != 0) { *raw_temp |= GENMASK(15, 14); } return 0; } static int adxl367_attr_set_thresh(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { const struct adxl367_dev_config *cfg = dev->config; struct adxl367_activity_threshold threshold; int64_t llvalue; int32_t value; int64_t micro_ms2 = val->val1 * 1000000LL + val->val2; llvalue = llabs((micro_ms2 * 10) / SENSOR_G); value = (int32_t) llvalue; threshold.value = value; threshold.enable = cfg->activity_th.enable; threshold.referenced = cfg->activity_th.referenced; switch (chan) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: case SENSOR_CHAN_ACCEL_XYZ: if (attr == SENSOR_ATTR_UPPER_THRESH) { return adxl367_setup_activity_detection(dev, &threshold); } else { return adxl367_setup_inactivity_detection(dev, &threshold); } default: LOG_ERR("attr_set() not supported on this channel"); return -ENOTSUP; } } static int adxl367_attr_set_odr(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { enum adxl367_odr odr; switch (val->val1) { case 12: case 13: odr = ADXL367_ODR_12P5HZ; break; case 25: odr = ADXL367_ODR_25HZ; break; case 50: odr = ADXL367_ODR_50HZ; break; case 100: odr = ADXL367_ODR_100HZ; break; case 200: odr = ADXL367_ODR_200HZ; break; case 400: odr = ADXL367_ODR_400HZ; break; default: return -EINVAL; } return adxl367_set_output_rate(dev, odr); } static int adxl367_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 adxl367_attr_set_odr(dev, chan, attr, val); case SENSOR_ATTR_UPPER_THRESH: case SENSOR_ATTR_LOWER_THRESH: return adxl367_attr_set_thresh(dev, chan, attr, val); default: return -ENOTSUP; } } static int adxl367_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct adxl367_data *data = dev->data; int ret; ret = adxl367_get_accel_data(dev, &data->sample); if (ret != 0) { return ret; } return adxl367_get_temp_data(dev, &data->temp_val); } static void adxl367_accel_convert(const struct device *dev, struct sensor_value *val, int16_t value) { struct adxl367_data *data = dev->data; int64_t micro_ms2 = value * (SENSOR_G * 250 / 10000 * adxl367_scale_mul[data->range] / 1000); val->val1 = micro_ms2 / 1000000; val->val2 = micro_ms2 % 1000000; } static void adxl367_temp_convert(struct sensor_value *val, int16_t value) { int64_t temp_data = (value + ADXL367_TEMP_OFFSET) * ADXL367_TEMP_SCALE; val->val1 = temp_data / ADXL367_TEMP_SCALE_DIV; val->val2 = temp_data % ADXL367_TEMP_SCALE_DIV; } static int adxl367_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct adxl367_data *data = dev->data; switch (chan) { case SENSOR_CHAN_ACCEL_X: adxl367_accel_convert(dev, val, data->sample.x); break; case SENSOR_CHAN_ACCEL_Y: adxl367_accel_convert(dev, val, data->sample.y); break; case SENSOR_CHAN_ACCEL_Z: adxl367_accel_convert(dev, val, data->sample.z); break; case SENSOR_CHAN_ACCEL_XYZ: adxl367_accel_convert(dev, val++, data->sample.x); adxl367_accel_convert(dev, val++, data->sample.y); adxl367_accel_convert(dev, val, data->sample.z); break; case SENSOR_CHAN_DIE_TEMP: adxl367_temp_convert(val, data->temp_val); default: return -ENOTSUP; } return 0; } static const struct sensor_driver_api adxl367_api_funcs = { .attr_set = adxl367_attr_set, .sample_fetch = adxl367_sample_fetch, .channel_get = adxl367_channel_get, #ifdef CONFIG_ADXL367_TRIGGER .trigger_set = adxl367_trigger_set, #endif }; static int adxl367_probe(const struct device *dev) { const struct adxl367_dev_config *cfg = dev->config; struct adxl367_data *data = dev->data; uint8_t dev_id, part_id; int ret; ret = adxl367_reset(dev); if (ret != 0) { return ret; } ret = data->hw_tf->read_reg(dev, ADXL367_DEVID, &dev_id); if (ret != 0) { return ret; } ret = data->hw_tf->read_reg(dev, ADXL367_PART_ID, &part_id); if (ret != 0) { return ret; } if (dev_id != ADXL367_DEVID_VAL || part_id != ADXL367_PARTID_VAL) { LOG_ERR("failed to read id (0x%X:0x%X)\n", dev_id, part_id); return -ENODEV; } data->range = cfg->range; #ifdef CONFIG_ADXL367_TRIGGER data->act_proc_mode = ADXL367_LINKED; #else data->act_proc_mode = ADXL367_LOOPED; #endif ret = adxl367_self_test(dev); if (ret != 0) { return ret; } ret = adxl367_temp_read_en(dev, cfg->temp_en); if (ret != 0) { return ret; } ret = adxl367_set_autosleep(dev, cfg->autosleep); if (ret != 0) { return ret; } ret = adxl367_set_low_noise(dev, cfg->low_noise); if (ret != 0) { return ret; } ret = adxl367_setup_activity_detection(dev, &cfg->activity_th); if (ret != 0) { return ret; } ret = adxl367_setup_inactivity_detection(dev, &cfg->inactivity_th); if (ret != 0) { return ret; } ret = adxl367_set_activity_time(dev, cfg->activity_time); if (ret != 0) { return ret; } ret = adxl367_set_inactivity_time(dev, cfg->inactivity_time); if (ret != 0) { return ret; } ret = adxl367_set_output_rate(dev, cfg->odr); if (ret != 0) { return ret; } ret = adxl367_fifo_setup(dev, cfg->fifo_config.fifo_mode, cfg->fifo_config.fifo_format, cfg->fifo_config.fifo_read_mode, cfg->fifo_config.fifo_samples); if (ret != 0) { return ret; } if (IS_ENABLED(CONFIG_ADXL367_TRIGGER)) { ret = adxl367_init_interrupt(dev); if (ret != 0) { LOG_ERR("Failed to initialize interrupt!"); return -EIO; } } ret = adxl367_set_op_mode(dev, cfg->op_mode); if (ret != 0) { return ret; } ret = adxl367_set_range(dev, data->range); if (ret != 0) { return ret; } return adxl367_set_act_proc_mode(dev, data->act_proc_mode); } static int adxl367_init(const struct device *dev) { int ret; const struct adxl367_dev_config *cfg = dev->config; ret = cfg->bus_init(dev); if (ret != 0) { LOG_ERR("Failed to initialize sensor bus\n"); return ret; } return adxl367_probe(dev); } #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0 #warning "ADXL367 driver enabled without any devices" #endif /* * Device creation macro, shared by ADXL367_DEFINE_SPI() and * ADXL367_DEFINE_I2C(). */ #define ADXL367_DEVICE_INIT(inst) \ SENSOR_DEVICE_DT_INST_DEFINE(inst, \ adxl367_init, \ NULL, \ &adxl367_data_##inst, \ &adxl367_config_##inst, \ POST_KERNEL, \ CONFIG_SENSOR_INIT_PRIORITY, \ &adxl367_api_funcs); #ifdef CONFIG_ADXL367_TRIGGER #define ADXL367_CFG_IRQ(inst) \ .interrupt = GPIO_DT_SPEC_INST_GET(inst, int1_gpios), #else #define ADXL367_CFG_IRQ(inst) #endif /* CONFIG_ADXL367_TRIGGER */ #define ADXL367_CONFIG(inst) \ .odr = DT_INST_PROP(inst, odr), \ .autosleep = false, \ .low_noise = false, \ .temp_en = true, \ .range = ADXL367_2G_RANGE, \ .activity_th.value = CONFIG_ADXL367_ACTIVITY_THRESHOLD, \ .activity_th.referenced = \ IS_ENABLED(CONFIG_ADXL367_REFERENCED_ACTIVITY_DETECTION_MODE), \ .activity_th.enable = \ IS_ENABLED(CONFIG_ADXL367_ACTIVITY_DETECTION_MODE), \ .activity_time = CONFIG_ADXL367_ACTIVITY_TIME, \ .inactivity_th.value = CONFIG_ADXL367_INACTIVITY_THRESHOLD, \ .inactivity_th.referenced = \ IS_ENABLED(CONFIG_ADXL367_REFERENCED_INACTIVITY_DETECTION_MODE),\ .inactivity_th.enable = \ IS_ENABLED(CONFIG_ADXL367_INACTIVITY_DETECTION_MODE), \ .inactivity_time = CONFIG_ADXL367_INACTIVITY_TIME, \ .fifo_config.fifo_mode = ADXL367_FIFO_DISABLED, \ .fifo_config.fifo_format = ADXL367_FIFO_FORMAT_XYZ, \ .fifo_config.fifo_samples = 128, \ .fifo_config.fifo_read_mode = ADXL367_14B_CHID, \ .op_mode = ADXL367_MEASURE, /* * Instantiation macros used when a device is on a SPI bus. */ #define ADXL367_CONFIG_SPI(inst) \ { \ .bus_init = adxl367_spi_init, \ .spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8) | \ SPI_TRANSFER_MSB, 0), \ ADXL367_CONFIG(inst) \ COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ (ADXL367_CFG_IRQ(inst)), ()) \ } #define ADXL367_DEFINE_SPI(inst) \ static struct adxl367_data adxl367_data_##inst; \ static const struct adxl367_dev_config adxl367_config_##inst = \ ADXL367_CONFIG_SPI(inst); \ ADXL367_DEVICE_INIT(inst) /* * Instantiation macros used when a device is on an I2C bus. */ #define ADXL367_CONFIG_I2C(inst) \ { \ .bus_init = adxl367_i2c_init, \ .i2c = I2C_DT_SPEC_INST_GET(inst), \ ADXL367_CONFIG(inst) \ COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ (ADXL367_CFG_IRQ(inst)), ()) \ } #define ADXL367_DEFINE_I2C(inst) \ static struct adxl367_data adxl367_data_##inst; \ static const struct adxl367_dev_config adxl367_config_##inst = \ ADXL367_CONFIG_I2C(inst); \ ADXL367_DEVICE_INIT(inst) /* * Main instantiation macro. Use of COND_CODE_1() selects the right * bus-specific macro at preprocessor time. */ #define ADXL367_DEFINE(inst) \ COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ (ADXL367_DEFINE_SPI(inst)), \ (ADXL367_DEFINE_I2C(inst))) DT_INST_FOREACH_STATUS_OKAY(ADXL367_DEFINE)