drivers: bme280: get dependencies straight from DT
Now that we have various convenience macros in drivers/spi.h and device.h defined, we can resolve some longstanding TODO items in how this driver gets a hold of the devices it depends on: - get bus devices with DEVICE_DT_GET - get SPI chip select information with SPI_CONFIG_DT_INST The results are shorter on boilerplate, save RAM, and improve boot time. The same techniques could be reused by other device drivers. These changes require that the SPI bus and GPIO (for device CS) devices used to interface with the BME280 are defined in devicetree. Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This commit is contained in:
parent
193b8872cd
commit
8c2709e81a
1 changed files with 88 additions and 203 deletions
|
@ -20,6 +20,9 @@
|
|||
|
||||
#include "bme280.h"
|
||||
|
||||
#define BME280_SPI_OPERATION (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | \
|
||||
SPI_MODE_CPOL | SPI_MODE_CPHA)
|
||||
|
||||
#define DT_DRV_COMPAT bosch_bme280
|
||||
|
||||
#define BME280_BUS_SPI DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
|
||||
|
@ -31,22 +34,7 @@ LOG_MODULE_REGISTER(BME280, CONFIG_SENSOR_LOG_LEVEL);
|
|||
#warning "BME280 driver enabled without any devices"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This driver is an example of why devices should be resolvable at
|
||||
* link time instead of only at runtime via device_get_binding().
|
||||
*
|
||||
* We only need to store 'bus' and 'spi_cs' in RAM because we can't
|
||||
* resolve devices at link time. They should be moved to ROM if that
|
||||
* becomes possible. That would in turn enable several further
|
||||
* cleanups.
|
||||
*/
|
||||
|
||||
struct bme280_data {
|
||||
const struct device *bus;
|
||||
#if BME280_BUS_SPI
|
||||
struct spi_cs_control spi_cs;
|
||||
#endif
|
||||
|
||||
/* Compensation parameters. */
|
||||
uint16_t dig_t1;
|
||||
int16_t dig_t2;
|
||||
|
@ -82,14 +70,9 @@ struct bme280_data {
|
|||
#endif
|
||||
};
|
||||
|
||||
struct bme280_spi_cfg {
|
||||
struct spi_config spi_cfg;
|
||||
const char *cs_gpios_label;
|
||||
};
|
||||
|
||||
union bme280_bus_config {
|
||||
#if BME280_BUS_SPI
|
||||
const struct bme280_spi_cfg *spi_cfg;
|
||||
struct spi_config spi_cfg;
|
||||
#endif
|
||||
#if BME280_BUS_I2C
|
||||
uint16_t i2c_addr;
|
||||
|
@ -97,11 +80,13 @@ union bme280_bus_config {
|
|||
};
|
||||
|
||||
struct bme280_config {
|
||||
const char *bus_label;
|
||||
const struct bme280_reg_io *reg_io;
|
||||
const struct device *bus;
|
||||
const struct bme280_bus_io *bus_io;
|
||||
const union bme280_bus_config bus_config;
|
||||
};
|
||||
|
||||
typedef int (*bme280_bus_check_fn)(const struct device *bus,
|
||||
const union bme280_bus_config *bus_config);
|
||||
typedef int (*bme280_reg_read_fn)(const struct device *bus,
|
||||
const union bme280_bus_config *bus_config,
|
||||
uint8_t start, uint8_t *buf, int size);
|
||||
|
@ -109,7 +94,8 @@ typedef int (*bme280_reg_write_fn)(const struct device *bus,
|
|||
const union bme280_bus_config *bus_config,
|
||||
uint8_t reg, uint8_t val);
|
||||
|
||||
struct bme280_reg_io {
|
||||
struct bme280_bus_io {
|
||||
bme280_bus_check_fn check;
|
||||
bme280_reg_read_fn read;
|
||||
bme280_reg_write_fn write;
|
||||
};
|
||||
|
@ -126,19 +112,34 @@ static inline const struct bme280_config *to_config(const struct device *dev)
|
|||
|
||||
static inline const struct device *to_bus(const struct device *dev)
|
||||
{
|
||||
return to_data(dev)->bus;
|
||||
return to_config(dev)->bus;
|
||||
}
|
||||
|
||||
static inline const union bme280_bus_config *to_bus_config(const struct device *dev)
|
||||
static inline const union bme280_bus_config*
|
||||
to_bus_config(const struct device *dev)
|
||||
{
|
||||
return &to_config(dev)->bus_config;
|
||||
}
|
||||
|
||||
#if BME280_BUS_SPI
|
||||
static inline const struct spi_config *
|
||||
to_spi_config(const union bme280_bus_config *bus_config)
|
||||
static int bme280_bus_check_spi(const struct device *bus,
|
||||
const union bme280_bus_config *bus_config)
|
||||
{
|
||||
return &bus_config->spi_cfg->spi_cfg;
|
||||
const struct spi_cs_control *cs;
|
||||
|
||||
if (!device_is_ready(bus)) {
|
||||
LOG_DBG("SPI bus %s not ready", bus->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
cs = bus_config->spi_cfg.cs;
|
||||
if (cs && !device_is_ready(cs->gpio_dev)) {
|
||||
LOG_DBG("SPI CS GPIO controller %s not ready",
|
||||
cs->gpio_dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bme280_reg_read_spi(const struct device *bus,
|
||||
|
@ -172,7 +173,7 @@ static int bme280_reg_read_spi(const struct device *bus,
|
|||
addr = (start + i) | 0x80;
|
||||
rx_buf[1].buf = &buf[i];
|
||||
|
||||
ret = spi_transceive(bus, to_spi_config(bus_config), &tx, &rx);
|
||||
ret = spi_transceive(bus, &bus_config->spi_cfg, &tx, &rx);
|
||||
if (ret) {
|
||||
LOG_DBG("spi_transceive FAIL %d\n", ret);
|
||||
return ret;
|
||||
|
@ -197,7 +198,7 @@ static int bme280_reg_write_spi(const struct device *bus,
|
|||
};
|
||||
int ret;
|
||||
|
||||
ret = spi_write(bus, to_spi_config(bus_config), &tx);
|
||||
ret = spi_write(bus, &bus_config->spi_cfg, &tx);
|
||||
if (ret) {
|
||||
LOG_DBG("spi_write FAIL %d\n", ret);
|
||||
return ret;
|
||||
|
@ -205,13 +206,20 @@ static int bme280_reg_write_spi(const struct device *bus,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct bme280_reg_io bme280_reg_io_spi = {
|
||||
static const struct bme280_bus_io bme280_bus_io_spi = {
|
||||
.check = bme280_bus_check_spi,
|
||||
.read = bme280_reg_read_spi,
|
||||
.write = bme280_reg_write_spi,
|
||||
};
|
||||
#endif /* BME280_BUS_SPI */
|
||||
|
||||
#if BME280_BUS_I2C
|
||||
static int bme280_bus_check_i2c(const struct device *bus,
|
||||
const union bme280_bus_config *bus_config)
|
||||
{
|
||||
return device_is_ready(bus) ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static int bme280_reg_read_i2c(const struct device *bus,
|
||||
const union bme280_bus_config *bus_config,
|
||||
uint8_t start, uint8_t *buf, int size)
|
||||
|
@ -228,23 +236,29 @@ static int bme280_reg_write_i2c(const struct device *bus,
|
|||
reg, val);
|
||||
}
|
||||
|
||||
static const struct bme280_reg_io bme280_reg_io_i2c = {
|
||||
static const struct bme280_bus_io bme280_bus_io_i2c = {
|
||||
.check = bme280_bus_check_i2c,
|
||||
.read = bme280_reg_read_i2c,
|
||||
.write = bme280_reg_write_i2c,
|
||||
};
|
||||
#endif /* BME280_BUS_I2C */
|
||||
|
||||
static inline int bme280_bus_check(const struct device *dev)
|
||||
{
|
||||
return to_config(dev)->bus_io->check(to_bus(dev), to_bus_config(dev));
|
||||
}
|
||||
|
||||
static inline int bme280_reg_read(const struct device *dev,
|
||||
uint8_t start, uint8_t *buf, int size)
|
||||
{
|
||||
return to_config(dev)->reg_io->read(to_bus(dev), to_bus_config(dev),
|
||||
return to_config(dev)->bus_io->read(to_bus(dev), to_bus_config(dev),
|
||||
start, buf, size);
|
||||
}
|
||||
|
||||
static inline int bme280_reg_write(const struct device *dev, uint8_t reg,
|
||||
uint8_t val)
|
||||
{
|
||||
return to_config(dev)->reg_io->write(to_bus(dev), to_bus_config(dev),
|
||||
return to_config(dev)->bus_io->write(to_bus(dev), to_bus_config(dev),
|
||||
reg, val);
|
||||
}
|
||||
|
||||
|
@ -469,6 +483,15 @@ static int bme280_chip_init(const struct device *dev)
|
|||
struct bme280_data *data = to_data(dev);
|
||||
int err;
|
||||
|
||||
LOG_DBG("initializing \"%s\" on bus \"%s\"",
|
||||
dev->name, to_bus(dev)->name);
|
||||
|
||||
err = bme280_bus_check(dev);
|
||||
if (err < 0) {
|
||||
LOG_DBG("bus check failed: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bme280_reg_read(dev, BME280_REG_ID, &data->chip_id, 1);
|
||||
if (err < 0) {
|
||||
LOG_DBG("ID read failed: %d", err);
|
||||
|
@ -513,90 +536,12 @@ static int bme280_chip_init(const struct device *dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if BME280_BUS_SPI
|
||||
static inline int bme280_is_on_spi(const struct device *dev)
|
||||
{
|
||||
return to_config(dev)->reg_io == &bme280_reg_io_spi;
|
||||
}
|
||||
|
||||
static inline int bme280_spi_init(const struct device *dev)
|
||||
{
|
||||
struct bme280_data *data = to_data(dev);
|
||||
const struct bme280_spi_cfg *spi_cfg = to_bus_config(dev)->spi_cfg;
|
||||
|
||||
if (spi_cfg->cs_gpios_label != NULL) {
|
||||
data->spi_cs.gpio_dev = device_get_binding(
|
||||
spi_cfg->cs_gpios_label);
|
||||
if (!data->spi_cs.gpio_dev) {
|
||||
LOG_DBG("can't get GPIO SPI CS device %s",
|
||||
spi_cfg->cs_gpios_label);
|
||||
return -ENODEV;
|
||||
}
|
||||
} else {
|
||||
LOG_DBG("no chip select set");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int bme280_is_on_spi(const struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int bme280_spi_init(const struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int bme280_init(const struct device *dev)
|
||||
{
|
||||
const char *name = dev->name;
|
||||
struct bme280_data *data = to_data(dev);
|
||||
const struct bme280_config *config = to_config(dev);
|
||||
int rc;
|
||||
|
||||
LOG_DBG("initializing %s", name);
|
||||
|
||||
data->bus = device_get_binding(config->bus_label);
|
||||
if (!data->bus) {
|
||||
LOG_DBG("bus \"%s\" not found", config->bus_label);
|
||||
rc = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (bme280_is_on_spi(dev)) {
|
||||
rc = bme280_spi_init(dev);
|
||||
if (rc < 0) {
|
||||
rc = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
rc = bme280_chip_init(dev);
|
||||
if (rc < 0) {
|
||||
rc = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
/* Set power state to ACTIVE */
|
||||
data->pm_state = DEVICE_PM_ACTIVE_STATE;
|
||||
#endif
|
||||
|
||||
done:
|
||||
if (rc == 0) {
|
||||
LOG_DBG("%s OK", name);
|
||||
} else {
|
||||
LOG_DBG("%s failed", name);
|
||||
}
|
||||
return rc;
|
||||
LOG_DBG("\"%s\" OK", dev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
|
@ -651,15 +596,37 @@ int bme280_pm_ctrl(const struct device *dev, uint32_t ctrl_command,
|
|||
}
|
||||
#endif /* CONFIG_PM_DEVICE */
|
||||
|
||||
/* Initializes a struct bme280_config for an instance on a SPI bus. */
|
||||
#define BME280_CONFIG_SPI(inst) \
|
||||
{ \
|
||||
.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \
|
||||
.bus_io = &bme280_bus_io_spi, \
|
||||
.bus_config.spi_cfg = \
|
||||
SPI_CONFIG_DT_INST(inst, \
|
||||
BME280_SPI_OPERATION, \
|
||||
0), \
|
||||
}
|
||||
|
||||
/* Initializes a struct bme280_config for an instance on an I2C bus. */
|
||||
#define BME280_CONFIG_I2C(inst) \
|
||||
{ \
|
||||
.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \
|
||||
.bus_io = &bme280_bus_io_i2c, \
|
||||
.bus_config.i2c_addr = DT_INST_REG_ADDR(inst), \
|
||||
}
|
||||
|
||||
/*
|
||||
* Device creation macro, shared by BME280_DEFINE_SPI() and
|
||||
* BME280_DEFINE_I2C().
|
||||
* Main instantiation macro, which selects the correct bus-specific
|
||||
* instantiation macros for the instance.
|
||||
*/
|
||||
|
||||
#define BME280_DEVICE_INIT(inst) \
|
||||
#define BME280_DEFINE(inst) \
|
||||
static struct bme280_data bme280_data_##inst; \
|
||||
static const struct bme280_config bme280_config_##inst = \
|
||||
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
|
||||
(BME280_CONFIG_SPI(inst)), \
|
||||
(BME280_CONFIG_I2C(inst))); \
|
||||
DEVICE_DT_INST_DEFINE(inst, \
|
||||
bme280_init, \
|
||||
bme280_chip_init, \
|
||||
bme280_pm_ctrl, \
|
||||
&bme280_data_##inst, \
|
||||
&bme280_config_##inst, \
|
||||
|
@ -667,87 +634,5 @@ int bme280_pm_ctrl(const struct device *dev, uint32_t ctrl_command,
|
|||
CONFIG_SENSOR_INIT_PRIORITY, \
|
||||
&bme280_api_funcs);
|
||||
|
||||
/*
|
||||
* Instantiation macros used when a device is on a SPI bus.
|
||||
*/
|
||||
|
||||
#define BME280_HAS_CS(inst) DT_INST_SPI_DEV_HAS_CS_GPIOS(inst)
|
||||
|
||||
#define BME280_DATA_SPI_CS(inst) \
|
||||
{ .spi_cs = { \
|
||||
.gpio_pin = DT_INST_SPI_DEV_CS_GPIOS_PIN(inst), \
|
||||
.gpio_dt_flags = DT_INST_SPI_DEV_CS_GPIOS_FLAGS(inst), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define BME280_DATA_SPI(inst) \
|
||||
COND_CODE_1(BME280_HAS_CS(inst), \
|
||||
(BME280_DATA_SPI_CS(inst)), \
|
||||
({}))
|
||||
|
||||
#define BME280_SPI_CS_PTR(inst) \
|
||||
COND_CODE_1(BME280_HAS_CS(inst), \
|
||||
(&(bme280_data_##inst.spi_cs)), \
|
||||
(NULL))
|
||||
|
||||
#define BME280_SPI_CS_LABEL(inst) \
|
||||
COND_CODE_1(BME280_HAS_CS(inst), \
|
||||
(DT_INST_SPI_DEV_CS_GPIOS_LABEL(inst)), (NULL))
|
||||
|
||||
#define BME280_SPI_CFG(inst) \
|
||||
(&(struct bme280_spi_cfg) { \
|
||||
.spi_cfg = { \
|
||||
.frequency = \
|
||||
DT_INST_PROP(inst, spi_max_frequency), \
|
||||
.operation = (SPI_WORD_SET(8) | \
|
||||
SPI_TRANSFER_MSB | \
|
||||
SPI_MODE_CPOL | \
|
||||
SPI_MODE_CPHA), \
|
||||
.slave = DT_INST_REG_ADDR(inst), \
|
||||
.cs = BME280_SPI_CS_PTR(inst), \
|
||||
}, \
|
||||
.cs_gpios_label = BME280_SPI_CS_LABEL(inst), \
|
||||
})
|
||||
|
||||
#define BME280_CONFIG_SPI(inst) \
|
||||
{ \
|
||||
.bus_label = DT_INST_BUS_LABEL(inst), \
|
||||
.reg_io = &bme280_reg_io_spi, \
|
||||
.bus_config = { .spi_cfg = BME280_SPI_CFG(inst) } \
|
||||
}
|
||||
|
||||
#define BME280_DEFINE_SPI(inst) \
|
||||
static struct bme280_data bme280_data_##inst = \
|
||||
BME280_DATA_SPI(inst); \
|
||||
static const struct bme280_config bme280_config_##inst = \
|
||||
BME280_CONFIG_SPI(inst); \
|
||||
BME280_DEVICE_INIT(inst)
|
||||
|
||||
/*
|
||||
* Instantiation macros used when a device is on an I2C bus.
|
||||
*/
|
||||
|
||||
#define BME280_CONFIG_I2C(inst) \
|
||||
{ \
|
||||
.bus_label = DT_INST_BUS_LABEL(inst), \
|
||||
.reg_io = &bme280_reg_io_i2c, \
|
||||
.bus_config = { .i2c_addr = DT_INST_REG_ADDR(inst), } \
|
||||
}
|
||||
|
||||
#define BME280_DEFINE_I2C(inst) \
|
||||
static struct bme280_data bme280_data_##inst; \
|
||||
static const struct bme280_config bme280_config_##inst = \
|
||||
BME280_CONFIG_I2C(inst); \
|
||||
BME280_DEVICE_INIT(inst)
|
||||
|
||||
/*
|
||||
* Main instantiation macro. Use of COND_CODE_1() selects the right
|
||||
* bus-specific macro at preprocessor time.
|
||||
*/
|
||||
|
||||
#define BME280_DEFINE(inst) \
|
||||
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
|
||||
(BME280_DEFINE_SPI(inst)), \
|
||||
(BME280_DEFINE_I2C(inst)))
|
||||
|
||||
/* Create the struct device for every status "okay" node in the devicetree. */
|
||||
DT_INST_FOREACH_STATUS_OKAY(BME280_DEFINE)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue