Skip to content

Commit

Permalink
drivers: sensor: LIS3MDL: support SPI
Browse files Browse the repository at this point in the history
The LIS3MDL sensor driver does not support SPI.
This commit adds support for usage through SPI.

Signed-off-by: De Murlot <demurlotpierre@gmail.com>
  • Loading branch information
DeMurlot committed Sep 16, 2024
1 parent e3f8ba0 commit ab27d4c
Show file tree
Hide file tree
Showing 11 changed files with 372 additions and 39 deletions.
2 changes: 2 additions & 0 deletions drivers/sensor/st/lis3mdl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
zephyr_library()

zephyr_library_sources(lis3mdl.c)
zephyr_library_sources(lis3mdl_i2c.c)
zephyr_library_sources(lis3mdl_spi.c)
zephyr_library_sources_ifdef(CONFIG_LIS3MDL_TRIGGER lis3mdl_trigger.c)
5 changes: 3 additions & 2 deletions drivers/sensor/st/lis3mdl/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ menuconfig LIS3MDL
bool "LIS3MDL magnetometer"
default y
depends on DT_HAS_ST_LIS3MDL_MAGN_ENABLED
select I2C
select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS3MDL_MAGN),i2c)
select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS3MDL_MAGN),spi)
help
Enable driver for LIS3MDL I2C-based magnetometer.
Enable driver for LIS3MDL magnetometer.

if LIS3MDL

Expand Down
103 changes: 76 additions & 27 deletions drivers/sensor/st/lis3mdl/lis3mdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

#define DT_DRV_COMPAT st_lis3mdl_magn

#include <zephyr/drivers/i2c.h>
#include <zephyr/init.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/byteorder.h>
Expand Down Expand Up @@ -74,7 +73,7 @@ int lis3mdl_sample_fetch(const struct device *dev, enum sensor_channel chan)
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);

