sensor: bmm150: Add I2C-base or SPI-base interface in build time

move DT_DRV_COMPAT to bmm150.h. so that can be decide which interface
to use.

define struct bmm150_bus_io interface for bmm150_i2c.c and bmm150_spi.c
in bmm150.h.

redefined bus operation interface in bmm150.c, this allow the driver
to decide which interface to use during construction.

Signed-off-by: Weiwei Guo <guoweiwei@syriusrobotics.com>
This commit is contained in:
Weiwei Guo 2022-11-02 14:41:57 +08:00 committed by Carles Cufí
parent 012ae578e1
commit 08ece57b9e
9 changed files with 326 additions and 68 deletions

View file

@ -1,5 +1,4 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources(bmm150.c)
zephyr_library_sources(bmm150.c bmm150_i2c.c bmm150_spi.c)

View file

@ -6,8 +6,6 @@
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT bosch_bmm150
#include <zephyr/logging/log.h>
#include "bmm150.h"
@ -36,15 +34,59 @@ static const struct bmm150_preset {
[BMM150_HIGH_ACCURACY_PRESET] = { 47, 83, 20 }
};
static inline int bmm150_bus_check(const struct device *dev)
{
const struct bmm150_config *cfg = dev->config;
return cfg->bus_io->check(&cfg->bus);
}
static inline int bmm150_reg_read(const struct device *dev,
uint8_t start, uint8_t *buf, int size)
{
const struct bmm150_config *cfg = dev->config;
return cfg->bus_io->read(&cfg->bus, start, buf, size);
}
static inline int bmm150_reg_write(const struct device *dev, uint8_t reg,
uint8_t val)
{
const struct bmm150_config *cfg = dev->config;
return cfg->bus_io->write(&cfg->bus, reg, val);
}
int bmm150_reg_update_byte(const struct device *dev, uint8_t reg,
uint8_t mask, uint8_t value)
{
int ret = 0;
uint8_t old_value, new_value;
ret = bmm150_reg_read(dev, reg, &old_value, 1);
if (ret < 0) {
goto failed;
}
new_value = (old_value & ~mask) | (value & mask);
if (new_value == old_value) {
return 0;
}
return bmm150_reg_write(dev, reg, new_value);
failed:
return ret;
}
static int bmm150_set_power_mode(const struct device *dev,
enum bmm150_power_modes mode,
int state)
{
const struct bmm150_config *config = dev->config;
switch (mode) {
case BMM150_POWER_MODE_SUSPEND:
if (i2c_reg_update_byte_dt(&config->i2c,
if (bmm150_reg_update_byte(dev,
BMM150_REG_POWER,
BMM150_MASK_POWER_CTL,
!state) < 0) {
@ -54,14 +96,14 @@ static int bmm150_set_power_mode(const struct device *dev,
return 0;
case BMM150_POWER_MODE_SLEEP:
return i2c_reg_update_byte_dt(&config->i2c,
return bmm150_reg_update_byte(dev,
BMM150_REG_OPMODE_ODR,
BMM150_MASK_OPMODE,
BMM150_MODE_SLEEP <<
BMM150_SHIFT_OPMODE);
break;
case BMM150_POWER_MODE_NORMAL:
return i2c_reg_update_byte_dt(&config->i2c,
return bmm150_reg_update_byte(dev,
BMM150_REG_OPMODE_ODR,
BMM150_MASK_OPMODE,
BMM150_MODE_NORMAL <<
@ -75,12 +117,11 @@ static int bmm150_set_power_mode(const struct device *dev,
static int bmm150_set_odr(const struct device *dev, uint8_t val)
{
const struct bmm150_config *config = dev->config;
uint8_t i;
for (i = 0U; i < ARRAY_SIZE(bmm150_samp_freq_table); ++i) {
if (val <= bmm150_samp_freq_table[i].freq) {
return i2c_reg_update_byte_dt(&config->i2c,
return bmm150_reg_update_byte(dev,
BMM150_REG_OPMODE_ODR,
BMM150_MASK_ODR,
(bmm150_samp_freq_table[i].reg_val <<
@ -97,8 +138,7 @@ static int bmm150_read_rep_xy(const struct device *dev)
const struct bmm150_config *config = dev->config;
uint8_t reg_val;
if (i2c_reg_read_byte_dt(&config->i2c,
BMM150_REG_REP_XY, &reg_val) < 0) {
if (bmm150_reg_read(dev, BMM150_REG_REP_XY, &reg_val, 1) < 0) {
return -EIO;
}
@ -113,8 +153,7 @@ static int bmm150_read_rep_z(const struct device *dev)
const struct bmm150_config *config = dev->config;
uint8_t reg_val;
if (i2c_reg_read_byte_dt(&config->i2c,
BMM150_REG_REP_Z, &reg_val) < 0) {
if (bmm150_reg_read(dev, BMM150_REG_REP_Z, &reg_val, 1) < 0) {
return -EIO;
}
@ -160,8 +199,7 @@ static int bmm150_read_odr(const struct device *dev)
const struct bmm150_config *config = dev->config;
uint8_t i, odr_val, reg_val;
if (i2c_reg_read_byte_dt(&config->i2c,
BMM150_REG_OPMODE_ODR, &reg_val) < 0) {
if (bmm150_reg_read(dev, BMM150_REG_OPMODE_ODR, &reg_val, 1) < 0) {
return -EIO;
}
@ -184,7 +222,7 @@ static int bmm150_write_rep_xy(const struct device *dev, int val)
struct bmm150_data *data = dev->data;
const struct bmm150_config *config = dev->config;
if (i2c_reg_update_byte_dt(&config->i2c,
if (bmm150_reg_update_byte(dev,
BMM150_REG_REP_XY,
BMM150_REG_REP_DATAMASK,
BMM150_REPXY_TO_REGVAL(val)) < 0) {
@ -203,7 +241,7 @@ static int bmm150_write_rep_z(const struct device *dev, int val)
struct bmm150_data *data = dev->data;
const struct bmm150_config *config = dev->config;
if (i2c_reg_update_byte_dt(&config->i2c,
if (bmm150_reg_update_byte(dev,
BMM150_REG_REP_Z,
BMM150_REG_REP_DATAMASK,
BMM150_REPZ_TO_REGVAL(val)) < 0) {
@ -286,7 +324,6 @@ static int bmm150_sample_fetch(const struct device *dev,
{
struct bmm150_data *drv_data = dev->data;
const struct bmm150_config *config = dev->config;
uint16_t values[BMM150_AXIS_XYZR_MAX];
int16_t raw_x, raw_y, raw_z;
uint16_t rhall;
@ -294,9 +331,7 @@ static int bmm150_sample_fetch(const struct device *dev,
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL ||
chan == SENSOR_CHAN_MAGN_XYZ);
if (i2c_burst_read_dt(&config->i2c,
BMM150_REG_X_L, (uint8_t *)values,
sizeof(values)) < 0) {
if (bmm150_reg_read(dev, BMM150_REG_X_L, (uint8_t *)values, sizeof(values)) < 0) {
LOG_ERR("failed to read sample");
return -EIO;
}
@ -483,28 +518,31 @@ static const struct sensor_driver_api bmm150_api_funcs = {
static int bmm150_init_chip(const struct device *dev)
{
struct bmm150_data *data = dev->data;
const struct bmm150_config *config = dev->config;
uint8_t chip_id;
struct bmm150_preset preset;
if (bmm150_set_power_mode(dev, BMM150_POWER_MODE_NORMAL, 0) < 0) {
LOG_ERR("failed to bring up device from normal mode");
return -EIO;
/* Soft reset chip */
if (bmm150_reg_update_byte(dev, BMM150_REG_POWER, BMM150_MASK_SOFT_RESET,
BMM150_SOFT_RESET) < 0) {
LOG_ERR("failed reset chip");
goto err_poweroff;
}
if (bmm150_set_power_mode(dev, BMM150_POWER_MODE_SUSPEND, 1) < 0) {
LOG_ERR("failed to bring up device in suspend mode");
return -EIO;
}
/* Sleep for 1ms after software reset */
k_sleep(K_MSEC(1));
/* Suspend mode to sleep mode */
if (bmm150_set_power_mode(dev, BMM150_POWER_MODE_SUSPEND, 0)
< 0) {
LOG_ERR("failed to bring up device from suspend mode");
return -EIO;
}
if (i2c_reg_read_byte_dt(&config->i2c,
BMM150_REG_CHIP_ID, &chip_id) < 0) {
/* Sleep for 3ms from suspend to sleep mode */
k_sleep(K_MSEC(3));
/* Read chip ID */
if (bmm150_reg_read(dev, BMM150_REG_CHIP_ID, &chip_id, 1) < 0) {
LOG_ERR("failed reading chip id");
goto err_poweroff;
}
@ -514,6 +552,7 @@ static int bmm150_init_chip(const struct device *dev)
goto err_poweroff;
}
/* Setting preset mode */
preset = bmm150_presets_table[BMM150_DEFAULT_PRESET];
if (bmm150_set_odr(dev, preset.odr) < 0) {
LOG_ERR("failed to set ODR to %d",
@ -521,30 +560,27 @@ static int bmm150_init_chip(const struct device *dev)
goto err_poweroff;
}
if (i2c_reg_write_byte_dt(&config->i2c,
BMM150_REG_REP_XY,
BMM150_REPXY_TO_REGVAL(preset.rep_xy))
if (bmm150_reg_write(dev, BMM150_REG_REP_XY, BMM150_REPXY_TO_REGVAL(preset.rep_xy))
< 0) {
LOG_ERR("failed to set REP XY to %d",
preset.rep_xy);
goto err_poweroff;
}
if (i2c_reg_write_byte_dt(&config->i2c,
BMM150_REG_REP_Z,
BMM150_REPZ_TO_REGVAL(preset.rep_z)) < 0) {
if (bmm150_reg_write(dev, BMM150_REG_REP_Z, BMM150_REPZ_TO_REGVAL(preset.rep_z)) < 0) {
LOG_ERR("failed to set REP Z to %d",
preset.rep_z);
goto err_poweroff;
}
/* Set chip normal mode */
if (bmm150_set_power_mode(dev, BMM150_POWER_MODE_NORMAL, 1)
< 0) {
LOG_ERR("failed to power on device");
}
if (i2c_burst_read_dt(&config->i2c,
BMM150_REG_TRIM_START, (uint8_t *)&data->tregs,
/* Reads the trim registers of the sensor */
if (bmm150_reg_read(dev, BMM150_REG_TRIM_START, (uint8_t *)&data->tregs,
sizeof(data->tregs)) < 0) {
LOG_ERR("failed to read trim regs");
goto err_poweroff;
@ -574,12 +610,12 @@ err_poweroff:
static int bmm150_init(const struct device *dev)
{
const struct bmm150_config *const config =
dev->config;
int err = 0;
if (!device_is_ready(config->i2c.bus)) {
LOG_ERR("I2C bus device not ready");
return -ENODEV;
err = bmm150_bus_check(dev);
if (err < 0) {
LOG_DBG("bus check failed: %d", err);
return err;
}
if (bmm150_init_chip(dev) < 0) {
@ -590,15 +626,37 @@ static int bmm150_init(const struct device *dev)
return 0;
}
#define BMM150_DEFINE(inst) \
static struct bmm150_data bmm150_data_##inst; \
\
static const struct bmm150_config bmm150_config_##inst = { \
.i2c = I2C_DT_SPEC_INST_GET(inst), \
}; \
\
SENSOR_DEVICE_DT_INST_DEFINE(inst, bmm150_init, NULL, \
&bmm150_data_##inst, &bmm150_config_##inst, POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, &bmm150_api_funcs); \
/* Initializes a struct bmm150_config for an instance on a SPI bus. */
#define BMM150_CONFIG_SPI(inst) \
.bus.spi = SPI_DT_SPEC_INST_GET(inst, BMM150_SPI_OPERATION, 0), \
.bus_io = &bmm150_bus_io_spi,
/* Initializes a struct bmm150_config for an instance on an I2C bus. */
#define BMM150_CONFIG_I2C(inst) \
.bus.i2c = I2C_DT_SPEC_INST_GET(inst), \
.bus_io = &bmm150_bus_io_i2c,
#define BMM150_BUS_CFG(inst) \
COND_CODE_1(DT_INST_ON_BUS(inst, i2c), \
(BMM150_CONFIG_I2C(inst)), \
(BMM150_CONFIG_SPI(inst)))
/*
* Main instantiation macro, which selects the correct bus-specific
* instantiation macros for the instance.
*/
#define BMM150_DEFINE(inst) \
static struct bmm150_data bmm150_data_##inst; \
static const struct bmm150_config bmm150_config_##inst = { \
BMM150_BUS_CFG(inst) \
}; \
SENSOR_DEVICE_DT_INST_DEFINE(inst, \
bmm150_init, NULL, \
&bmm150_data_##inst, \
&bmm150_config_##inst, \
POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, \
&bmm150_api_funcs);
/* Create the struct device for every status "okay" node in the devicetree. */
DT_INST_FOREACH_STATUS_OKAY(BMM150_DEFINE)

View file

@ -9,6 +9,47 @@
#ifndef ZEPHYR_DRIVERS_SENSOR_BMM150_BMM150_H_
#define ZEPHYR_DRIVERS_SENSOR_BMM150_BMM150_H_
#include <zephyr/types.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/i2c.h>
#define DT_DRV_COMPAT bosch_bmm150
#define BMM150_BUS_SPI DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
#define BMM150_BUS_I2C DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
union bmm150_bus {
#if BMM150_BUS_SPI
struct spi_dt_spec spi;
#endif
#if BMM150_BUS_I2C
struct i2c_dt_spec i2c;
#endif
};
typedef int (*bmm150_bus_check_fn)(const union bmm150_bus *bus);
typedef int (*bmm150_reg_read_fn)(const union bmm150_bus *bus,
uint8_t start, uint8_t *buf, int size);
typedef int (*bmm150_reg_write_fn)(const union bmm150_bus *bus,
uint8_t reg, uint8_t val);
struct bmm150_bus_io {
bmm150_bus_check_fn check;
bmm150_reg_read_fn read;
bmm150_reg_write_fn write;
};
#if BMM150_BUS_SPI
#define BMM150_SPI_OPERATION (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | \
SPI_MODE_CPOL | SPI_MODE_CPHA)
extern const struct bmm150_bus_io bmm150_bus_io_spi;
#endif
#if BMM150_BUS_I2C
extern const struct bmm150_bus_io bmm150_bus_io_i2c;
#endif
#include <zephyr/types.h>
#include <zephyr/drivers/i2c.h>
@ -41,6 +82,8 @@
#define BMM150_REG_POWER 0x4B
#define BMM150_MASK_POWER_CTL BIT(0)
#define BMM150_MASK_SOFT_RESET (BIT(1) | BIT(7))
#define BMM150_SOFT_RESET 0x81
#define BMM150_REG_OPMODE_ODR 0x4C
#define BMM150_MASK_OPMODE (BIT(2) | BIT(1))
@ -66,7 +109,7 @@
#define BMM150_REGVAL_TO_REPXY(regval) (((regval) * 2) + 1)
#define BMM150_REGVAL_TO_REPZ(regval) ((regval) + 1)
#define BMM150_REPXY_TO_REGVAL(rep) (((rep) - 1) / 2)
#define BMM150_REPZ_TO_REGVAL(rep) ((rep) - 1)
#define BMM150_REPZ_TO_REGVAL(rep) BMM150_REPXY_TO_REGVAL(rep)
#define BMM150_REG_INT 0x4D
@ -92,11 +135,6 @@
#define BMM150_MAGN_SET_ATTR
#endif
struct bmm150_config {
struct i2c_dt_spec i2c;
};
struct bmm150_trim_regs {
int8_t x1;
int8_t y1;
@ -114,6 +152,11 @@ struct bmm150_trim_regs {
uint8_t xy1;
} __packed;
struct bmm150_config {
union bmm150_bus bus;
const struct bmm150_bus_io *bus_io;
};
struct bmm150_data {
struct k_sem sem;
struct bmm150_trim_regs tregs;
@ -153,4 +196,7 @@ enum bmm150_presets {
#define BMM150_DEFAULT_PRESET BMM150_HIGH_ACCURACY_PRESET
#endif
int bmm150_reg_update_byte(const struct device *dev, uint8_t reg,
uint8_t mask, uint8_t value);
#endif /* __SENSOR_BMM150_H__ */

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2016, 2017 Intel Corporation
* Copyright (c) 2017 IpTronix S.r.l.
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Bus-specific functionality for BMM150s accessed via I2C.
*/
#include "bmm150.h"
#if BMM150_BUS_I2C
static int bmm150_bus_check_i2c(const union bmm150_bus *bus)
{
return i2c_is_ready_dt(&bus->i2c) ? 0 : -ENODEV;
}
static int bmm150_reg_read_i2c(const union bmm150_bus *bus,
uint8_t start, uint8_t *buf, int size)
{
return i2c_burst_read_dt(&bus->i2c, start, buf, size);
}
static int bmm150_reg_write_i2c(const union bmm150_bus *bus,
uint8_t reg, uint8_t val)
{
return i2c_reg_write_byte_dt(&bus->i2c, reg, val);
}
const struct bmm150_bus_io bmm150_bus_io_i2c = {
.check = bmm150_bus_check_i2c,
.read = bmm150_reg_read_i2c,
.write = bmm150_reg_write_i2c,
};
#endif /* BMM150_BUS_I2C */

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2016, 2017 Intel Corporation
* Copyright (c) 2017 IpTronix S.r.l.
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Bus-specific functionality for BMM150s accessed via SPI.
*/
#include <zephyr/logging/log.h>
#include "bmm150.h"
#if BMM150_BUS_SPI
LOG_MODULE_DECLARE(BMM150, CONFIG_SENSOR_LOG_LEVEL);
static int bmm150_bus_check_spi(const union bmm150_bus *bus)
{
return spi_is_ready_dt(&bus->spi) ? 0 : -ENODEV;
}
static int bmm150_reg_read_spi(const union bmm150_bus *bus,
uint8_t start, uint8_t *buf, int size)
{
uint8_t addr;
const struct spi_buf tx_buf = {
.buf = &addr,
.len = 1
};
const struct spi_buf_set tx = {
.buffers = &tx_buf,
.count = 1
};
struct spi_buf rx_buf[2];
const struct spi_buf_set rx = {
.buffers = rx_buf,
.count = ARRAY_SIZE(rx_buf)
};
int i;
rx_buf[0].buf = NULL;
rx_buf[0].len = 1;
rx_buf[1].len = 1;
for (i = 0; i < size; i++) {
int ret;
addr = (start + i) | 0x80;
rx_buf[1].buf = &buf[i];
ret = spi_transceive_dt(&bus->spi, &tx, &rx);
if (ret) {
LOG_DBG("spi_transceive FAIL %d\n", ret);
return ret;
}
}
return 0;
}
static int bmm150_reg_write_spi(const union bmm150_bus *bus,
uint8_t reg, uint8_t val)
{
uint8_t cmd[] = { reg & 0x7F, val };
const struct spi_buf tx_buf = {
.buf = cmd,
.len = sizeof(cmd)
};
const struct spi_buf_set tx = {
.buffers = &tx_buf,
.count = 1
};
int ret;
ret = spi_write_dt(&bus->spi, &tx);
if (ret) {
LOG_DBG("spi_write FAIL %d\n", ret);
return ret;
}
return 0;
}
const struct bmm150_bus_io bmm150_bus_io_spi = {
.check = bmm150_bus_check_spi,
.read = bmm150_reg_read_spi,
.write = bmm150_reg_write_spi,
};
#endif /* BMM150_BUS_SPI */

View file

@ -0,0 +1,10 @@
# Copyright (c) 2019, Linaro Limited
# SPDX-License-Identifier: Apache-2.0
description: |
Bosch BMM150 Geomagnetic sensor. See more info at:
https://www.bosch-sensortec.com/bst/products/all_products/bmm150
compatible: "bosch,bmm150"
include: ["i2c-device.yaml", "bosch,bmm150.yaml"]

View file

@ -0,0 +1,10 @@
# Copyright (c) 2019, Linaro Limited
# SPDX-License-Identifier: Apache-2.0
description: |
Bosch BMM150 Geomagnetic sensor. See more info at:
https://www.bosch-sensortec.com/bst/products/all_products/bmm150
compatible: "bosch,bmm150"
include: ["spi-device.yaml", "bosch,bmm150.yaml"]

View file

@ -1,10 +1,6 @@
# Copyright (c) 2019, Linaro Limited
# SPDX-License-Identifier: Apache-2.0
description: |
Bosch BMM150 Geomagnetic sensor. See more info at:
https://www.bosch-sensortec.com/bst/products/all_products/bmm150
# Common fields for BMM150
compatible: "bosch,bmm150"
include: [sensor-device.yaml, i2c-device.yaml]
include: sensor-device.yaml

View file

@ -354,3 +354,9 @@ test_spi_max31865: max31865@2a {
high-threshold = <32767>;
filter-50hz;
};
test_spi_bmm150: bmm150@2b {
compatible = "bosch,bmm150";
reg = <0x2b>;
spi-max-frequency = <0>;
};