diff --git a/drivers/sensor/adxl345/Kconfig b/drivers/sensor/adxl345/Kconfig index 68ba21a87ee..951a94a8d48 100644 --- a/drivers/sensor/adxl345/Kconfig +++ b/drivers/sensor/adxl345/Kconfig @@ -4,7 +4,7 @@ # SPDX-License-Identifier: Apache-2.0 config ADXL345 - bool "ADXL345 Three Axis I2C accelerometer" - depends on I2C + bool "ADXL345 Three Axis accelerometer" + depends on I2C || SPI help Enable driver for ADXL345 Three-Axis Digital Accelerometer. diff --git a/drivers/sensor/adxl345/adxl345.c b/drivers/sensor/adxl345/adxl345.c index cd8319eca7c..dbd96f62024 100644 --- a/drivers/sensor/adxl345/adxl345.c +++ b/drivers/sensor/adxl345/adxl345.c @@ -17,14 +17,99 @@ LOG_MODULE_REGISTER(ADXL345, CONFIG_SENSOR_LOG_LEVEL); +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +static bool adxl345_bus_is_ready_i2c(const union adxl345_bus *bus) +{ + return device_is_ready(bus->i2c.bus); +} + +static int adxl345_reg_access_i2c(const struct device *dev, uint8_t cmd, uint8_t reg_addr, + uint8_t *data, size_t length) +{ + const struct adxl345_dev_config *cfg = dev->config; + + if (cmd == ADXL345_READ_CMD) { + return i2c_burst_read_dt(&cfg->bus.i2c, reg_addr, data, length); + } else { + return i2c_burst_write_dt(&cfg->bus.i2c, reg_addr, data, length); + } +} +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +static bool adxl345_bus_is_ready_spi(const union adxl345_bus *bus) +{ + return spi_is_ready(&bus->spi); +} + +static int adxl345_reg_access_spi(const struct device *dev, uint8_t cmd, uint8_t reg_addr, + 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)}; + struct spi_buf_set tx = { + .buffers = buf, + .count = 2, + }; + + if (cmd == ADXL345_READ_CMD) { + tx.count = 1; + return spi_transceive_dt(&cfg->bus.spi, &tx, &rx); + } else { + return spi_write_dt(&cfg->bus.spi, &tx); + } +} +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +static inline int adxl345_reg_access(const struct device *dev, uint8_t cmd, uint8_t addr, + uint8_t *data, size_t len) +{ + const struct adxl345_dev_config *cfg = dev->config; + + return cfg->reg_access(dev, cmd, addr, data, len); +} + +static inline 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); +} + +static inline 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); +} + +static inline int adxl345_reg_write_byte(const struct device *dev, uint8_t addr, uint8_t val) +{ + return adxl345_reg_write(dev, addr, &val, 1); +} + +static inline int adxl345_reg_read_byte(const struct device *dev, uint8_t addr, uint8_t *buf) + +{ + return adxl345_reg_read(dev, addr, buf, 1); +} + +static inline bool adxl345_bus_is_ready(const struct device *dev) +{ + const struct adxl345_dev_config *cfg = dev->config; + + return cfg->bus_is_ready(&cfg->bus); +} + static int adxl345_read_sample(const struct device *dev, struct adxl345_sample *sample) { - const struct adxl345_dev_config *cfg = dev->config; int16_t raw_x, raw_y, raw_z; uint8_t axis_data[6]; - int rc = i2c_burst_read_dt(&cfg->i2c, ADXL345_X_AXIS_DATA_0_REG, axis_data, 6); + int rc = adxl345_reg_read(dev, ADXL345_X_AXIS_DATA_0_REG, axis_data, 6); if (rc < 0) { LOG_ERR("Samples read failed with rc=%d\n", rc); @@ -56,13 +141,12 @@ static int adxl345_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct adxl345_dev_data *data = dev->data; - const struct adxl345_dev_config *cfg = dev->config; struct adxl345_sample sample; uint8_t samples_count; int rc; data->sample_number = 0; - rc = i2c_reg_read_byte_dt(&cfg->i2c, ADXL345_FIFO_STATUS_REG, &samples_count); + 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; @@ -129,41 +213,40 @@ static int adxl345_init(const struct device *dev) { int rc; struct adxl345_dev_data *data = dev->data; - const struct adxl345_dev_config *cfg = dev->config; uint8_t dev_id; data->sample_number = 0; - if (!device_is_ready(cfg->i2c.bus)) { - LOG_ERR("I2C bus device is not ready"); + if (!adxl345_bus_is_ready(dev)) { + LOG_ERR("bus not ready"); return -ENODEV; } - rc = i2c_reg_read_byte_dt(&cfg->i2c, ADXL345_DEVICE_ID_REG, &dev_id); + rc = adxl345_reg_read_byte(dev, ADXL345_DEVICE_ID_REG, &dev_id); if (rc < 0 || dev_id != ADXL345_PART_ID) { LOG_ERR("Read PART ID failed: 0x%x\n", rc); return -ENODEV; } - rc = i2c_reg_write_byte_dt(&cfg->i2c, ADXL345_FIFO_CTL_REG, ADXL345_FIFO_STREAM_MODE); + 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; } - rc = i2c_reg_write_byte_dt(&cfg->i2c, ADXL345_DATA_FORMAT_REG, ADXL345_RANGE_16G); + rc = adxl345_reg_write_byte(dev, ADXL345_DATA_FORMAT_REG, ADXL345_RANGE_16G); if (rc < 0) { LOG_ERR("Data format set failed\n"); return -EIO; } - rc = i2c_reg_write_byte_dt(&cfg->i2c, ADXL345_RATE_REG, ADXL345_RATE_25HZ); + rc = adxl345_reg_write_byte(dev, ADXL345_RATE_REG, ADXL345_RATE_25HZ); if (rc < 0) { LOG_ERR("Rate setting failed\n"); return -EIO; } - rc = i2c_reg_write_byte_dt(&cfg->i2c, ADXL345_POWER_CTL_REG, ADXL345_ENABLE_MEASURE_BIT); + 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; @@ -172,13 +255,32 @@ static int adxl345_init(const struct device *dev) return 0; } +#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, \ + } + +#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, \ + } + #define ADXL345_DEFINE(inst) \ static struct adxl345_dev_data adxl345_data_##inst; \ \ - static const struct adxl345_dev_config adxl345_config_##inst = { \ - .i2c = I2C_DT_SPEC_INST_GET(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))); \ + \ DEVICE_DT_INST_DEFINE(inst, adxl345_init, NULL, \ &adxl345_data_##inst, &adxl345_config_##inst, POST_KERNEL,\ CONFIG_SENSOR_INIT_PRIORITY, &adxl345_api_funcs); \ diff --git a/drivers/sensor/adxl345/adxl345.h b/drivers/sensor/adxl345/adxl345.h index 4f7f6422a12..35412ac7c8b 100644 --- a/drivers/sensor/adxl345/adxl345.h +++ b/drivers/sensor/adxl345/adxl345.h @@ -10,9 +10,20 @@ #include #include #include +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) #include +#endif +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif #include +/* ADXL345 communication commands */ +#define ADXL345_WRITE_CMD 0x00 +#define ADXL345_READ_CMD 0x80 +#define ADXL345_MULTIBYTE_FLAG 0x40 + +/* Registers */ #define ADXL345_DEVICE_ID_REG 0x00 #define ADXL345_RATE_REG 0x2c #define ADXL345_POWER_CTL_REG 0x2d @@ -49,8 +60,23 @@ struct adxl345_sample { int16_t z; }; -struct adxl345_dev_config { +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); + +struct adxl345_dev_config { + const union adxl345_bus bus; + adxl345_bus_is_ready_fn bus_is_ready; + adxl345_reg_access_fn reg_access; }; #endif /* ZEPHYR_DRIVERS_SENSOR_ADX345_ADX345_H_ */