/* fetch magnetometer sample */
if (i2c_burst_read_dt(&config->i2c, LIS3MDL_REG_SAMPLE_START,
if (drv_data->hw_tf->read_data(dev, LIS3MDL_REG_SAMPLE_START,
(uint8_t *)buf, 6) < 0) {
LOG_DBG("Failed to fetch magnetometer sample.");
return -EIO;
Expand All @@ -86,7 +85,7 @@ int lis3mdl_sample_fetch(const struct device *dev, enum sensor_channel chan)
* the same read as magnetometer data, so do another
* burst read to fetch the temperature sample
*/
if (i2c_burst_read_dt(&config->i2c, LIS3MDL_REG_SAMPLE_START + 6,
if (drv_data->hw_tf->read_data(dev, LIS3MDL_REG_SAMPLE_START + 6,
(uint8_t *)(buf + 3), 2) < 0) {
LOG_DBG("Failed to fetch temperature sample.");
return -EIO;
Expand All @@ -112,16 +111,20 @@ static const struct sensor_driver_api lis3mdl_driver_api = {
int lis3mdl_init(const struct device *dev)
{
const struct lis3mdl_config *config = dev->config;
uint8_t chip_cfg[6];
const struct lis3mdl_data *data = dev->data;
uint8_t chip_cfg[5];
uint8_t id, idx;

if (!device_is_ready(config->i2c.bus)) {
LOG_ERR("I2C bus device not ready");
int ret;

ret = config->bus_init(dev);
if (ret < 0) {
LOG_ERR("bus device not ready");
return -ENODEV;
}

/* check chip ID */
if (i2c_reg_read_byte_dt(&config->i2c, LIS3MDL_REG_WHO_AM_I, &id) < 0) {
if (data->hw_tf->read_reg(dev, LIS3MDL_REG_WHO_AM_I, &id) < 0) {
LOG_ERR("Failed to read chip ID.");
return -EIO;
}
Expand All @@ -144,18 +147,17 @@ int lis3mdl_init(const struct device *dev)
}

/* Configure sensor */
chip_cfg[0] = LIS3MDL_REG_CTRL1;
chip_cfg[1] = lis3mdl_odr_bits[idx];
chip_cfg[0] = lis3mdl_odr_bits[idx];
#ifdef CONFIG_LIS3MDL_DIE_TEMP_EN
chip_cfg[1] |= LIS3MDL_TEMP_EN_MASK;
chip_cfg[0] |= LIS3MDL_TEMP_EN_MASK;
#endif /*LIS3MDL_DIE_TEMP_EN*/
chip_cfg[2] = LIS3MDL_FS_IDX << LIS3MDL_FS_SHIFT;
chip_cfg[3] = LIS3MDL_MD_CONTINUOUS;
chip_cfg[4] = ((lis3mdl_odr_bits[idx] & LIS3MDL_OM_MASK) >>
chip_cfg[1] = LIS3MDL_FS_IDX << LIS3MDL_FS_SHIFT;
chip_cfg[2] = LIS3MDL_MD_CONTINUOUS;
chip_cfg[3] = ((lis3mdl_odr_bits[idx] & LIS3MDL_OM_MASK) >>
LIS3MDL_OM_SHIFT) << LIS3MDL_OMZ_SHIFT;
chip_cfg[5] = LIS3MDL_BDU_EN;
chip_cfg[4] = LIS3MDL_BDU_EN;

if (i2c_write_dt(&config->i2c, chip_cfg, 6) < 0) {
if (data->hw_tf->write_data(dev, LIS3MDL_REG_CTRL1, chip_cfg, 5) < 0) {
LOG_DBG("Failed to configure chip.");
return -EIO;
}
Expand All @@ -172,17 +174,64 @@ int lis3mdl_init(const struct device *dev)
return 0;
}

#define LIS3MDL_DEFINE(inst) \
static struct lis3mdl_data lis3mdl_data_##inst; \
\
static struct lis3mdl_config lis3mdl_config_##inst = { \
.i2c = I2C_DT_SPEC_INST_GET(inst), \
IF_ENABLED(CONFIG_LIS3MDL_TRIGGER, \
(.irq_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, irq_gpios, { 0 }),)) \
}; \
\
SENSOR_DEVICE_DT_INST_DEFINE(inst, lis3mdl_init, NULL, \
&lis3mdl_data_##inst, &lis3mdl_config_##inst, POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, &lis3mdl_driver_api); \


/*
* Device creation macro, shared by LIS3MDL_DEFINE_SPI() and
* LIS3MDL_DEFINE_I2C().
*/

#define LIS3MDL_DEVICE_INIT(inst) \
\
SENSOR_DEVICE_DT_INST_DEFINE(inst, \
lis3mdl_init, \
NULL, \
&lis3mdl_data_##inst, \
&lis3mdl_config_##inst, \
POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, \
&lis3mdl_driver_api);

#ifdef CONFIG_LIS3MDL_TRIGGER
#define LIS3MDL_CFG_IRQ(inst) \
.irq_gpio = GPIO_DT_SPEC_INST_GET(inst, irq_gpios, { 0 }),
#else
#define LIS3MDL_CFG_IRQ(inst)
#endif /* CONFIG_LIS3MDL_TRIGGER */

/*
* config macro used when a device is on a SPI bus.
*/

#define LIS3MDL_CONFIG_SPI(inst) \
{ \
.bus_init = lis3mdl_spi_init, \
.bus_cfg.spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8) | \
SPI_OP_MODE_MASTER | \
SPI_MODE_CPOL | \
SPI_MODE_CPHA, 0), \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
(LIS3MDL_CFG_IRQ(inst)), ()) \
}

/*
* config macro used when a device is on an I2C bus.
*/

#define LIS3MDL_CONFIG_I2C(inst) \
{ \
.bus_init = lis3mdl_i2c_init, \
.bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
(LIS3MDL_CFG_IRQ(inst)), ()) \
}

#define LIS3MDL_DEFINE(inst) \
static struct lis3mdl_data lis3mdl_data_##inst; \
static struct lis3mdl_config lis3mdl_config_##inst = \
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
(LIS3MDL_CONFIG_SPI(inst)), \
(LIS3MDL_CONFIG_I2C(inst))) \
LIS3MDL_DEVICE_INIT(inst)

DT_INST_FOREACH_STATUS_OKAY(LIS3MDL_DEFINE)
42 changes: 40 additions & 2 deletions drivers/sensor/st/lis3mdl/lis3mdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,17 @@
#include <zephyr/device.h>
#include <zephyr/sys/util.h>
#include <zephyr/types.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
#include <zephyr/drivers/spi.h>
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
#include <zephyr/drivers/i2c.h>
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */

#define LIS3MDL_REG_WHO_AM_I 0x0F
#define LIS3MDL_CHIP_ID 0x3D

Expand Down Expand Up @@ -109,6 +116,35 @@ static const uint16_t lis3mdl_magn_gain[] = {
6842, 3421, 2281, 1711
};

union lis3mdl_bus_cfg {
#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 /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
};

struct lis3mdl_transfer_function {
int (*read_data)(const struct device *dev, uint8_t reg_addr,
uint8_t *value, uint8_t len);
int (*write_data)(const struct device *dev, uint8_t reg_addr,
uint8_t *value, uint8_t len);
int (*read_reg)(const struct device *dev, uint8_t reg_addr,
uint8_t *value);
int (*update_reg)(const struct device *dev, uint8_t reg_addr,
uint8_t mask, uint8_t value);
};

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
int lis3mdl_i2c_init(const struct device *dev);
#endif /*DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)*/

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
int lis3mdl_spi_init(const struct device *dev);
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */

struct lis3mdl_data {
int16_t x_sample;
int16_t y_sample;
Expand All @@ -117,6 +153,7 @@ struct lis3mdl_data {
int16_t temp_sample;
#endif /*CONFIG_LIS3MDL_DIE_TEMP_EN*/

const struct lis3mdl_transfer_function *hw_tf;
#ifdef CONFIG_LIS3MDL_TRIGGER
const struct device *dev;
struct gpio_callback gpio_cb;
Expand All @@ -136,7 +173,8 @@ struct lis3mdl_data {
};

struct lis3mdl_config {
struct i2c_dt_spec i2c;
int (*bus_init)(const struct device *dev);
const union lis3mdl_bus_cfg bus_cfg;
#ifdef CONFIG_LIS3MDL_TRIGGER
struct gpio_dt_spec irq_gpio;
#endif /*CONFIG_LIS3MDL_TRIGGER*/
Expand Down
73 changes: 73 additions & 0 deletions drivers/sensor/st/lis3mdl/lis3mdl_i2c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2018 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/

/* adapted from lsm6dsl_i2c.c - I2C routines for LSM6DSL driver
*/
#define DT_DRV_COMPAT st_lis3mdl_magn

#include <string.h>
#include <zephyr/logging/log.h>

#include "lis3mdl.h"

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)

LOG_MODULE_DECLARE(LIS3MDL, CONFIG_SENSOR_LOG_LEVEL);

static int lis3mdl_i2c_read_data(const struct device *dev, uint8_t reg_addr,
uint8_t *value, uint8_t len)
{
const struct lis3mld_config *cfg = dev->config;

return i2c_burst_read_dt(&cfg->bus_cfg.i2c, reg_addr, value, len);
}

static int lis3mdl_i2c_write_data(const struct device *dev, uint8_t reg_addr,
uint8_t *value, uint8_t len)
{
const struct lis3mdl_config *cfg = dev->config;

return i2c_burst_write_dt(&cfg->bus_cfg.i2c, reg_addr, value, len);
}

static int lis3mdl_i2c_read_reg(const struct device *dev, uint8_t reg_addr,
uint8_t *value)
{
const struct lis3mdl_config *cfg = dev->config;

return i2c_reg_read_byte_dt(&cfg->bus_cfg.i2c, reg_addr, value);
}

static int lis3mdl_i2c_update_reg(const struct device *dev, uint8_t reg_addr,
uint8_t mask, uint8_t value)
{
const struct lis3mdl_config *cfg = dev->config;

return i2c_reg_update_byte_dt(&cfg->bus_cfg.i2c, reg_addr, mask, value);
}


static const struct lis3mdl_transfer_function lis3mdl_i2c_transfer_fn = {
.read_data = lis3mdl_i2c_read_data,
.write_data = lis3mdl_i2c_write_data,
.read_reg = lis3mdl_i2c_read_reg,
.update_reg = lis3mdl_i2c_update_reg,
};

int lis3mdl_i2c_init(const struct device *dev)
{
struct lis3mdl_data *data = dev->data;
const struct lis3mdl_config *cfg = dev->config;

data->hw_tf = &lis3mdl_i2c_transfer_fn;

if (!device_is_ready(cfg->bus_cfg.i2c.bus)) {
return -ENODEV;
}

return 0;
}
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */
Loading

0 comments on commit ab27d4c

Please sign in to comment.