Add driver for ScioSense ENS160 multi-gas sensor. The driver includes support for I2C and SPI, attributes for setting temperature and humidity compensation and data ready trigger. Also add ScioSense to the list of vendor prefixes. Signed-off-by: Gustavo Silva <gustavograzs@gmail.com>
162 lines
2.8 KiB
C
162 lines
2.8 KiB
C
/*
|
|
* Copyright (c) 2024 Gustavo Silva
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT sciosense_ens160
|
|
|
|
#include <zephyr/drivers/spi.h>
|
|
|
|
#include "ens160.h"
|
|
|
|
LOG_MODULE_DECLARE(ENS160, CONFIG_SENSOR_LOG_LEVEL);
|
|
|
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
|
|
|
|
#define ENS160_SPI_READ_BIT BIT(0)
|
|
|
|
static int ens160_read_reg_spi(const struct device *dev, uint8_t reg, uint8_t *val)
|
|
{
|
|
const struct ens160_config *config = dev->config;
|
|
|
|
uint8_t tx_buffer = (reg << 1) | ENS160_SPI_READ_BIT;
|
|
|
|
const struct spi_buf tx_buf = {
|
|
.buf = &tx_buffer,
|
|
.len = 1,
|
|
};
|
|
|
|
const struct spi_buf_set tx = {
|
|
.buffers = &tx_buf,
|
|
.count = 1,
|
|
};
|
|
|
|
struct spi_buf rx_buf[2] = {
|
|
{
|
|
.buf = NULL,
|
|
.len = 1,
|
|
},
|
|
{
|
|
.buf = val,
|
|
.len = 1,
|
|
}
|
|
};
|
|
|
|
const struct spi_buf_set rx = {
|
|
.buffers = rx_buf,
|
|
.count = 2,
|
|
};
|
|
|
|
return spi_transceive_dt(&config->spi, &tx, &rx);
|
|
}
|
|
|
|
static int ens160_read_data_spi(const struct device *dev, uint8_t start, uint8_t *data, size_t len)
|
|
{
|
|
const struct ens160_config *config = dev->config;
|
|
|
|
uint8_t tx_buffer = (start << 1) | ENS160_SPI_READ_BIT;
|
|
|
|
const struct spi_buf tx_buf = {
|
|
.buf = &tx_buffer,
|
|
.len = 1,
|
|
};
|
|
|
|
const struct spi_buf_set tx = {
|
|
.buffers = &tx_buf,
|
|
.count = 1,
|
|
};
|
|
|
|
struct spi_buf rx_buf[2] = {
|
|
{
|
|
.buf = NULL,
|
|
.len = 1,
|
|
},
|
|
{
|
|
.buf = data,
|
|
.len = len,
|
|
}
|
|
};
|
|
|
|
const struct spi_buf_set rx = {
|
|
.buffers = rx_buf,
|
|
.count = 2,
|
|
};
|
|
|
|
return spi_transceive_dt(&config->spi, &tx, &rx);
|
|
}
|
|
|
|
static int ens160_write_reg_spi(const struct device *dev, uint8_t reg, uint8_t val)
|
|
{
|
|
const struct ens160_config *config = dev->config;
|
|
|
|
uint8_t tx_buffer = reg << 1;
|
|
|
|
const struct spi_buf buf[2] = {
|
|
{
|
|
.buf = &tx_buffer,
|
|
.len = 1,
|
|
},
|
|
{
|
|
.buf = &val,
|
|
.len = 1,
|
|
}
|
|
};
|
|
|
|
const struct spi_buf_set tx = {
|
|
.buffers = buf,
|
|
.count = 2,
|
|
};
|
|
|
|
return spi_write_dt(&config->spi, &tx);
|
|
}
|
|
|
|
static int ens160_write_data_spi(const struct device *dev, uint8_t reg, uint8_t *data, size_t len)
|
|
{
|
|
const struct ens160_config *config = dev->config;
|
|
|
|
uint8_t tx_buffer = reg << 1;
|
|
|
|
const struct spi_buf buf[2] = {
|
|
{
|
|
.buf = &tx_buffer,
|
|
.len = 1,
|
|
},
|
|
{
|
|
.buf = &data,
|
|
.len = len,
|
|
}
|
|
};
|
|
|
|
const struct spi_buf_set tx = {
|
|
.buffers = buf,
|
|
.count = 2,
|
|
};
|
|
|
|
return spi_write_dt(&config->spi, &tx);
|
|
}
|
|
|
|
const struct ens160_transfer_function ens160_spi_transfer_function = {
|
|
.read_reg = ens160_read_reg_spi,
|
|
.read_data = ens160_read_data_spi,
|
|
.write_reg = ens160_write_reg_spi,
|
|
.write_data = ens160_write_data_spi,
|
|
};
|
|
|
|
int ens160_spi_init(const struct device *dev)
|
|
{
|
|
const struct ens160_config *config = dev->config;
|
|
struct ens160_data *data = dev->data;
|
|
|
|
if (!spi_is_ready_dt(&config->spi)) {
|
|
LOG_DBG("SPI bus not ready");
|
|
return -ENODEV;
|
|
}
|
|
|
|
data->tf = &ens160_spi_transfer_function;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
|