diff --git a/drivers/sensor/adi/adxl345/adxl345.c b/drivers/sensor/adi/adxl345/adxl345.c index 14463392bb7e2..825d076a07e9e 100644 --- a/drivers/sensor/adi/adxl345/adxl345.c +++ b/drivers/sensor/adi/adxl345/adxl345.c @@ -15,6 +15,12 @@ #include "adxl345.h" +static const uint8_t adxl345_fifo_ctl_trigger_init[] = { + [ADXL345_FIFO_CTL_TRIGGER_INT1] = ADXL345_INT1, + [ADXL345_FIFO_CTL_TRIGGER_INT2] = ADXL345_INT2, + [ADXL345_FIFO_CTL_TRIGGER_UNSET] = ADXL345_INT_UNSET, +}; + LOG_MODULE_REGISTER(ADXL345, CONFIG_SENSOR_LOG_LEVEL); #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) @@ -46,23 +52,30 @@ int adxl345_reg_access_spi(const struct device *dev, uint8_t cmd, uint8_t reg_ad uint8_t *data, size_t length) { const struct adxl345_dev_config *cfg = dev->config; - uint8_t access = reg_addr | cmd | (length == 1 ? 0 : ADXL345_MULTIBYTE_FLAG); - const struct spi_buf buf[2] = {{.buf = &access, .len = 1}, {.buf = data, .len = length}}; - const struct spi_buf_set rx = {.buffers = buf, .count = ARRAY_SIZE(buf)}; + uint8_t access = reg_addr; + + access |= cmd; + access |= (length == 1) ? 0 : ADXL345_MULTIBYTE_FLAG; + + const struct spi_buf buf[] = { + {.buf = &access, .len = 1}, + {.buf = data, .len = length}, + }; + + const struct spi_buf_set rx = { + .buffers = buf, + .count = ARRAY_SIZE(buf), + }; + struct spi_buf_set tx = { .buffers = buf, - .count = 2, + .count = (cmd == ADXL345_READ_CMD) ? 1 : 2, }; - int ret; if (cmd == ADXL345_READ_CMD) { - tx.count = 1; - ret = spi_transceive_dt(&cfg->bus.spi, &tx, &rx); - return ret; - } else { - ret = spi_write_dt(&cfg->bus.spi, &tx); - return ret; + return spi_transceive_dt(&cfg->bus.spi, &tx, &rx); } + return spi_write_dt(&cfg->bus.spi, &tx); } #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ @@ -77,14 +90,12 @@ int adxl345_reg_access(const struct device *dev, uint8_t cmd, uint8_t addr, int adxl345_reg_write(const struct device *dev, uint8_t addr, uint8_t *data, uint8_t len) { - return adxl345_reg_access(dev, ADXL345_WRITE_CMD, addr, data, len); } int adxl345_reg_read(const struct device *dev, uint8_t addr, uint8_t *data, uint8_t len) { - return adxl345_reg_access(dev, ADXL345_READ_CMD, addr, data, len); } @@ -94,28 +105,25 @@ int adxl345_reg_write_byte(const struct device *dev, uint8_t addr, uint8_t val) } int adxl345_reg_read_byte(const struct device *dev, uint8_t addr, uint8_t *buf) - { return adxl345_reg_read(dev, addr, buf, 1); } -int adxl345_reg_write_mask(const struct device *dev, - uint8_t reg_addr, - uint8_t mask, - uint8_t data) +int adxl345_reg_update_bits(const struct device *dev, uint8_t reg, + uint8_t mask, uint8_t val) { - int ret; - uint8_t tmp; + uint8_t regval, tmp; + int rc; - ret = adxl345_reg_read_byte(dev, reg_addr, &tmp); - if (ret) { - return ret; + rc = adxl345_reg_read_byte(dev, reg, ®val); + if (rc) { + return rc; } - tmp &= ~mask; - tmp |= data; + tmp = regval & ~mask; + tmp |= val & mask; - return adxl345_reg_write_byte(dev, reg_addr, tmp); + return adxl345_reg_write_byte(dev, reg, tmp); } static inline bool adxl345_bus_is_ready(const struct device *dev) @@ -125,102 +133,69 @@ static inline bool adxl345_bus_is_ready(const struct device *dev) return cfg->bus_is_ready(&cfg->bus); } -int adxl345_get_status(const struct device *dev, - uint8_t *status1, - uint16_t *fifo_entries) -{ - uint8_t buf[2], length = 1U; - int ret; - - ret = adxl345_reg_read(dev, ADXL345_INT_SOURCE, buf, length); +static const uint8_t adxl345_op_mode_init[] = { + [ADXL345_OP_STANDBY] = ADXL345_POWER_CTL_STANDBY_MODE, + [ADXL345_OP_MEASURE] = ADXL345_POWER_CTL_MEASURE_MODE, +}; - *status1 = buf[0]; - ret = adxl345_reg_read(dev, ADXL345_FIFO_STATUS_REG, buf+1, length); - if (fifo_entries) { - *fifo_entries = buf[1] & 0x3F; - } +int adxl345_set_measure_en(const struct device *dev, bool en) +{ + uint8_t val = adxl345_op_mode_init[en ? ADXL345_OP_MEASURE + : ADXL345_OP_STANDBY]; - return ret; + return adxl345_reg_update_bits(dev, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_MODE_MSK, val); } -/** - * Configure the operating parameters for the FIFO. - * @param dev - The device structure. - * @param mode - FIFO Mode. Specifies FIFO operating mode. - * Accepted values: ADXL345_FIFO_BYPASSED - * ADXL345_FIFO_STREAMED - * ADXL345_FIFO_TRIGGERED - * ADXL345_FIFO_OLD_SAVED - * @param trigger - FIFO trigger. Links trigger event to appropriate INT. - * Accepted values: ADXL345_INT1 - * ADXL345_INT2 - * @param fifo_samples - FIFO Samples. Watermark number of FIFO samples that - * triggers a FIFO_FULL condition when reached. - * Values range from 0 to 32. - - * @return 0 in case of success, negative error code otherwise. - */ -int adxl345_configure_fifo(const struct device *dev, - enum adxl345_fifo_mode mode, - enum adxl345_fifo_trigger trigger, - uint16_t fifo_samples) +int adxl345_flush_fifo(const struct device *dev) { +#ifdef CONFIG_ADXL345_TRIGGER struct adxl345_dev_data *data = dev->data; - uint8_t fifo_config; - int ret; + uint8_t regval; + int rc; - if (fifo_samples > 32) { - return -EINVAL; + rc = adxl345_set_measure_en(dev, false); + if (rc) { + return rc; } - fifo_config = (ADXL345_FIFO_CTL_TRIGGER_MODE(trigger) | - ADXL345_FIFO_CTL_MODE_MODE(mode) | - ADXL345_FIFO_CTL_SAMPLES_MODE(fifo_samples)); - - ret = adxl345_reg_write_byte(dev, ADXL345_FIFO_CTL_REG, fifo_config); - if (ret) { - return ret; + rc = adxl345_get_fifo_entries(dev, &data->sample_number); + if (rc) { + return rc; } - data->fifo_config.fifo_trigger = trigger; - data->fifo_config.fifo_mode = mode; - data->fifo_config.fifo_samples = fifo_samples; + do { /* Read FIFO entries + 1 sample lines */ + rc = adxl345_reg_read(dev, ADXL345_REG_DATA_XYZ_REGS, + ®val, ADXL345_FIFO_SAMPLE_SIZE); + if (rc) { + return rc; + } - return 0; + data->sample_number--; + } while (data->sample_number > 0); +#endif /* CONFIG_ADXL345_TRIGGER */ + + return adxl345_set_measure_en(dev, true); } -/** - * Set the mode of operation. - * @param dev - The device structure. - * @param op_mode - Mode of operation. - * Accepted values: ADXL345_STANDBY - * ADXL345_MEASURE - * @return 0 in case of success, negative error code otherwise. - */ -int adxl345_set_op_mode(const struct device *dev, enum adxl345_op_mode op_mode) +int adxl345_get_fifo_entries(const struct device *dev, uint8_t *fifo_entries) { - return adxl345_reg_write_mask(dev, ADXL345_POWER_CTL_REG, - ADXL345_POWER_CTL_MEASURE_MSK, - ADXL345_POWER_CTL_MEASURE_MODE(op_mode)); + uint8_t regval; + int rc; + + rc = adxl345_reg_read_byte(dev, ADXL345_REG_FIFO_STATUS, ®val); + if (rc) { + return rc; + } + + *fifo_entries = FIELD_GET(ADLX345_FIFO_STATUS_ENTRIES_MSK, regval); + + return 0; } -/** - * Set Output data rate. - * @param dev - The device structure. - * @param odr - Output data rate. - * Accepted values: ADXL345_ODR_12HZ - * ADXL345_ODR_25HZ - * ADXL345_ODR_50HZ - * ADXL345_ODR_100HZ - * ADXL345_ODR_200HZ - * ADXL345_ODR_400HZ - * @return 0 in case of success, negative error code otherwise. - */ -static int adxl345_set_odr(const struct device *dev, enum adxl345_odr odr) +int adxl345_get_status(const struct device *dev, uint8_t *status) { - return adxl345_reg_write_mask(dev, ADXL345_RATE_REG, - ADXL345_ODR_MSK, - ADXL345_ODR_MODE(odr)); + return adxl345_reg_read_byte(dev, ADXL345_REG_INT_SOURCE, status); } static int adxl345_attr_set_odr(const struct device *dev, @@ -254,13 +229,28 @@ static int adxl345_attr_set_odr(const struct device *dev, return -EINVAL; } - int ret = adxl345_set_odr(dev, odr); + data->odr = odr; + + return adxl345_reg_update_bits(dev, ADXL345_REG_RATE, ADXL345_ODR_MSK, + ADXL345_ODR_MODE(odr)); +} - if (ret == 0) { - data->odr = odr; +static int adxl345_attr_set_watermark(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + struct adxl345_dev_data *data = dev->data; + uint8_t wm = val->val1; + + if (wm < 1 || wm > ADXL345_MAX_FIFO_SIZE) { + return -EINVAL; } - return ret; + data->fifo_config.fifo_samples = wm; + + return adxl345_reg_update_bits(dev, ADXL345_REG_FIFO_CTL, + ADLX345_FIFO_STATUS_ENTRIES_MSK, wm); } static int adxl345_attr_set(const struct device *dev, @@ -271,119 +261,148 @@ static int adxl345_attr_set(const struct device *dev, switch (attr) { case SENSOR_ATTR_SAMPLING_FREQUENCY: return adxl345_attr_set_odr(dev, chan, attr, val); + case SENSOR_ATTR_MAX: + return adxl345_attr_set_watermark(dev, chan, attr, val); default: return -ENOTSUP; } } -int adxl345_read_sample(const struct device *dev, - struct adxl345_sample *sample) +int adxl345_get_accel_data(const struct device *dev, + struct adxl345_xyz_accel_data *sample) { - int16_t raw_x, raw_y, raw_z; - uint8_t axis_data[6], status1; - struct adxl345_dev_data *data = dev->data; - - if (!IS_ENABLED(CONFIG_ADXL345_TRIGGER)) { - do { - adxl345_get_status(dev, &status1, NULL); - } while (!(ADXL345_STATUS_DATA_RDY(status1))); - } - - int rc = adxl345_reg_read(dev, ADXL345_X_AXIS_DATA_0_REG, axis_data, 6); + uint8_t axis_data[ADXL345_FIFO_SAMPLE_SIZE]; + int rc; + rc = adxl345_reg_read(dev, ADXL345_REG_DATA_XYZ_REGS, + axis_data, ADXL345_FIFO_SAMPLE_SIZE); if (rc < 0) { LOG_ERR("Samples read failed with rc=%d\n", rc); return rc; } - raw_x = axis_data[0] | (axis_data[1] << 8); - raw_y = axis_data[2] | (axis_data[3] << 8); - raw_z = axis_data[4] | (axis_data[5] << 8); + sample->x = axis_data[0] | axis_data[1] << 8; + sample->y = axis_data[2] | axis_data[3] << 8; + sample->z = axis_data[4] | axis_data[5] << 8; - sample->x = raw_x; - sample->y = raw_y; - sample->z = raw_z; +#ifdef CONFIG_ADXL345_TRIGGER + struct adxl345_dev_data *data = dev->data; + sample->is_full_res = data->is_full_res; /* needed for decoder */ sample->selected_range = data->selected_range; - sample->is_full_res = data->is_full_res; +#endif - return 0; + return rc; } -void adxl345_accel_convert(struct sensor_value *val, int16_t sample) +/** + * adxl345_accel_convert - The fallback conversion of raw measurements. + * @out: Converted value for output, containing the initialized fractional. + * @sample: Input raw measurement. + * When working without decoder, neither TRIGGER, nor STREAM is enabled, + * this small converter is used. It assumes full scale resolution and 8g. + */ +void adxl345_accel_convert(struct sensor_value *out, int16_t sample) { - if (sample & BIT(9)) { - sample |= ADXL345_COMPLEMENT; + /* full resolution enabled w/ 8g */ + if (sample & BIT(11)) { + sample |= ADXL345_COMPLEMENT_MASK(12); } - - val->val1 = ((sample * SENSOR_G) / 32) / 1000000; - val->val2 = ((sample * SENSOR_G) / 32) % 1000000; + out->val1 = ((sample * SENSOR_G) / 32) / 1000000; + out->val2 = ((sample * SENSOR_G) / 32) % 1000000; } static int adxl345_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct adxl345_dev_data *data = dev->data; - struct adxl345_sample sample; - uint8_t samples_count; + uint8_t count; int rc; - data->sample_number = 0; - rc = adxl345_reg_read_byte(dev, ADXL345_FIFO_STATUS_REG, &samples_count); - if (rc < 0) { - LOG_ERR("Failed to read FIFO status rc = %d\n", rc); - return rc; + count = 1; + + /* FIFO BYPASSED is the only mode not using a FIFO buffer */ + if (data->fifo_config.fifo_mode != ADXL345_FIFO_BYPASSED) { + rc = adxl345_get_fifo_entries(dev, &count); + if (rc) { + LOG_ERR("Failed to read FIFO status rc=%d\n", rc); + return rc; + } } - __ASSERT_NO_MSG(samples_count <= ARRAY_SIZE(data->bufx)); + __ASSERT_NO_MSG(count <= ARRAY_SIZE(data->sample)); - for (uint8_t s = 0; s < samples_count; s++) { - rc = adxl345_read_sample(dev, &sample); + for (uint8_t s = 0; s < count; s++) { + rc = adxl345_get_accel_data(dev, &data->sample[s]); if (rc < 0) { LOG_ERR("Failed to fetch sample rc=%d\n", rc); return rc; } - data->bufx[s] = sample.x; - data->bufy[s] = sample.y; - data->bufz[s] = sample.z; + +#ifdef CONFIG_ADXL345_STREAM + data->sample[s].is_fifo = 0; +#endif } + /* new sample available, reset book-keeping */ + data->sample_idx = 0; + data->sample_number = count; + return 0; } +/** + * adxl345_channel_get - Read a single element of one or three axis. + * @dev: The sensor device. + * @chan: The axis channel, can be x, y, z or xyz. + * @val: The resulting value after conversion of the raw axis data. Val can be + * a single value or an array of three values, where the index correspondes to + * x, y, z axis entries. + */ static int adxl345_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct adxl345_dev_data *data = dev->data; - - if (data->sample_number >= ARRAY_SIZE(data->bufx)) { - data->sample_number = 0; + int idx; + + if (data->sample_number <= 0) { /* empty */ + val->val1 = 0; + val->val2 = 0; + if (chan == SENSOR_CHAN_ACCEL_XYZ) { + val[1].val1 = 0; + val[1].val2 = 0; + val[2].val1 = 0; + val[2].val2 = 0; + } + return -ENOTSUP; } + data->sample_idx = data->sample_idx % data->sample_number; + idx = data->sample_idx; + switch (chan) { case SENSOR_CHAN_ACCEL_X: - adxl345_accel_convert(val, data->bufx[data->sample_number]); - data->sample_number++; + adxl345_accel_convert(val, data->sample[idx].x); break; case SENSOR_CHAN_ACCEL_Y: - adxl345_accel_convert(val, data->bufy[data->sample_number]); - data->sample_number++; + adxl345_accel_convert(val, data->sample[idx].y); break; case SENSOR_CHAN_ACCEL_Z: - adxl345_accel_convert(val, data->bufz[data->sample_number]); - data->sample_number++; + adxl345_accel_convert(val, data->sample[idx].z); break; case SENSOR_CHAN_ACCEL_XYZ: - adxl345_accel_convert(val++, data->bufx[data->sample_number]); - adxl345_accel_convert(val++, data->bufy[data->sample_number]); - adxl345_accel_convert(val, data->bufz[data->sample_number]); - data->sample_number++; + adxl345_accel_convert(val++, data->sample[idx].x); + adxl345_accel_convert(val++, data->sample[idx].y); + adxl345_accel_convert(val, data->sample[idx].z); + break; default: return -ENOTSUP; } + data->sample_idx++; + return 0; } @@ -400,137 +419,131 @@ static DEVICE_API(sensor, adxl345_api_funcs) = { #endif }; -#ifdef CONFIG_ADXL345_TRIGGER -/** - * Configure the INT1 and INT2 interrupt pins. - * @param dev - The device structure. - * @param int1 - INT1 interrupt pins. - * @return 0 in case of success, negative error code otherwise. - */ -static int adxl345_interrupt_config(const struct device *dev, - uint8_t int1) -{ - int ret; - const struct adxl345_dev_config *cfg = dev->config; - - ret = adxl345_reg_write_byte(dev, ADXL345_INT_MAP, int1); - if (ret) { - return ret; - } - - ret = adxl345_reg_write_byte(dev, ADXL345_INT_ENABLE, int1); - if (ret) { - return ret; - } - - uint8_t samples; - - ret = adxl345_reg_read_byte(dev, ADXL345_INT_MAP, &samples); - ret = adxl345_reg_read_byte(dev, ADXL345_INT_ENABLE, &samples); -#ifdef CONFIG_ADXL345_TRIGGER - gpio_pin_interrupt_configure_dt(&cfg->interrupt, - GPIO_INT_EDGE_TO_ACTIVE); -#endif - return 0; -} -#endif - static int adxl345_init(const struct device *dev) { - int rc; struct adxl345_dev_data *data = dev->data; -#ifdef CONFIG_ADXL345_TRIGGER const struct adxl345_dev_config *cfg = dev->config; -#endif - uint8_t dev_id, full_res; - - data->sample_number = 0; + enum adxl345_fifo_mode fifo_mode; + uint8_t dev_id, pwr_ctl, int_en, regval; + int rc; if (!adxl345_bus_is_ready(dev)) { LOG_ERR("bus not ready"); return -ENODEV; } - rc = adxl345_reg_read_byte(dev, ADXL345_DEVICE_ID_REG, &dev_id); + rc = adxl345_reg_read_byte(dev, ADXL345_REG_DEVICE_ID, &dev_id); if (rc < 0 || dev_id != ADXL345_PART_ID) { LOG_ERR("Read PART ID failed: 0x%x\n", rc); return -ENODEV; } -#if CONFIG_ADXL345_STREAM - rc = adxl345_reg_write_byte(dev, ADXL345_FIFO_CTL_REG, ADXL345_FIFO_STREAM_MODE); - if (rc < 0) { - LOG_ERR("FIFO enable failed\n"); - return -EIO; - } -#endif - - rc = adxl345_reg_write_byte(dev, ADXL345_DATA_FORMAT_REG, ADXL345_RANGE_8G); + /* reset the sensor */ + data->selected_range = ADXL345_RANGE_8G; + data->is_full_res = true; + data->sample_number = 0; + data->sample_idx = 0; + + /* + * Reset the following sensor fields (in case of warm starts) + * - turn off measurements as MSB values, use left justified vals + * - configure full resolution accordingly + * - turn off interrupt inversion + * - turn off 3-wire SPI + * - turn off self test mode + */ + regval = (data->is_full_res ? ADXL345_DATA_FORMAT_FULL_RES : 0x00); + regval |= adxl345_range_init[data->selected_range]; + rc = adxl345_reg_write_byte(dev, ADXL345_REG_DATA_FORMAT, regval); if (rc < 0) { LOG_ERR("Data format set failed\n"); return -EIO; } - data->selected_range = ADXL345_RANGE_8G; - - rc = adxl345_reg_write_byte(dev, ADXL345_RATE_REG, ADXL345_RATE_25HZ); - if (rc < 0) { - LOG_ERR("Rate setting failed\n"); - return -EIO; + rc = adxl345_reg_update_bits(dev, ADXL345_REG_RATE, ADXL345_ODR_MSK, + ADXL345_ODR_MODE(cfg->odr)); + if (rc) { + return rc; } -#ifdef CONFIG_ADXL345_TRIGGER - rc = adxl345_configure_fifo(dev, ADXL345_FIFO_STREAMED, - ADXL345_INT2, - SAMPLE_NUM); + pwr_ctl = 0x00; + int_en = 0x00; + fifo_mode = ADXL345_FIFO_BYPASSED; + + rc = adxl345_reg_write_byte(dev, ADXL345_REG_INT_ENABLE, int_en); if (rc) { return rc; } -#endif - rc = adxl345_reg_write_byte(dev, ADXL345_POWER_CTL_REG, ADXL345_ENABLE_MEASURE_BIT); - if (rc < 0) { - LOG_ERR("Enable measure bit failed\n"); - return -EIO; + rc = adxl345_reg_write_byte(dev, ADXL345_REG_POWER_CTL, pwr_ctl); + if (rc) { + return rc; } #ifdef CONFIG_ADXL345_TRIGGER - rc = adxl345_init_interrupt(dev); - if (rc < 0) { - LOG_ERR("Failed to initialize interrupt!"); - return -EIO; + if (adxl345_init_interrupt(dev)) { + /* no interrupt lines configured in DT */ + LOG_INF("No IRQ lines specified, fallback to FIFO BYPASSED"); + fifo_mode = ADXL345_FIFO_BYPASSED; + } else { + LOG_INF("Set FIFO STREAMED mode"); + fifo_mode = ADXL345_FIFO_STREAMED; + + /* + * Currently, map all interrupts to the (same) gpio line + * configured in the device tree. + */ + uint8_t int_mask = 0xff; + + int_en = (cfg->drdy_pad == 2) ? int_mask : ~int_mask; + rc = adxl345_reg_update_bits(dev, ADXL345_REG_INT_MAP, + int_mask, int_en); + if (rc) { + return rc; + } } +#endif /* CONFIG_ADXL345_TRIGGER */ - rc = adxl345_set_odr(dev, cfg->odr); - if (rc) { - return rc; - } - rc = adxl345_interrupt_config(dev, ADXL345_INT_MAP_WATERMARK_MSK); + data->fifo_config.fifo_mode = fifo_mode; + uint8_t fifo_config = adxl345_fifo_ctl_mode_init[fifo_mode]; + + data->fifo_config.fifo_trigger = ADXL345_INT_UNSET; + fifo_config |= adxl345_fifo_ctl_trigger_init[ADXL345_INT_UNSET]; + + data->fifo_config.fifo_samples = ADXL345_FIFO_CTL_SAMPLES_MSK; + fifo_config |= ADXL345_FIFO_CTL_SAMPLES_MSK; + + rc = adxl345_reg_write_byte(dev, ADXL345_REG_FIFO_CTL, fifo_config); if (rc) { return rc; } -#endif - rc = adxl345_reg_read_byte(dev, ADXL345_DATA_FORMAT_REG, &full_res); - uint8_t is_full_res_set = (full_res & ADXL345_DATA_FORMAT_FULL_RES) != 0; + if (fifo_mode == ADXL345_FIFO_BYPASSED) { + return adxl345_set_measure_en(dev, true); + } - data->is_full_res = is_full_res_set; return 0; } #ifdef CONFIG_ADXL345_TRIGGER #define ADXL345_CFG_IRQ(inst) \ - .interrupt = GPIO_DT_SPEC_INST_GET(inst, int2_gpios), + .gpio_int1 = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, {0}), \ + .gpio_int2 = GPIO_DT_SPEC_INST_GET_OR(inst, int2_gpios, {0}), \ + .drdy_pad = DT_INST_PROP_OR(inst, drdy_pin, -1) #else #define ADXL345_CFG_IRQ(inst) #endif /* CONFIG_ADXL345_TRIGGER */ +#define ADXL345_CONFIG_COMMON(inst) \ + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (ADXL345_CFG_IRQ(inst))) + #define ADXL345_RTIO_SPI_DEFINE(inst) \ COND_CODE_1(CONFIG_SPI_RTIO, \ (SPI_DT_IODEV_DEFINE(adxl345_iodev_##inst, DT_DRV_INST(inst), \ SPI_WORD_SET(8) | SPI_TRANSFER_MSB | \ - SPI_MODE_CPOL | SPI_MODE_CPHA, 0U);), \ - ()) + SPI_MODE_CPOL | SPI_MODE_CPHA, 0U);), ()) #define ADXL345_RTIO_I2C_DEFINE(inst) \ COND_CODE_1(CONFIG_I2C_RTIO, \ @@ -544,65 +557,75 @@ static int adxl345_init(const struct device *dev) * (adx345_stram - line 203), using smaller amounts of samples * to trigger an interrupt can decrease the pool sizes. */ -#define ADXL345_RTIO_DEFINE(inst) \ - /* Conditionally include SPI and/or I2C parts based on their presence */ \ - COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ - (ADXL345_RTIO_SPI_DEFINE(inst)), \ - ()) \ - COND_CODE_1(DT_INST_ON_BUS(inst, i2c), \ - (ADXL345_RTIO_I2C_DEFINE(inst)), \ - ()) \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, spi_dt_spec) && \ - DT_INST_NODE_HAS_PROP(inst, i2c_dt_spec), \ - (RTIO_DEFINE(adxl345_rtio_ctx_##inst, 128, 128);), \ - (RTIO_DEFINE(adxl345_rtio_ctx_##inst, 64, 64);)) \ - -#define ADXL345_CONFIG(inst) \ - .odr = DT_INST_PROP(inst, odr), \ - .fifo_config.fifo_mode = ADXL345_FIFO_STREAMED, \ - .fifo_config.fifo_trigger = ADXL345_INT2, \ - .fifo_config.fifo_samples = SAMPLE_NUM, \ - .odr = ADXL345_RATE_25HZ, \ - -#define ADXL345_CONFIG_SPI(inst) \ - { \ - .bus = {.spi = SPI_DT_SPEC_INST_GET(inst, \ - SPI_WORD_SET(8) | \ - SPI_TRANSFER_MSB | \ - SPI_MODE_CPOL | \ - SPI_MODE_CPHA, \ - 0)}, \ - .bus_is_ready = adxl345_bus_is_ready_spi, \ - .reg_access = adxl345_reg_access_spi, \ - .bus_type = ADXL345_BUS_SPI, \ +#define ADXL345_RTIO_DEFINE(inst) \ + /* Conditionally include SPI or I2C parts based on their presence */ \ + (COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (ADXL345_RTIO_SPI_DEFINE(inst)), ()) \ + COND_CODE_1(DT_INST_ON_BUS(inst, i2c), \ + (ADXL345_RTIO_I2C_DEFINE(inst)), ()) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, spi_dt_spec) && \ + DT_INST_NODE_HAS_PROP(inst, i2c_dt_spec), \ + (RTIO_DEFINE(adxl345_rtio_ctx_##inst, 128, 128);), \ + (RTIO_DEFINE(adxl345_rtio_ctx_##inst, 64, 64);))) + +#define ADXL345_CONFIG(inst) \ + .odr = DT_INST_PROP_OR(inst, odr, ADXL345_RATE_25HZ), + +#define ADXL345_CONFIG_SPI(inst) \ + { \ + .bus = {.spi = SPI_DT_SPEC_INST_GET(inst, \ + SPI_WORD_SET(8) | \ + SPI_TRANSFER_MSB | \ + SPI_MODE_CPOL | \ + SPI_MODE_CPHA, \ + 0)}, \ + .bus_is_ready = adxl345_bus_is_ready_spi, \ + .reg_access = adxl345_reg_access_spi, \ + .bus_type = ADXL345_BUS_SPI, \ ADXL345_CONFIG(inst) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + (ADXL345_CONFIG_COMMON(inst)), ()) \ COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int2_gpios), \ - (ADXL345_CFG_IRQ(inst)), ()) \ + (ADXL345_CONFIG_COMMON(inst)), ()) \ } -#define ADXL345_CONFIG_I2C(inst) \ - { \ - .bus = {.i2c = I2C_DT_SPEC_INST_GET(inst)}, \ - .bus_is_ready = adxl345_bus_is_ready_i2c, \ - .reg_access = adxl345_reg_access_i2c, \ - .bus_type = ADXL345_BUS_I2C, \ +#define ADXL345_CONFIG_I2C(inst) \ + { \ + .bus = {.i2c = I2C_DT_SPEC_INST_GET(inst)}, \ + .bus_is_ready = adxl345_bus_is_ready_i2c, \ + .reg_access = adxl345_reg_access_i2c, \ + .bus_type = ADXL345_BUS_I2C, \ ADXL345_CONFIG(inst) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + (ADXL345_CONFIG_COMMON(inst)), ()) \ COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int2_gpios), \ - (ADXL345_CFG_IRQ(inst)), ()) \ + (ADXL345_CONFIG_COMMON(inst)), ()) \ } -#define ADXL345_DEFINE(inst) \ - IF_ENABLED(CONFIG_ADXL345_STREAM, (ADXL345_RTIO_DEFINE(inst))); \ - static struct adxl345_dev_data adxl345_data_##inst = { \ - COND_CODE_1(adxl345_iodev_##inst, (.rtio_ctx = &adxl345_rtio_ctx_##inst, \ - .iodev = &adxl345_iodev_##inst,), ()) \ - }; \ - static const struct adxl345_dev_config adxl345_config_##inst = \ - COND_CODE_1(DT_INST_ON_BUS(inst, spi), (ADXL345_CONFIG_SPI(inst)), \ - (ADXL345_CONFIG_I2C(inst))); \ - \ - SENSOR_DEVICE_DT_INST_DEFINE(inst, adxl345_init, NULL, \ - &adxl345_data_##inst, &adxl345_config_##inst, POST_KERNEL,\ - CONFIG_SENSOR_INIT_PRIORITY, &adxl345_api_funcs); \ +#define ADXL345_DEFINE(inst) \ + IF_ENABLED(CONFIG_ADXL345_STREAM, (ADXL345_RTIO_DEFINE(inst))); \ + \ + static struct adxl345_dev_data adxl345_data_##inst = { \ + IF_ENABLED(CONFIG_ADXL345_STREAM, \ + (.rtio_ctx = &adxl345_rtio_ctx_##inst, \ + .iodev = &adxl345_iodev_##inst,)) \ + }; \ + \ + static const struct adxl345_dev_config adxl345_config_##inst = \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (ADXL345_CONFIG_SPI(inst)), \ + (ADXL345_CONFIG_I2C(inst))); \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, adxl345_init, NULL, \ + &adxl345_data_##inst, \ + &adxl345_config_##inst, \ + POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &adxl345_api_funcs); \ + \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, drdy_pin), \ + (BUILD_ASSERT(DT_INST_NODE_HAS_PROP(inst, \ + CONCAT(int, DT_INST_PROP(inst, drdy_pin), _gpios)), \ + "No GPIO pin defined for ADXL345 DRDY interrupt");)) DT_INST_FOREACH_STATUS_OKAY(ADXL345_DEFINE) diff --git a/drivers/sensor/adi/adxl345/adxl345.h b/drivers/sensor/adi/adxl345/adxl345.h index 8bc25f5034028..ebed3adc4e08a 100644 --- a/drivers/sensor/adi/adxl345/adxl345.h +++ b/drivers/sensor/adi/adxl345/adxl345.h @@ -14,6 +14,8 @@ #include #include +#include + #ifdef CONFIG_ADXL345_STREAM #include #endif /* CONFIG_ADXL345_STREAM */ @@ -29,92 +31,116 @@ #include /* ADXL345 communication commands */ -#define ADXL345_WRITE_CMD 0x00 -#define ADXL345_READ_CMD 0x80 -#define ADXL345_MULTIBYTE_FLAG 0x40 +#define ADXL345_WRITE_CMD 0x00 +#define ADXL345_READ_CMD 0x80 +#define ADXL345_MULTIBYTE_FLAG 0x40 -#define ADXL345_REG_READ(x) ((x & 0xFF) | ADXL345_READ_CMD) +#define ADXL345_REG_READ(x) (FIELD_GET(GENMASK(5, 0), x) | ADXL345_READ_CMD) -#define SAMPLE_SIZE 6 -#define SAMPLE_MASK 0x3F -#define SAMPLE_NUM 0x1F +#define ADXL345_COMPLEMENT_MASK(x) GENMASK(15, (x)) +#define ADXL345_COMPLEMENT GENMASK(15, 9) /* Registers */ -#define ADXL345_DEVICE_ID_REG 0x00 -#define ADXL345_RATE_REG 0x2c -#define ADXL345_POWER_CTL_REG 0x2d -#define ADXL345_DATA_FORMAT_REG 0x31 -#define ADXL345_DATA_FORMAT_FULL_RES 0x08 -#define ADXL345_X_AXIS_DATA_0_REG 0x32 -#define ADXL345_FIFO_CTL_REG 0x38 -#define ADXL345_FIFO_STATUS_REG 0x39 - -#define ADXL345_PART_ID 0xe5 - -#define ADXL345_RANGE_2G 0x0 -#define ADXL345_RANGE_4G 0x1 -#define ADXL345_RANGE_8G 0x2 -#define ADXL345_RANGE_16G 0x3 -#define ADXL345_RATE_25HZ 0x8 -#define ADXL345_ENABLE_MEASURE_BIT (1 << 3) -#define ADXL345_FIFO_STREAM_MODE (1 << 7) -#define ADXL345_FIFO_COUNT_MASK 0x3f -#define ADXL345_COMPLEMENT_MASK(x) GENMASK(15, (x)) -#define ADXL345_COMPLEMENT 0xfc00 - -#define ADXL345_MAX_FIFO_SIZE 32 - -#define ADXL345_INT_ENABLE 0x2Eu -#define ADXL345_INT_MAP 0x2Fu -#define ADXL345_INT_SOURCE 0x30u - -/* ADXL345_STATUS_1 */ -#define ADXL345_STATUS_DOUBLE_TAP(x) (((x) >> 5) & 0x1) -#define ADXL345_STATUS_SINGLE_TAP(x) (((x) >> 6) & 0x1) -#define ADXL345_STATUS_DATA_RDY(x) (((x) >> 7) & 0x1) +#define ADXL345_REG_DEVICE_ID 0x00 +#define ADXL345_REG_RATE 0x2c +#define ADXL345_REG_POWER_CTL 0x2d +#define ADXL345_REG_INT_ENABLE 0x2e +#define ADXL345_REG_INT_MAP 0x2f +#define ADXL345_REG_INT_SOURCE 0x30 +#define ADXL345_REG_DATA_FORMAT 0x31 +#define ADXL345_REG_DATA_XYZ_REGS 0x32 +#define ADXL345_REG_FIFO_CTL 0x38 +#define ADXL345_REG_FIFO_STATUS 0x39 + +/* Regstier fields / content values */ +#define ADXL345_PART_ID 0xe5 + +#define ADXL345_DATA_FORMAT_RIGHT_JUSTIFY BIT(2) /* enable left justified */ +#define ADXL345_DATA_FORMAT_FULL_RES BIT(3) +#define ADXL345_DATA_FORMAT_INT_INVERT BIT(5) /* enable int active low */ +#define ADXL345_DATA_FORMAT_3WIRE_SPI BIT(6) /* enable 3-wire SPI */ +#define ADXL345_DATA_FORMAT_SELF_TEST BIT(7) /* enable self test */ + +#define ADXL345_DATA_FORMAT_RANGE_2G 0x00 +#define ADXL345_DATA_FORMAT_RANGE_4G 0x01 +#define ADXL345_DATA_FORMAT_RANGE_8G 0x02 +#define ADXL345_DATA_FORMAT_RANGE_16G 0x03 + +enum adxl345_range { + ADXL345_RANGE_2G, + ADXL345_RANGE_4G, + ADXL345_RANGE_8G, + ADXL345_RANGE_16G, +}; + +static const uint8_t adxl345_range_init[] = { + [ADXL345_RANGE_2G] = ADXL345_DATA_FORMAT_RANGE_2G, + [ADXL345_RANGE_4G] = ADXL345_DATA_FORMAT_RANGE_4G, + [ADXL345_RANGE_8G] = ADXL345_DATA_FORMAT_RANGE_8G, + [ADXL345_RANGE_16G] = ADXL345_DATA_FORMAT_RANGE_16G, +}; + +#define ADXL345_RATE_25HZ 0x8 /* ADXL345_INT_MAP */ -#define ADXL345_INT_MAP_OVERRUN_MSK BIT(0) -#define ADXL345_INT_MAP_OVERRUN_MODE(x) (((x) & 0x1) << 0) -#define ADXL345_INT_MAP_WATERMARK_MSK BIT(1) -#define ADXL345_INT_MAP_WATERMARK_MODE(x) (((x) & 0x1) << 1) -#define ADXL345_INT_MAP_FREE_FALL_MSK BIT(2) -#define ADXL345_INT_MAP_FREE_FALL_MODE(x) (((x) & 0x1) << 2) -#define ADXL345_INT_MAP_INACT_MSK BIT(3) -#define ADXL345_INT_MAP_INACT_MODE(x) (((x) & 0x1) << 3) -#define ADXL345_INT_MAP_ACT_MSK BIT(4) -#define ADXL345_INT_MAP_ACT_MODE(x) (((x) & 0x1) << 4) -#define ADXL345_INT_MAP_DOUBLE_TAP_MSK BIT(5) -#define ADXL345_INT_MAP_DOUBLE_TAP_MODE(x) (((x) & 0x1) << 5) -#define ADXL345_INT_MAP_SINGLE_TAP_MSK BIT(6) -#define ADXL345_INT_MAP_SINGLE_TAP_MODE(x) (((x) & 0x1) << 6) -#define ADXL345_INT_MAP_DATA_RDY_MSK BIT(7) -#define ADXL345_INT_MAP_DATA_RDY_MODE(x) (((x) & 0x1) << 7) +#define ADXL345_INT_OVERRUN BIT(0) +#define ADXL345_INT_WATERMARK BIT(1) +#define ADXL345_INT_FREE_FALL BIT(2) +#define ADXL345_INT_INACT BIT(3) +#define ADXL345_INT_ACT BIT(4) +#define ADXL345_INT_DOUBLE_TAP BIT(5) +#define ADXL345_INT_SINGLE_TAP BIT(6) +#define ADXL345_INT_DATA_RDY BIT(7) /* POWER_CTL */ -#define ADXL345_POWER_CTL_WAKEUP_4HZ BIT(0) -#define ADXL345_POWER_CTL_WAKEUP_4HZ_MODE(x) (((x) & 0x1) << 0) -#define ADXL345_POWER_CTL_WAKEUP_2HZ BIT(1) -#define ADXL345_POWER_CTL_WAKEUP_2HZ_MODE(x) (((x) & 0x1) << 1) -#define ADXL345_POWER_CTL_SLEEP BIT(2) -#define ADXL345_POWER_CTL_SLEEP_MODE(x) (((x) & 0x1) << 2) -#define ADXL345_POWER_CTL_MEASURE_MSK GENMASK(3, 3) -#define ADXL345_POWER_CTL_MEASURE_MODE(x) (((x) & 0x1) << 3) -#define ADXL345_POWER_CTL_STANDBY_MODE(x) (((x) & 0x0) << 3) +#define ADXL345_POWER_CTL_WAKEUP_4HZ BIT(0) +#define ADXL345_POWER_CTL_WAKEUP_2HZ BIT(1) +#define ADXL345_POWER_CTL_SLEEP BIT(2) + +#define ADXL345_POWER_CTL_MEASURE_MODE BIT(3) +#define ADXL345_POWER_CTL_STANDBY_MODE 0x0 +#define ADXL345_POWER_CTL_MODE_MSK BIT(3) /* ADXL345_FIFO_CTL */ -#define ADXL345_FIFO_CTL_MODE_MSK GENMASK(7, 6) -#define ADXL345_FIFO_CTL_MODE_MODE(x) (((x) & 0x3) << 6) -#define ADXL345_FIFO_CTL_TRIGGER_MSK BIT(5) -#define ADXL345_FIFO_CTL_TRIGGER_MODE(x) (((x) & 0x1) << 5) -#define ADXL345_FIFO_CTL_SAMPLES_MSK BIT(0) -#define ADXL345_FIFO_CTL_SAMPLES_MODE(x) ((x) & 0x1F) +#define ADXL345_FIFO_CTL_MODE_MSK GENMASK(7, 6) +#define ADXL345_FIFO_CTL_MODE_BYPASSED 0x0 +#define ADXL345_FIFO_CTL_MODE_OLD_SAVED 0x40 +#define ADXL345_FIFO_CTL_MODE_STREAMED 0x80 +#define ADXL345_FIFO_CTL_MODE_TRIGGERED 0xc0 + +enum adxl345_fifo_mode { + ADXL345_FIFO_BYPASSED, + ADXL345_FIFO_OLD_SAVED, + ADXL345_FIFO_STREAMED, + ADXL345_FIFO_TRIGGERED, +}; + +static const uint8_t adxl345_fifo_ctl_mode_init[] = { + [ADXL345_FIFO_BYPASSED] = ADXL345_FIFO_CTL_MODE_BYPASSED, + [ADXL345_FIFO_OLD_SAVED] = ADXL345_FIFO_CTL_MODE_OLD_SAVED, + [ADXL345_FIFO_STREAMED] = ADXL345_FIFO_CTL_MODE_STREAMED, + [ADXL345_FIFO_TRIGGERED] = ADXL345_FIFO_CTL_MODE_TRIGGERED, +}; + +#define ADXL345_FIFO_SAMPLE_SIZE 6 + +#define ADXL345_FIFO_CTL_SAMPLES_MSK GENMASK(4, 0) +#define ADLX345_FIFO_STATUS_ENTRIES_MSK GENMASK(5, 0) +#define ADXL345_MAX_FIFO_SIZE 32 + +#define ADXL345_FIFO_CTL_TRIGGER_INT1 0x0 +#define ADXL345_FIFO_CTL_TRIGGER_INT2 BIT(5) +#define ADXL345_FIFO_CTL_TRIGGER_UNSET 0x0 -#define ADXL345_ODR_MSK GENMASK(3, 0) -#define ADXL345_ODR_MODE(x) ((x) & 0xF) +/* FIFO trigger, note this is only used in FIFO triggered mode */ +enum adxl345_fifo_trigger { + ADXL345_INT1, + ADXL345_INT2, + ADXL345_INT_UNSET, +}; -#define ADXL345_BUS_I2C 0 -#define ADXL345_BUS_SPI 1 +#define ADXL345_ODR_MSK GENMASK(3, 0) +#define ADXL345_ODR_MODE(x) ((x) & 0xF) enum adxl345_odr { ADXL345_ODR_12HZ = 0x7, @@ -122,50 +148,73 @@ enum adxl345_odr { ADXL345_ODR_50HZ, ADXL345_ODR_100HZ, ADXL345_ODR_200HZ, - ADXL345_ODR_400HZ + ADXL345_ODR_400HZ, }; -enum adxl345_fifo_trigger { - ADXL345_INT1, - ADXL345_INT2 -}; +#define ADXL345_BUS_I2C 0 +#define ADXL345_BUS_SPI 1 -enum adxl345_fifo_mode { - ADXL345_FIFO_BYPASSED, - ADXL345_FIFO_OLD_SAVED, - ADXL345_FIFO_STREAMED, - ADXL345_FIFO_TRIGGERED +enum adxl345_op_mode { + ADXL345_OP_STANDBY, + ADXL345_OP_MEASURE, }; struct adxl345_fifo_config { enum adxl345_fifo_mode fifo_mode; enum adxl345_fifo_trigger fifo_trigger; - uint16_t fifo_samples; + uint8_t fifo_samples; /* number of entries to read for STREAM */ }; -enum adxl345_op_mode { - ADXL345_STANDBY, - ADXL345_MEASURE +struct adxl345_fifo_data { + uint8_t is_fifo: 1; + uint8_t is_full_res: 1; + enum adxl345_range selected_range: 2; + uint8_t sample_set_size: 4; + uint8_t int_status; + uint16_t accel_odr: 4; + uint16_t fifo_byte_count: 12; + uint64_t timestamp; +} __attribute__((__packed__)); + +struct adxl345_xyz_accel_data { +#ifdef CONFIG_ADXL345_STREAM + uint8_t is_fifo: 1; + uint8_t res: 7; +#endif /* CONFIG_ADXL345_STREAM */ + enum adxl345_range selected_range; + bool is_full_res; + int16_t x; + int16_t y; + int16_t z; +} __attribute__((__packed__)); + +union adxl345_bus { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + struct i2c_dt_spec i2c; +#endif +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + struct spi_dt_spec spi; +#endif }; struct adxl345_dev_data { - unsigned int sample_number; - int16_t bufx[ADXL345_MAX_FIFO_SIZE]; - int16_t bufy[ADXL345_MAX_FIFO_SIZE]; - int16_t bufz[ADXL345_MAX_FIFO_SIZE]; + struct adxl345_xyz_accel_data sample[ADXL345_MAX_FIFO_SIZE]; + uint8_t sample_number; /* number of samples to read from sensor */ + uint8_t sample_idx; /* index counting up sample_number entries */ struct adxl345_fifo_config fifo_config; - uint8_t is_full_res; - uint8_t selected_range; + bool is_full_res; + enum adxl345_range selected_range; enum adxl345_odr odr; #ifdef CONFIG_ADXL345_TRIGGER - struct gpio_callback gpio_cb; - - sensor_trigger_handler_t th_handler; - const struct sensor_trigger *th_trigger; + struct gpio_callback int1_cb; + struct gpio_callback int2_cb; sensor_trigger_handler_t drdy_handler; const struct sensor_trigger *drdy_trigger; + sensor_trigger_handler_t wm_handler; + const struct sensor_trigger *wm_trigger; + sensor_trigger_handler_t overrun_handler; + const struct sensor_trigger *overrun_trigger; const struct device *dev; - #if defined(CONFIG_ADXL345_TRIGGER_OWN_THREAD) K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ADXL345_THREAD_STACK_SIZE); struct k_sem gpio_sem; @@ -182,44 +231,11 @@ struct adxl345_dev_data { uint8_t fifo_ent[1]; uint64_t timestamp; struct rtio *r_cb; - uint8_t fifo_watermark_irq; uint8_t fifo_samples; uint16_t fifo_total_bytes; #endif /* CONFIG_ADXL345_STREAM */ }; -struct adxl345_fifo_data { - uint8_t is_fifo: 1; - uint8_t is_full_res: 1; - uint8_t selected_range: 2; - uint8_t sample_set_size: 4; - uint8_t int_status; - uint16_t accel_odr: 4; - uint16_t fifo_byte_count: 12; - uint64_t timestamp; -} __attribute__((__packed__)); - -struct adxl345_sample { -#ifdef CONFIG_ADXL345_STREAM - uint8_t is_fifo: 1; - uint8_t res: 7; -#endif /* CONFIG_ADXL345_STREAM */ - uint8_t selected_range; - bool is_full_res; - int16_t x; - int16_t y; - int16_t z; -}; - -union adxl345_bus { -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) - struct i2c_dt_spec i2c; -#endif -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) - struct spi_dt_spec spi; -#endif -}; - typedef bool (*adxl345_bus_is_ready_fn)(const union adxl345_bus *bus); typedef int (*adxl345_reg_access_fn)(const struct device *dev, uint8_t cmd, uint8_t reg_addr, uint8_t *data, size_t length); @@ -229,20 +245,26 @@ struct adxl345_dev_config { adxl345_bus_is_ready_fn bus_is_ready; adxl345_reg_access_fn reg_access; enum adxl345_odr odr; - bool op_mode; - struct adxl345_fifo_config fifo_config; uint8_t bus_type; #ifdef CONFIG_ADXL345_TRIGGER - struct gpio_dt_spec interrupt; + struct gpio_dt_spec gpio_int1; + struct gpio_dt_spec gpio_int2; + int8_t drdy_pad; #endif }; +int adxl345_set_gpios_en(const struct device *dev, bool enable); + void adxl345_submit_stream(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe); void adxl345_stream_irq_handler(const struct device *dev); +int adxl345_set_measure_en(const struct device *dev, bool en); + +int adxl345_flush_fifo(const struct device *dev); + #ifdef CONFIG_ADXL345_TRIGGER -int adxl345_get_status(const struct device *dev, - uint8_t *status, uint16_t *fifo_entries); +int adxl345_get_fifo_entries(const struct device *dev, uint8_t *fifo_entries); +int adxl345_get_status(const struct device *dev, uint8_t *status); int adxl345_trigger_set(const struct device *dev, const struct sensor_trigger *trig, @@ -252,35 +274,34 @@ int adxl345_init_interrupt(const struct device *dev); #endif /* CONFIG_ADXL345_TRIGGER */ -int adxl345_reg_write_mask(const struct device *dev, - uint8_t reg_addr, - uint8_t mask, - uint8_t data); - int adxl345_reg_access(const struct device *dev, uint8_t cmd, uint8_t addr, - uint8_t *data, size_t len); + uint8_t *data, size_t len); int adxl345_reg_write(const struct device *dev, uint8_t addr, uint8_t *data, - uint8_t len); + uint8_t len); int adxl345_reg_read(const struct device *dev, uint8_t addr, uint8_t *data, - uint8_t len); + uint8_t len); int adxl345_reg_write_byte(const struct device *dev, uint8_t addr, uint8_t val); int adxl345_reg_read_byte(const struct device *dev, uint8_t addr, uint8_t *buf); -int adxl345_set_op_mode(const struct device *dev, enum adxl345_op_mode op_mode); +int adxl345_reg_update_bits(const struct device *dev, uint8_t reg, + uint8_t mask, uint8_t val); + #ifdef CONFIG_SENSOR_ASYNC_API -int adxl345_read_sample(const struct device *dev, struct adxl345_sample *sample); -void adxl345_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe); -int adxl345_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder); +int adxl345_get_accel_data(const struct device *dev, + struct adxl345_xyz_accel_data *sample); +void adxl345_submit(const struct device *dev, + struct rtio_iodev_sqe *iodev_sqe); +int adxl345_get_decoder(const struct device *dev, + const struct sensor_decoder_api **decoder); void adxl345_accel_convert(struct sensor_value *val, int16_t sample); #endif /* CONFIG_SENSOR_ASYNC_API */ #ifdef CONFIG_ADXL345_STREAM -int adxl345_configure_fifo(const struct device *dev, enum adxl345_fifo_mode mode, - enum adxl345_fifo_trigger trigger, uint16_t fifo_samples); size_t adxl345_get_packet_size(const struct adxl345_dev_config *cfg); #endif /* CONFIG_ADXL345_STREAM */ + #endif /* ZEPHYR_DRIVERS_SENSOR_ADX345_ADX345_H_ */ diff --git a/drivers/sensor/adi/adxl345/adxl345_decoder.c b/drivers/sensor/adi/adxl345/adxl345_decoder.c index 1f39fb9d1d141..22ca2cec53691 100644 --- a/drivers/sensor/adi/adxl345/adxl345_decoder.c +++ b/drivers/sensor/adi/adxl345/adxl345_decoder.c @@ -25,7 +25,6 @@ static const uint32_t qscale_factor_no_full_res[] = { [ADXL345_RANGE_16G] = UINT32_C(2570754), }; - /** Sensitivities based on Range: * * - At 2G: 256 LSB/g, 10-bits resolution. @@ -51,8 +50,9 @@ static const uint32_t range_to_shift[] = { [ADXL345_RANGE_16G] = 8, }; -static inline void adxl345_accel_convert_q31(q31_t *out, int16_t sample, int32_t range, - uint8_t is_full_res) +static inline void adxl345_accel_convert_q31(q31_t *out, int16_t sample, + enum adxl345_range range, + bool is_full_res) { if (is_full_res) { switch (range) { @@ -88,8 +88,6 @@ static inline void adxl345_accel_convert_q31(q31_t *out, int16_t sample, int32_t #ifdef CONFIG_ADXL345_STREAM -#define SENSOR_SCALING_FACTOR (SENSOR_G / (16 * 1000 / 100)) - static const uint32_t accel_period_ns[] = { [ADXL345_ODR_12HZ] = UINT32_C(1000000000) / 12, [ADXL345_ODR_25HZ] = UINT32_C(1000000000) / 25, @@ -112,18 +110,23 @@ static int adxl345_decode_stream(const uint8_t *buffer, struct sensor_chan_spec return 0; } + if (chan_spec.chan_type != SENSOR_CHAN_ACCEL_XYZ) { + return -ENOTSUP; + } + struct sensor_three_axis_data *data = (struct sensor_three_axis_data *)data_out; + enum adxl345_range selected_range = enc_data->selected_range; memset(data, 0, sizeof(struct sensor_three_axis_data)); data->header.base_timestamp_ns = enc_data->timestamp; data->header.reading_count = 1; - data->shift = range_to_shift[enc_data->selected_range]; + data->shift = range_to_shift[selected_range]; buffer += sizeof(struct adxl345_fifo_data); uint8_t sample_set_size = enc_data->sample_set_size; uint64_t period_ns = accel_period_ns[enc_data->accel_odr]; - uint8_t is_full_res = enc_data->is_full_res; + bool is_full_res = enc_data->is_full_res; /* Calculate which sample is decoded. */ if ((uint8_t *)*fit >= buffer) { @@ -141,29 +144,26 @@ static int adxl345_decode_stream(const uint8_t *buffer, struct sensor_chan_spec continue; } - switch (chan_spec.chan_type) { - case SENSOR_CHAN_ACCEL_XYZ: - data->readings[count].timestamp_delta = sample_num * period_ns; - uint8_t buff_offset = 0; - - adxl345_accel_convert_q31(&data->readings[count].x, *(int16_t *)buffer, - enc_data->selected_range, is_full_res); - buff_offset = 2; - adxl345_accel_convert_q31(&data->readings[count].y, - *(int16_t *)(buffer + buff_offset), - enc_data->selected_range, is_full_res); - buff_offset += 2; - adxl345_accel_convert_q31(&data->readings[count].z, - *(int16_t *)(buffer + buff_offset), - enc_data->selected_range, is_full_res); - break; - default: - return -ENOTSUP; - } + data->readings[count].timestamp_delta = sample_num * period_ns; + uint8_t buff_offset = 0; + + adxl345_accel_convert_q31(&data->readings[count].x, + *(int16_t *)buffer, + selected_range, is_full_res); + buff_offset = 2; + adxl345_accel_convert_q31(&data->readings[count].y, + *(int16_t *)(buffer + buff_offset), + selected_range, is_full_res); + buff_offset += 2; + adxl345_accel_convert_q31(&data->readings[count].z, + *(int16_t *)(buffer + buff_offset), + selected_range, is_full_res); + buffer = sample_end; *fit = (uintptr_t)sample_end; count++; } + return count; } @@ -172,10 +172,8 @@ static int adxl345_decode_stream(const uint8_t *buffer, struct sensor_chan_spec static int adxl345_decoder_get_frame_count(const uint8_t *buffer, struct sensor_chan_spec chan_spec, uint16_t *frame_count) { - int32_t ret = -ENOTSUP; - if (chan_spec.chan_idx != 0) { - return ret; + return -ENOTSUP; } #ifdef CONFIG_ADXL345_STREAM @@ -189,38 +187,35 @@ static int adxl345_decoder_get_frame_count(const uint8_t *buffer, struct sensor_ case SENSOR_CHAN_ACCEL_Z: case SENSOR_CHAN_ACCEL_XYZ: *frame_count = 1; - ret = 0; - break; - + return 0; default: - break; + return -ENOTSUP; } #ifdef CONFIG_ADXL345_STREAM } else { if (data->fifo_byte_count == 0) { *frame_count = 0; - ret = 0; - } else { - switch (chan_spec.chan_type) { - case SENSOR_CHAN_ACCEL_XYZ: - *frame_count = - data->fifo_byte_count / data->sample_set_size; - ret = 0; - break; - - default: - break; - } + return 0; } + + if (chan_spec.chan_type != SENSOR_CHAN_ACCEL_XYZ) { + return -ENOTSUP; + } + + *frame_count = data->fifo_byte_count / data->sample_set_size; + return 0; + } #endif /* CONFIG_ADXL345_STREAM */ - return ret; + return -ENOTSUP; } -static int adxl345_decode_sample(const struct adxl345_sample *data, - struct sensor_chan_spec chan_spec, uint32_t *fit, - uint16_t max_count, void *data_out) +static int adxl345_decode_sample(const struct adxl345_xyz_accel_data *data, + struct sensor_chan_spec chan_spec, + uint32_t *fit, + uint16_t max_count, + void *data_out) { struct sensor_three_axis_data *out = (struct sensor_three_axis_data *)data_out; @@ -233,32 +228,38 @@ static int adxl345_decode_sample(const struct adxl345_sample *data, return -ENOTSUP; } - switch (chan_spec.chan_type) { - case SENSOR_CHAN_ACCEL_XYZ: - adxl345_accel_convert_q31(&out->readings->x, data->x, data->selected_range, - data->is_full_res); - adxl345_accel_convert_q31(&out->readings->y, data->y, data->selected_range, - data->is_full_res); - adxl345_accel_convert_q31(&out->readings->z, data->z, data->selected_range, - data->is_full_res); - break; - default: + if (chan_spec.chan_type != SENSOR_CHAN_ACCEL_XYZ) { return -ENOTSUP; } + adxl345_accel_convert_q31(&out->readings->x, data->x, + data->selected_range, + data->is_full_res); + adxl345_accel_convert_q31(&out->readings->y, data->y, + data->selected_range, + data->is_full_res); + adxl345_accel_convert_q31(&out->readings->z, data->z, + data->selected_range, + data->is_full_res); + *fit = 1; return 1; } -static int adxl345_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, - uint32_t *fit, uint16_t max_count, void *data_out) +static int adxl345_decoder_decode(const uint8_t *buffer, + struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, + void *data_out) { - const struct adxl345_sample *data = (const struct adxl345_sample *)buffer; + const struct adxl345_xyz_accel_data *data; + + data = (const struct adxl345_xyz_accel_data *)buffer; #ifdef CONFIG_ADXL345_STREAM if (data->is_fifo) { - return adxl345_decode_stream(buffer, chan_spec, fit, max_count, data_out); + return adxl345_decode_stream(buffer, chan_spec, + fit, max_count, data_out); } #endif /* CONFIG_ADXL345_STREAM */ @@ -274,8 +275,12 @@ static bool adxl345_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigg } switch (trigger) { + case SENSOR_TRIG_DATA_READY: + return FIELD_GET(ADXL345_INT_DATA_RDY, data->int_status); case SENSOR_TRIG_FIFO_WATERMARK: - return FIELD_GET(ADXL345_INT_MAP_WATERMARK_MSK, data->int_status); + return FIELD_GET(ADXL345_INT_WATERMARK, data->int_status); + case SENSOR_TRIG_FIFO_FULL: + return FIELD_GET(ADXL345_INT_OVERRUN, data->int_status); default: return false; } diff --git a/drivers/sensor/adi/adxl345/adxl345_rtio.c b/drivers/sensor/adi/adxl345/adxl345_rtio.c index c8f0d682a067f..19bd5f0de0fc4 100644 --- a/drivers/sensor/adi/adxl345/adxl345_rtio.c +++ b/drivers/sensor/adi/adxl345/adxl345_rtio.c @@ -17,28 +17,33 @@ static void adxl345_submit_fetch(struct rtio_iodev_sqe *iodev_sqe) const struct sensor_read_config *cfg = (const struct sensor_read_config *) iodev_sqe->sqe.iodev->data; const struct device *dev = cfg->sensor; - int rc; uint32_t min_buffer_len = sizeof(struct adxl345_dev_data); uint8_t *buffer; uint32_t buffer_len; + struct adxl345_xyz_accel_data *data; + int rc; - rc = rtio_sqe_rx_buf(iodev_sqe, min_buffer_len, min_buffer_len, &buffer, &buffer_len); - if (rc != 0) { - LOG_ERR("Failed to get a read buffer of size %u bytes", min_buffer_len); - rtio_iodev_sqe_err(iodev_sqe, rc); - return; + rc = rtio_sqe_rx_buf(iodev_sqe, min_buffer_len, min_buffer_len, + &buffer, &buffer_len); + if (rc) { + LOG_ERR("Failed to get a read buffer of size %u bytes", + min_buffer_len); + goto err; } - struct adxl345_sample *data = (struct adxl345_sample *)buffer; + data = (struct adxl345_xyz_accel_data *)buffer; - rc = adxl345_read_sample(dev, data); - if (rc != 0) { + rc = adxl345_get_accel_data(dev, data); + if (rc) { LOG_ERR("Failed to fetch samples"); - rtio_iodev_sqe_err(iodev_sqe, rc); - return; + goto err; } rtio_iodev_sqe_ok(iodev_sqe, 0); + + return; +err: + rtio_iodev_sqe_err(iodev_sqe, rc); } void adxl345_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) diff --git a/drivers/sensor/adi/adxl345/adxl345_stream.c b/drivers/sensor/adi/adxl345/adxl345_stream.c index ac62f3fbf6a2a..c8a5bf4cc55d5 100644 --- a/drivers/sensor/adi/adxl345/adxl345_stream.c +++ b/drivers/sensor/adi/adxl345/adxl345_stream.c @@ -17,7 +17,7 @@ void adxl345_submit_stream(const struct device *dev, struct rtio_iodev_sqe *iode (const struct sensor_read_config *) iodev_sqe->sqe.iodev->data; struct adxl345_dev_data *data = (struct adxl345_dev_data *)dev->data; const struct adxl345_dev_config *cfg_345 = dev->config; - uint8_t int_value = (uint8_t)~ADXL345_INT_MAP_WATERMARK_MSK; + uint8_t int_value = (uint8_t)~ADXL345_INT_WATERMARK; uint8_t fifo_watermark_irq = 0; int rc = gpio_pin_interrupt_configure_dt(&cfg_345->interrupt, GPIO_INT_DISABLE); @@ -28,15 +28,15 @@ void adxl345_submit_stream(const struct device *dev, struct rtio_iodev_sqe *iode for (size_t i = 0; i < cfg->count; i++) { if (cfg->triggers[i].trigger == SENSOR_TRIG_FIFO_WATERMARK) { - int_value = ADXL345_INT_MAP_WATERMARK_MSK; + int_value = ADXL345_INT_WATERMARK; fifo_watermark_irq = 1; } } uint8_t status; if (fifo_watermark_irq != data->fifo_watermark_irq) { data->fifo_watermark_irq = fifo_watermark_irq; - rc = adxl345_reg_write_mask(dev, ADXL345_INT_MAP, ADXL345_INT_MAP_WATERMARK_MSK, - int_value); + rc = adxl345_reg_write_mask(dev, ADXL345_REG_INT_MAP, + ADXL345_INT_WATERMARK, int_value); if (rc < 0) { return; } @@ -51,7 +51,8 @@ void adxl345_submit_stream(const struct device *dev, struct rtio_iodev_sqe *iode data->fifo_config.fifo_samples); adxl345_configure_fifo(dev, current_fifo_mode, data->fifo_config.fifo_trigger, data->fifo_config.fifo_samples); - rc = adxl345_reg_read_byte(dev, ADXL345_FIFO_STATUS_REG, &status); + rc = adxl345_reg_read_byte(dev, ADXL345_REG_FIFO_STATUS, + &status); } rc = gpio_pin_interrupt_configure_dt(&cfg_345->interrupt, @@ -75,22 +76,24 @@ static void adxl345_fifo_flush_rtio(const struct device *dev) struct adxl345_dev_data *data = dev->data; uint8_t fifo_config; - fifo_config = (ADXL345_FIFO_CTL_TRIGGER_MODE(data->fifo_config.fifo_trigger) | - ADXL345_FIFO_CTL_MODE_MODE(ADXL345_FIFO_BYPASSED) | - ADXL345_FIFO_CTL_SAMPLES_MODE(data->fifo_config.fifo_samples)); + fifo_config = (adxl345_fifo_ctl_trigger_init[data->fifo_config.fifo_trigger] | + adxl345_fifo_ctl_mode_init[ADXL345_FIFO_BYPASSED] | + FIELD_GET(ADXL345_FIFO_CTL_SAMPLES_MSK, + data->fifo_config.fifo_samples)); struct rtio_sqe *write_fifo_addr = rtio_sqe_acquire(data->rtio_ctx); - const uint8_t reg_addr_w2[2] = {ADXL345_FIFO_CTL_REG, fifo_config}; + const uint8_t reg_addr_w2[2] = {ADXL345_REG_FIFO_CTL, fifo_config}; rtio_sqe_prep_tiny_write(write_fifo_addr, data->iodev, RTIO_PRIO_NORM, reg_addr_w2, 2, NULL); - fifo_config = (ADXL345_FIFO_CTL_TRIGGER_MODE(data->fifo_config.fifo_trigger) | - ADXL345_FIFO_CTL_MODE_MODE(data->fifo_config.fifo_mode) | - ADXL345_FIFO_CTL_SAMPLES_MODE(data->fifo_config.fifo_samples)); + fifo_config = (adxl345_fifo_ctl_trigger_init[data->fifo_config.fifo_trigger] | + adxl345_fifo_ctl_mode_init[data->fifo_config.fifo_mode] | + FIELD_GET(ADXL345_FIFO_CTL_SAMPLES_MSK, + data->fifo_config.fifo_samples)); write_fifo_addr = rtio_sqe_acquire(data->rtio_ctx); - const uint8_t reg_addr_w3[2] = {ADXL345_FIFO_CTL_REG, fifo_config}; + const uint8_t reg_addr_w3[2] = {ADXL345_REG_FIFO_CTL, fifo_config}; rtio_sqe_prep_tiny_write(write_fifo_addr, data->iodev, RTIO_PRIO_NORM, reg_addr_w3, 2, NULL); @@ -123,9 +126,10 @@ static void adxl345_process_fifo_samples_cb(struct rtio *r, const struct rtio_sq struct adxl345_dev_data *data = (struct adxl345_dev_data *) dev->data; const struct adxl345_dev_config *cfg = (const struct adxl345_dev_config *) dev->config; struct rtio_iodev_sqe *current_sqe = data->sqe; - uint16_t fifo_samples = (data->fifo_ent[0]) & SAMPLE_MASK; - size_t sample_set_size = SAMPLE_SIZE; - uint16_t fifo_bytes = fifo_samples * SAMPLE_SIZE; + uint8_t fifo_samples = (data->fifo_ent[0]) & + ADLX345_FIFO_STATUS_ENTRIES_MSK; + size_t sample_set_size = ADXL345_FIFO_SAMPLE_SIZE; + uint8_t fifo_bytes = fifo_samples * ADXL345_FIFO_SAMPLE_SIZE; data->sqe = NULL; @@ -206,16 +210,18 @@ static void adxl345_process_fifo_samples_cb(struct rtio *r, const struct rtio_sq struct rtio_sqe *read_fifo_data = rtio_sqe_acquire(data->rtio_ctx); data->fifo_samples--; - const uint8_t reg_addr = ADXL345_REG_READ(ADXL345_X_AXIS_DATA_0_REG) - | ADXL345_MULTIBYTE_FLAG; + const uint8_t reg_addr; + + reg_addr = ADXL345_REG_READ(ADXL345_REG_DATA_XYZ_REGS) | + ADXL345_MULTIBYTE_FLAG; rtio_sqe_prep_tiny_write(write_fifo_addr, data->iodev, RTIO_PRIO_NORM, ®_addr, 1, NULL); write_fifo_addr->flags = RTIO_SQE_TRANSACTION; rtio_sqe_prep_read(read_fifo_data, data->iodev, RTIO_PRIO_NORM, - read_buf + data->fifo_total_bytes, - SAMPLE_SIZE, current_sqe); - data->fifo_total_bytes += SAMPLE_SIZE; + read_buf + data->fifo_total_bytes, + ADXL345_FIFO_SAMPLE_SIZE, current_sqe); + data->fifo_total_bytes += ADXL345_FIFO_SAMPLE_SIZE; if (cfg->bus_type == ADXL345_BUS_I2C) { read_fifo_data->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART; } @@ -268,7 +274,7 @@ static void adxl345_process_status1_cb(struct rtio *r, const struct rtio_sqe *sq bool fifo_full_irq = false; if ((fifo_wmark_cfg != NULL) - && FIELD_GET(ADXL345_INT_MAP_WATERMARK_MSK, status1)) { + && FIELD_GET(ADXL345_INT_WATERMARK, status1)) { fifo_full_irq = true; } @@ -338,7 +344,7 @@ static void adxl345_process_status1_cb(struct rtio *r, const struct rtio_sqe *sq struct rtio_sqe *write_fifo_addr = rtio_sqe_acquire(data->rtio_ctx); struct rtio_sqe *read_fifo_data = rtio_sqe_acquire(data->rtio_ctx); struct rtio_sqe *complete_op = rtio_sqe_acquire(data->rtio_ctx); - const uint8_t reg_addr = ADXL345_REG_READ(ADXL345_FIFO_STATUS_REG); + const uint8_t reg_addr = ADXL345_REG_READ(ADXL345_REG_FIFO_STATUS); rtio_sqe_prep_tiny_write(write_fifo_addr, data->iodev, RTIO_PRIO_NORM, ®_addr, 1, NULL); write_fifo_addr->flags = RTIO_SQE_TRANSACTION; @@ -376,7 +382,7 @@ void adxl345_stream_irq_handler(const struct device *dev) struct rtio_sqe *write_status_addr = rtio_sqe_acquire(data->rtio_ctx); struct rtio_sqe *read_status_reg = rtio_sqe_acquire(data->rtio_ctx); struct rtio_sqe *check_status_reg = rtio_sqe_acquire(data->rtio_ctx); - uint8_t reg = ADXL345_REG_READ(ADXL345_INT_SOURCE); + uint8_t reg = ADXL345_REG_READ(ADXL345_REG_INT_SOURCE); rtio_sqe_prep_tiny_write(write_status_addr, data->iodev, RTIO_PRIO_NORM, ®, 1, NULL); write_status_addr->flags = RTIO_SQE_TRANSACTION; diff --git a/drivers/sensor/adi/adxl345/adxl345_trigger.c b/drivers/sensor/adi/adxl345/adxl345_trigger.c index 7c29523436b74..bf4a6e7bf3a51 100644 --- a/drivers/sensor/adi/adxl345/adxl345_trigger.c +++ b/drivers/sensor/adi/adxl345/adxl345_trigger.c @@ -11,169 +11,314 @@ #include #include #include + #include "adxl345.h" #include + LOG_MODULE_DECLARE(ADXL345, CONFIG_SENSOR_LOG_LEVEL); -#if defined(CONFIG_ADXL345_TRIGGER_OWN_THREAD) || defined(CONFIG_ADXL345_TRIGGER_GLOBAL_THREAD) -static void adxl345_thread_cb(const struct device *dev) +static int adxl345_set_int_pad_state(const struct device *dev, uint8_t pad, + bool en) { const struct adxl345_dev_config *cfg = dev->config; - struct adxl345_dev_data *drv_data = dev->data; - uint8_t status1; - int ret; + int state = en ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE; - /* Clear the status */ - if (adxl345_get_status(dev, &status1, NULL) < 0) { - return; + /* in case of neither INT_1 nor INT_2 being defined */ + if (!cfg->gpio_int1.port && !cfg->gpio_int2.port) { + return -ENOTSUP; } - if ((drv_data->drdy_handler != NULL) && - ADXL345_STATUS_DATA_RDY(status1)) { - drv_data->drdy_handler(dev, drv_data->drdy_trigger); + if (pad == 1) { + return gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, state); + } else if (pad == 2) { + return gpio_pin_interrupt_configure_dt(&cfg->gpio_int2, state); } - ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt, - GPIO_INT_EDGE_TO_ACTIVE); - __ASSERT(ret == 0, "Interrupt configuration failed"); + /* pad may be -1, e.g. if no INT line defined in DT */ + return -EINVAL; } -#endif -static void adxl345_gpio_callback(const struct device *dev, - struct gpio_callback *cb, uint32_t pins) +int adxl345_set_gpios_en(const struct device *dev, bool en) { - struct adxl345_dev_data *drv_data = - CONTAINER_OF(cb, struct adxl345_dev_data, gpio_cb); - const struct adxl345_dev_config *cfg = drv_data->dev->config; + const struct adxl345_dev_config *cfg = dev->config; + + return adxl345_set_int_pad_state(dev, cfg->drdy_pad, en); +} - gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_DISABLE); +#if defined(CONFIG_ADXL345_TRIGGER_OWN_THREAD) || \ + defined(CONFIG_ADXL345_TRIGGER_GLOBAL_THREAD) - if (IS_ENABLED(CONFIG_ADXL345_STREAM)) { - adxl345_stream_irq_handler(drv_data->dev); +/** adxl345_handle_interrupt - Interrupt service routine for the sensor. + * @dev: The device instance. + * Handle and reset the sensor interrupt events. + */ +static void adxl345_handle_interrupt(const struct device *dev) +{ + struct adxl345_dev_data *data = dev->data; + uint8_t status; + int rc; + + rc = adxl345_get_status(dev, &status); + __ASSERT(rc == 0, "Interrupt configuration failed"); + + if (FIELD_GET(ADXL345_INT_DATA_RDY, status)) { + if (data->drdy_handler) { + /* + * A handler needs to flush FIFO, i.e. fetch and get + * samples to get new events + */ + data->drdy_handler(dev, data->drdy_trigger); + } + } + + if (FIELD_GET(ADXL345_INT_WATERMARK, status)) { + if (data->wm_handler) { + /* + * Impede further IRQs by turning off measurement, + * this avoids falling into permanent overrun + */ + adxl345_set_measure_en(dev, false); + + /* + * A handler needs to implement fetch, then get FIFO + * entries according to configured watermark in order + * to obtain new sensor events + */ + data->wm_handler(dev, data->wm_trigger); + + adxl345_set_measure_en(dev, true); + } } + /* handle FIFO: overrun */ + if (FIELD_GET(ADXL345_INT_OVERRUN, status)) { + if (data->overrun_handler) { + /* + * A handler may handle read outs, the fallback flushes + * the fifo and interrupt status register + */ + data->overrun_handler(dev, data->overrun_trigger); + } + + /* + * If overrun handling is enabled, reset status register and + * fifo here, if not handled before in any way + */ + adxl345_flush_fifo(dev); + } +} +#endif + +static void adxl345_int1_gpio_callback(const struct device *dev, + struct gpio_callback *cb, + uint32_t pins) +{ + struct adxl345_dev_data *data = + CONTAINER_OF(cb, struct adxl345_dev_data, int1_cb); + + ARG_UNUSED(pins); + + adxl345_set_int_pad_state(dev, 1, false); + #if defined(CONFIG_ADXL345_TRIGGER_OWN_THREAD) - k_sem_give(&drv_data->gpio_sem); + k_sem_give(&data->gpio_sem); #elif defined(CONFIG_ADXL345_TRIGGER_GLOBAL_THREAD) - k_work_submit(&drv_data->work); + k_work_submit(&data->work); #endif } -#if defined(CONFIG_ADXL345_TRIGGER_OWN_THREAD) -static void adxl345_thread(void *p1, void *p2, void *p3) +static void adxl345_int2_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) { - ARG_UNUSED(p2); - ARG_UNUSED(p3); + struct adxl345_dev_data *data = + CONTAINER_OF(cb, struct adxl345_dev_data, int2_cb); + + ARG_UNUSED(pins); + + adxl345_set_int_pad_state(dev, 2, false); - struct adxl345_dev_data *drv_data = p1; +#if defined(CONFIG_ADXL345_TRIGGER_OWN_THREAD) + k_sem_give(&data->gpio_sem); +#elif defined(CONFIG_ADXL345_TRIGGER_GLOBAL_THREAD) + k_work_submit(&data->work); +#endif +} +#if defined(CONFIG_ADXL345_TRIGGER_OWN_THREAD) +static void adxl345_thread(struct adxl345_dev_data *data) +{ while (true) { - k_sem_take(&drv_data->gpio_sem, K_FOREVER); - adxl345_thread_cb(drv_data->dev); + k_sem_take(&data->gpio_sem, K_FOREVER); + adxl345_handle_interrupt(data->dev); } } #elif defined(CONFIG_ADXL345_TRIGGER_GLOBAL_THREAD) static void adxl345_work_cb(struct k_work *work) { - struct adxl345_dev_data *drv_data = + struct adxl345_dev_data *data = CONTAINER_OF(work, struct adxl345_dev_data, work); - adxl345_thread_cb(drv_data->dev); +#if !defined CONFIG_ADXL345_STREAM + /* + * Make sure, STREAM ISR w/ RTIO is handling the interrupt, and not + * cleaned up afterwards by the TRIGGER handler, if STREAM is enabled. + * So, disable TRIGGER ISR if STREAM is defined. + */ + adxl345_handle_interrupt(data->dev); +#endif /* !defined CONFIG_ADXL345_STREAM */ + } #endif +/** + * adxl345_trigger_set - Register a handler for a sensor trigger from the app. + * @dev: The device instance. + * @trig: The interrupt event type of the sensor. + * @handler: A handler for the sensor event to be registered. + * Map sensor events to the interrupt lines. + * return: 0 for success, or error. + */ int adxl345_trigger_set(const struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler) { const struct adxl345_dev_config *cfg = dev->config; - struct adxl345_dev_data *drv_data = dev->data; - uint8_t int_mask, int_en, status1; - int ret; - - ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt, - GPIO_INT_DISABLE); - if (ret < 0) { - return ret; + struct adxl345_dev_data *data = dev->data; + int rc; + + if (!cfg->gpio_int1.port && !cfg->gpio_int2.port) { + /* might be in FIFO BYPASS mode */ + goto done; + } + + /* generally turn off interrupts */ + rc = adxl345_set_gpios_en(dev, false); + if (rc) { + return rc; } switch (trig->type) { case SENSOR_TRIG_DATA_READY: - drv_data->drdy_handler = handler; - drv_data->drdy_trigger = trig; - int_mask = ADXL345_INT_MAP_DATA_RDY_MSK; + data->drdy_handler = handler; + data->drdy_trigger = trig; + rc = adxl345_reg_update_bits(dev, ADXL345_REG_INT_ENABLE, + ADXL345_INT_DATA_RDY, + 0xff); + if (rc) { + return rc; + } + + break; + case SENSOR_TRIG_FIFO_WATERMARK: + data->wm_handler = handler; + data->wm_trigger = trig; + rc = adxl345_reg_update_bits(dev, ADXL345_REG_INT_ENABLE, + ADXL345_INT_WATERMARK, + 0xff); + if (rc) { + return rc; + } + break; + case SENSOR_TRIG_FIFO_FULL: + data->overrun_handler = handler; + data->overrun_trigger = trig; + rc = adxl345_reg_update_bits(dev, ADXL345_REG_INT_ENABLE, + ADXL345_INT_OVERRUN, + 0xff); + if (rc) { + return rc; + } break; default: LOG_ERR("Unsupported sensor trigger"); return -ENOTSUP; } - if (handler) { - int_en = int_mask; - } else { - int_en = 0U; +done: + rc = adxl345_set_gpios_en(dev, true); + if (rc) { + return rc; } - ret = adxl345_reg_write_mask(dev, ADXL345_INT_MAP, int_mask, int_en); - if (ret < 0) { - return ret; - } - /* Clear status */ - ret = adxl345_get_status(dev, &status1, NULL); - if (ret < 0) { - return ret; - } - - ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt, - GPIO_INT_EDGE_TO_ACTIVE); - if (ret < 0) { - return ret; - } - - return 0; + return adxl345_flush_fifo(dev); } int adxl345_init_interrupt(const struct device *dev) { const struct adxl345_dev_config *cfg = dev->config; - struct adxl345_dev_data *drv_data = dev->data; - int ret; + struct adxl345_dev_data *data = dev->data; + int rc; - if (!gpio_is_ready_dt(&cfg->interrupt)) { - LOG_ERR("GPIO port %s not ready", cfg->interrupt.port->name); - return -EINVAL; + /* TRIGGER is set, but not INT line was defined in DT */ + if (!cfg->gpio_int1.port && !cfg->gpio_int2.port) { + return -ENOTSUP; } - ret = gpio_pin_configure_dt(&cfg->interrupt, GPIO_INPUT); - if (ret < 0) { - return ret; + if (cfg->gpio_int1.port) { + if (!gpio_is_ready_dt(&cfg->gpio_int1)) { + LOG_ERR("INT_1 line defined, but not ready"); + return -ENODEV; + } } - gpio_init_callback(&drv_data->gpio_cb, - adxl345_gpio_callback, - BIT(cfg->interrupt.pin)); - - ret = gpio_add_callback(cfg->interrupt.port, &drv_data->gpio_cb); - if (ret < 0) { - LOG_ERR("Failed to set gpio callback!"); - return ret; + if (cfg->gpio_int2.port) { + if (!gpio_is_ready_dt(&cfg->gpio_int2)) { + LOG_ERR("INT_2 line defined, but not ready"); + return -ENODEV; + } } - drv_data->dev = dev; - #if defined(CONFIG_ADXL345_TRIGGER_OWN_THREAD) - k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT); + k_sem_init(&data->gpio_sem, 0, K_SEM_MAX_LIMIT); - k_thread_create(&drv_data->thread, drv_data->thread_stack, + k_thread_create(&data->thread, data->thread_stack, CONFIG_ADXL345_THREAD_STACK_SIZE, - adxl345_thread, drv_data, + adxl345_thread, data, NULL, NULL, K_PRIO_COOP(CONFIG_ADXL345_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_ADXL345_TRIGGER_GLOBAL_THREAD) - drv_data->work.handler = adxl345_work_cb; + data->work.handler = adxl345_work_cb; #endif + if (cfg->gpio_int1.port) { + rc = gpio_pin_configure_dt(&cfg->gpio_int1, GPIO_INPUT); + if (rc < 0) { + return rc; + } + + gpio_init_callback(&data->int1_cb, + adxl345_int1_gpio_callback, + BIT(cfg->gpio_int1.pin)); + + rc = gpio_add_callback(cfg->gpio_int1.port, + &data->int1_cb); + if (rc < 0) { + LOG_ERR("Failed to set INT_1 gpio callback!"); + return -EIO; + } + } + + if (cfg->gpio_int2.port) { + rc = gpio_pin_configure_dt(&cfg->gpio_int2, GPIO_INPUT); + if (rc < 0) { + return rc; + } + + gpio_init_callback(&data->int2_cb, + adxl345_int2_gpio_callback, + BIT(cfg->gpio_int2.pin)); + + rc = gpio_add_callback(cfg->gpio_int2.port, + &data->int2_cb); + if (rc < 0) { + LOG_ERR("Failed to set INT_2 gpio callback!"); + return -EIO; + } + } + + data->dev = dev; + return 0; } diff --git a/dts/bindings/sensor/adi,adxl345-common.yaml b/dts/bindings/sensor/adi,adxl345-common.yaml index 6a3f301e2a778..834de35a234ae 100644 --- a/dts/bindings/sensor/adi,adxl345-common.yaml +++ b/dts/bindings/sensor/adi,adxl345-common.yaml @@ -4,6 +4,27 @@ include: sensor-device.yaml properties: + int1-gpios: + type: phandle-array + description: | + The pin defaults to active high when produced by the sensor. The property + specifies the INT_1 line of the sensor. + + int2-gpios: + type: phandle-array + description: | + The pin defaults to active high when produced by the sensor. The property + specifies the INT_2 line of the sensor. + + drdy-pin: + type: int + enum: [1, 2] + description: | + Specify which of the two interrupt lines (INT_1 or INT_2), if any, + delivers the data ready signal. + - 1 + - 2 + odr: type: int default: 0 @@ -22,10 +43,3 @@ properties: - 3 - 4 - 5 - - int2-gpios: - type: phandle-array - description: | - The INT2 signal defaults to active high as produced by the - sensor. The property value should ensure the flags properly - describe the signal that is presented to the driver.