drivers/sensor: add support to IIS2MDC magnetometer sensor

The IIS2MDC is a 3D digital magnetometer ultra-low power sensor
for industrial applications, which can be interfaced through
either I2C or SPI bus.

https://www.st.com/resource/en/datasheet/iis2mdc.pdf

This driver is based on stmemsc i/f v1.02.

Signed-off-by: Armando Visconti <armando.visconti@st.com>
This commit is contained in:
Armando Visconti 2020-01-31 10:39:41 +01:00 committed by Maureen Helm
commit a302786e9b
14 changed files with 933 additions and 0 deletions

View file

@ -26,6 +26,7 @@ add_subdirectory_ifdef(CONFIG_HMC5883L hmc5883l)
add_subdirectory_ifdef(CONFIG_HP206C hp206c)
add_subdirectory_ifdef(CONFIG_HTS221 hts221)
add_subdirectory_ifdef(CONFIG_IIS2DLPC iis2dlpc)
add_subdirectory_ifdef(CONFIG_IIS2MDC iis2mdc)
add_subdirectory_ifdef(CONFIG_IIS3DHHC iis3dhhc)
add_subdirectory_ifdef(CONFIG_ISL29035 isl29035)
add_subdirectory_ifdef(CONFIG_ISM330DHCX ism330dhcx)

View file

@ -81,6 +81,8 @@ source "drivers/sensor/hts221/Kconfig"
source "drivers/sensor/iis2dlpc/Kconfig"
source "drivers/sensor/iis2mdc/Kconfig"
source "drivers/sensor/iis3dhhc/Kconfig"
source "drivers/sensor/isl29035/Kconfig"

View file

@ -0,0 +1,11 @@
#
# Copyright (c) 2020 STMicroelectronics
#
# SPDX-License-Identifier: Apache-2.0
#
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_IIS2MDC iis2mdc.c)
zephyr_library_sources_ifdef(CONFIG_IIS2MDC iis2mdc_i2c.c)
zephyr_library_sources_ifdef(CONFIG_IIS2MDC iis2mdc_spi.c)
zephyr_library_sources_ifdef(CONFIG_IIS2MDC_TRIGGER iis2mdc_trigger.c)

View file

@ -0,0 +1,60 @@
# Copyright (c) 2020 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
menuconfig IIS2MDC
bool "IIS2MDC Magnetometer"
depends on (I2C && HAS_DTS_I2C) || SPI
select HAS_STMEMSC
select USE_STDC_IIS2MDC
help
Enable driver for IIS2MDC I2C-based magnetometer sensor.
if IIS2MDC
choice IIS2MDC_TRIGGER_MODE
prompt "Trigger mode"
default IIS2MDC_TRIGGER_GLOBAL_THREAD
help
Specify the type of triggering to be used by the driver.
config IIS2MDC_TRIGGER_NONE
bool "No trigger"
config IIS2MDC_TRIGGER_GLOBAL_THREAD
bool "Use global thread"
depends on GPIO
select IIS2MDC_TRIGGER
config IIS2MDC_TRIGGER_OWN_THREAD
bool "Use own thread"
depends on GPIO
select IIS2MDC_TRIGGER
endchoice # IIS2MDC_TRIGGER_MODE
config IIS2MDC_TRIGGER
bool
config IIS2MDC_THREAD_PRIORITY
int "Thread priority"
depends on IIS2MDC_TRIGGER_OWN_THREAD
default 10
help
Priority of thread used by the driver to handle interrupts.
config IIS2MDC_THREAD_STACK_SIZE
int "Thread stack size"
depends on IIS2MDC_TRIGGER_OWN_THREAD
default 1024
help
Stack size of thread used by the driver to handle interrupts.
config IIS2MDC_MAG_ODR_RUNTIME
bool "Set magnetometer sampling frequency (ODR) at runtime (default: 10 Hz)"
default y
config IIS2MDC_SPI_FULL_DUPLEX
bool "Enable SPI 4wire mode (separated MISO and MOSI lines)"
depends on SPI
endif # IIS2MDC

View file

@ -0,0 +1,364 @@
/* ST Microelectronics IIS2MDC 3-axis magnetometer sensor
*
* Copyright (c) 2020 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/iis2mdc.pdf
*/
#include <init.h>
#include <sys/__assert.h>
#include <sys/byteorder.h>
#include <drivers/sensor.h>
#include <string.h>
#include <logging/log.h>
#include "iis2mdc.h"
struct iis2mdc_data iis2mdc_data;
LOG_MODULE_REGISTER(IIS2MDC, CONFIG_SENSOR_LOG_LEVEL);
#ifdef CONFIG_IIS2MDC_MAG_ODR_RUNTIME
static int iis2mdc_set_odr(struct device *dev, const struct sensor_value *val)
{
struct iis2mdc_data *iis2mdc = dev->driver_data;
iis2mdc_odr_t odr;
switch (val->val1) {
case 10:
odr = IIS2MDC_ODR_10Hz;
break;
case 20:
odr = IIS2MDC_ODR_20Hz;
break;
case 50:
odr = IIS2MDC_ODR_50Hz;
break;
case 100:
odr = IIS2MDC_ODR_100Hz;
break;
default:
return -EINVAL;
}
if (iis2mdc_data_rate_set(iis2mdc->ctx, odr)) {
return -EIO;
}
return 0;
}
#endif /* CONFIG_IIS2MDC_MAG_ODR_RUNTIME */
static int iis2mdc_set_hard_iron(struct device *dev, enum sensor_channel chan,
const struct sensor_value *val)
{
struct iis2mdc_data *iis2mdc = dev->driver_data;
u8_t i;
union axis3bit16_t offset;
for (i = 0U; i < 3; i++) {
offset.i16bit[i] = sys_cpu_to_le16(val->val1);
val++;
}
return iis2mdc_mag_user_offset_set(iis2mdc->ctx, offset.u8bit);
}
static void iis2mdc_channel_get_mag(struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
s32_t cval;
int i;
u8_t ofs_start, ofs_stop;
struct iis2mdc_data *iis2mdc = dev->driver_data;
struct sensor_value *pval = val;
switch (chan) {
case SENSOR_CHAN_MAGN_X:
ofs_start = ofs_stop = 0U;
break;
case SENSOR_CHAN_MAGN_Y:
ofs_start = ofs_stop = 1U;
break;
case SENSOR_CHAN_MAGN_Z:
ofs_start = ofs_stop = 2U;
break;
default:
ofs_start = 0U; ofs_stop = 2U;
break;
}
for (i = ofs_start; i <= ofs_stop; i++) {
cval = iis2mdc->mag[i] * 1500;
pval->val1 = cval / 1000000;
pval->val2 = cval % 1000000;
pval++;
}
}
/* read internal temperature */
static void iis2mdc_channel_get_temp(struct device *dev,
struct sensor_value *val)
{
struct iis2mdc_data *drv_data = dev->driver_data;
val->val1 = drv_data->temp_sample / 100;
val->val2 = (drv_data->temp_sample % 100) * 10000;
}
static int iis2mdc_channel_get(struct device *dev, enum sensor_channel chan,
struct sensor_value *val)
{
switch (chan) {
case SENSOR_CHAN_MAGN_X:
case SENSOR_CHAN_MAGN_Y:
case SENSOR_CHAN_MAGN_Z:
case SENSOR_CHAN_MAGN_XYZ:
iis2mdc_channel_get_mag(dev, chan, val);
break;
case SENSOR_CHAN_DIE_TEMP:
iis2mdc_channel_get_temp(dev, val);
break;
default:
LOG_DBG("Channel not supported");
return -ENOTSUP;
}
return 0;
}
static int iis2mdc_config(struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
switch (attr) {
#ifdef CONFIG_IIS2MDC_MAG_ODR_RUNTIME
case SENSOR_ATTR_SAMPLING_FREQUENCY:
return iis2mdc_set_odr(dev, val);
#endif /* CONFIG_IIS2MDC_MAG_ODR_RUNTIME */
case SENSOR_ATTR_OFFSET:
return iis2mdc_set_hard_iron(dev, chan, val);
default:
LOG_DBG("Mag attribute not supported");
return -ENOTSUP;
}
return 0;
}
static int iis2mdc_attr_set(struct device *dev,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
switch (chan) {
case SENSOR_CHAN_ALL:
case SENSOR_CHAN_MAGN_X:
case SENSOR_CHAN_MAGN_Y:
case SENSOR_CHAN_MAGN_Z:
case SENSOR_CHAN_MAGN_XYZ:
return iis2mdc_config(dev, chan, attr, val);
default:
LOG_DBG("attr_set() not supported on %d channel", chan);
return -ENOTSUP;
}
return 0;
}
static int iis2mdc_sample_fetch_mag(struct device *dev)
{
struct iis2mdc_data *iis2mdc = dev->driver_data;
union axis3bit16_t raw_mag;
/* fetch raw data sample */
if (iis2mdc_magnetic_raw_get(iis2mdc->ctx, raw_mag.u8bit) < 0) {
LOG_DBG("Failed to read sample");
return -EIO;
}
iis2mdc->mag[0] = sys_le16_to_cpu(raw_mag.i16bit[0]);
iis2mdc->mag[1] = sys_le16_to_cpu(raw_mag.i16bit[1]);
iis2mdc->mag[2] = sys_le16_to_cpu(raw_mag.i16bit[2]);
return 0;
}
static int iis2mdc_sample_fetch_temp(struct device *dev)
{
struct iis2mdc_data *iis2mdc = dev->driver_data;
union axis1bit16_t raw_temp;
s32_t temp;
/* fetch raw temperature sample */
if (iis2mdc_temperature_raw_get(iis2mdc->ctx, raw_temp.u8bit) < 0) {
LOG_DBG("Failed to read sample");
return -EIO;
}
/* formula is temp = 25 + (temp / 8) C */
temp = (sys_le16_to_cpu(raw_temp.i16bit) & 0x8FFF);
iis2mdc->temp_sample = 2500 + (temp * 100) / 8;
return 0;
}
static int iis2mdc_sample_fetch(struct device *dev, enum sensor_channel chan)
{
switch (chan) {
case SENSOR_CHAN_MAGN_X:
case SENSOR_CHAN_MAGN_Y:
case SENSOR_CHAN_MAGN_Z:
case SENSOR_CHAN_MAGN_XYZ:
iis2mdc_sample_fetch_mag(dev);
break;
case SENSOR_CHAN_DIE_TEMP:
iis2mdc_sample_fetch_temp(dev);
break;
case SENSOR_CHAN_ALL:
iis2mdc_sample_fetch_mag(dev);
iis2mdc_sample_fetch_temp(dev);
break;
default:
return -ENOTSUP;
}
return 0;
}
static const struct sensor_driver_api iis2mdc_driver_api = {
.attr_set = iis2mdc_attr_set,
#if CONFIG_IIS2MDC_TRIGGER
.trigger_set = iis2mdc_trigger_set,
#endif
.sample_fetch = iis2mdc_sample_fetch,
.channel_get = iis2mdc_channel_get,
};
static int iis2mdc_init_interface(struct device *dev)
{
const struct iis2mdc_config *const config =
dev->config->config_info;
struct iis2mdc_data *iis2mdc = dev->driver_data;
iis2mdc->bus = device_get_binding(config->master_dev_name);
if (!iis2mdc->bus) {
LOG_DBG("Could not get pointer to %s device",
config->master_dev_name);
return -EINVAL;
}
return config->bus_init(dev);
}
static const struct iis2mdc_config iis2mdc_dev_config = {
.master_dev_name = DT_INST_0_ST_IIS2MDC_BUS_NAME,
#ifdef CONFIG_IIS2MDC_TRIGGER
.drdy_port = DT_INST_0_ST_IIS2MDC_DRDY_GPIOS_CONTROLLER,
.drdy_pin = DT_INST_0_ST_IIS2MDC_DRDY_GPIOS_PIN,
.drdy_flags = DT_INST_0_ST_IIS2MDC_DRDY_GPIOS_FLAGS,
#endif /* CONFIG_IIS2MDC_TRIGGER */
#if defined(DT_ST_IIS2MDC_BUS_SPI)
.bus_init = iis2mdc_spi_init,
.spi_conf.frequency = DT_INST_0_ST_IIS2MDC_SPI_MAX_FREQUENCY,
.spi_conf.operation = (SPI_OP_MODE_MASTER | SPI_MODE_CPOL |
SPI_MODE_CPHA | SPI_WORD_SET(8) |
SPI_LINES_SINGLE),
.spi_conf.slave = DT_INST_0_ST_IIS2MDC_BASE_ADDRESS,
#if defined(DT_INST_0_ST_IIS2MDC_CS_GPIOS_CONTROLLER)
.gpio_cs_port = DT_INST_0_ST_IIS2MDC_CS_GPIOS_CONTROLLER,
.cs_gpio = DT_INST_0_ST_IIS2MDC_CS_GPIOS_PIN,
.spi_conf.cs = &iis2mdc_data.cs_ctrl,
#else
.spi_conf.cs = NULL,
#endif
#elif defined(DT_ST_IIS2MDC_BUS_I2C)
.bus_init = iis2mdc_i2c_init,
.i2c_slv_addr = DT_INST_0_ST_IIS2MDC_BASE_ADDRESS,
#else
#error "BUS MACRO NOT DEFINED IN DTS"
#endif
};
static int iis2mdc_init(struct device *dev)
{
struct iis2mdc_data *iis2mdc = dev->driver_data;
u8_t wai;
if (iis2mdc_init_interface(dev)) {
return -EINVAL;
}
/* check chip ID */
if (iis2mdc_device_id_get(iis2mdc->ctx, &wai) < 0) {
return -EIO;
}
if (wai != IIS2MDC_ID) {
LOG_DBG("Invalid chip ID: %02x\n", wai);
return -EINVAL;
}
/* reset sensor configuration */
if (iis2mdc_reset_set(iis2mdc->ctx, PROPERTY_ENABLE) < 0) {
LOG_DBG("s/w reset failed\n");
return -EIO;
}
k_busy_wait(100);
#if CONFIG_IIS2MDC_SPI_FULL_DUPLEX
/* After s/w reset set SPI 4wires again if the case */
if (iis2mdc_spi_mode_set(iis2mdc->ctx, IIS2MDC_SPI_4_WIRE) < 0) {
return -EIO;
}
#endif
/* enable BDU */
if (iis2mdc_block_data_update_set(iis2mdc->ctx, PROPERTY_ENABLE) < 0) {
LOG_DBG("setting bdu failed\n");
return -EIO;
}
/* Set Output Data Rate */
if (iis2mdc_data_rate_set(iis2mdc->ctx, IIS2MDC_ODR_10Hz)) {
LOG_DBG("set odr failed\n");
return -EIO;
}
/* Set / Reset sensor mode */
if (iis2mdc_set_rst_mode_set(iis2mdc->ctx,
IIS2MDC_SENS_OFF_CANC_EVERY_ODR)) {
LOG_DBG("reset sensor mode failed\n");
return -EIO;
}
/* Enable temperature compensation */
if (iis2mdc_offset_temp_comp_set(iis2mdc->ctx, PROPERTY_ENABLE)) {
LOG_DBG("enable temp compensation failed\n");
return -EIO;
}
/* Set device in continuous mode */
if (iis2mdc_operating_mode_set(iis2mdc->ctx, IIS2MDC_CONTINUOUS_MODE)) {
LOG_DBG("set continuos mode failed\n");
return -EIO;
}
#ifdef CONFIG_IIS2MDC_TRIGGER
if (iis2mdc_init_interrupt(dev) < 0) {
LOG_DBG("Failed to initialize interrupts");
return -EIO;
}
#endif
return 0;
}
DEVICE_AND_API_INIT(iis2mdc, DT_INST_0_ST_IIS2MDC_LABEL, iis2mdc_init,
&iis2mdc_data, &iis2mdc_dev_config, POST_KERNEL,
CONFIG_SENSOR_INIT_PRIORITY, &iis2mdc_driver_api);

View file

@ -0,0 +1,94 @@
/* ST Microelectronics IIS2MDC 3-axis magnetometer sensor
*
* Copyright (c) 2020 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/iis2mdc.pdf
*/
#ifndef __MAG_IIS2MDC_H
#define __MAG_IIS2MDC_H
#include <drivers/spi.h>
#include <drivers/gpio.h>
#include <drivers/sensor.h>
#include <sys/util.h>
#include "iis2mdc_reg.h"
union axis3bit16_t {
s16_t i16bit[3];
u8_t u8bit[6];
};
union axis1bit16_t {
s16_t i16bit;
u8_t u8bit[2];
};
struct iis2mdc_config {
char *master_dev_name;
int (*bus_init)(struct device *dev);
#ifdef CONFIG_IIS2MDC_TRIGGER
const char *drdy_port;
gpio_pin_t drdy_pin;
gpio_dt_flags_t drdy_flags;
#endif /* CONFIG_IIS2MDC_TRIGGER */
#ifdef DT_ST_IIS2MDC_BUS_I2C
u16_t i2c_slv_addr;
#elif DT_ST_IIS2MDC_BUS_SPI
struct spi_config spi_conf;
#if defined(DT_INST_0_ST_IIS2MDC_CS_GPIOS_CONTROLLER)
const char *gpio_cs_port;
u8_t cs_gpio;
#endif /* DT_INST_0_ST_IIS2MDC_CS_GPIOS_CONTROLLER */
#endif /* DT_ST_IIS2MDC_BUS_SPI */
};
/* Sensor data */
struct iis2mdc_data {
struct device *bus;
u16_t i2c_addr;
s16_t mag[3];
s32_t temp_sample;
stmdev_ctx_t *ctx;
#ifdef DT_ST_IIS2MDC_BUS_I2C
stmdev_ctx_t ctx_i2c;
#elif DT_ST_IIS2MDC_BUS_SPI
stmdev_ctx_t ctx_spi;
#endif
#ifdef CONFIG_IIS2MDC_TRIGGER
struct device *gpio;
struct gpio_callback gpio_cb;
sensor_trigger_handler_t handler_drdy;
#if defined(CONFIG_IIS2MDC_TRIGGER_OWN_THREAD)
K_THREAD_STACK_MEMBER(thread_stack, CONFIG_IIS2MDC_THREAD_STACK_SIZE);
struct k_thread thread;
struct k_sem gpio_sem;
#elif defined(CONFIG_IIS2MDC_TRIGGER_GLOBAL_THREAD)
struct k_work work;
struct device *dev;
#endif /* CONFIG_IIS2MDC_TRIGGER_GLOBAL_THREAD */
#endif /* CONFIG_IIS2MDC_TRIGGER */
#if defined(DT_INST_0_ST_IIS2MDC_CS_GPIOS_CONTROLLER)
struct spi_cs_control cs_ctrl;
#endif /* DT_INST_0_ST_IIS2MDC_CS_GPIOS_CONTROLLER */
};
int iis2mdc_spi_init(struct device *dev);
int iis2mdc_i2c_init(struct device *dev);
#ifdef CONFIG_IIS2MDC_TRIGGER
int iis2mdc_init_interrupt(struct device *dev);
int iis2mdc_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
#endif /* CONFIG_IIS2MDC_TRIGGER */
#endif /* __MAG_IIS2MDC_H */

View file

@ -0,0 +1,54 @@
/* ST Microelectronics IIS2MDC 3-axis magnetometer sensor
*
* Copyright (c) 2020 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/iis2mdc.pdf
*/
#include <string.h>
#include <drivers/i2c.h>
#include <logging/log.h>
#include "iis2mdc.h"
#ifdef DT_ST_IIS2MDC_BUS_I2C
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
LOG_MODULE_DECLARE(IIS2MDC);
static int iis2mdc_i2c_read(struct device *dev, u8_t reg_addr,
u8_t *value, u16_t len)
{
struct iis2mdc_data *data = dev->driver_data;
const struct iis2mdc_config *cfg = dev->config->config_info;
return i2c_burst_read(data->bus, cfg->i2c_slv_addr,
reg_addr, value, len);
}
static int iis2mdc_i2c_write(struct device *dev, u8_t reg_addr,
u8_t *value, u16_t len)
{
struct iis2mdc_data *data = dev->driver_data;
const struct iis2mdc_config *cfg = dev->config->config_info;
return i2c_burst_write(data->bus, cfg->i2c_slv_addr,
reg_addr, value, len);
}
int iis2mdc_i2c_init(struct device *dev)
{
struct iis2mdc_data *data = dev->driver_data;
data->ctx_i2c.read_reg = (stmdev_read_ptr) iis2mdc_i2c_read;
data->ctx_i2c.write_reg = (stmdev_write_ptr) iis2mdc_i2c_write;
data->ctx = &data->ctx_i2c;
data->ctx->handle = dev;
return 0;
}
#endif /* DT_ST_IIS2MDC_BUS_I2C */

View file

@ -0,0 +1,134 @@
/* ST Microelectronics IIS2MDC 3-axis magnetometer sensor
*
* Copyright (c) 2020 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/iis2mdc.pdf
*/
#include <string.h>
#include "iis2mdc.h"
#include <logging/log.h>
#ifdef DT_ST_IIS2MDC_BUS_SPI
#define IIS2MDC_SPI_READ (1 << 7)
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
LOG_MODULE_DECLARE(IIS2MDC);
static int iis2mdc_spi_read(struct device *dev, u8_t reg_addr,
u8_t *value, u8_t len)
{
struct iis2mdc_data *data = dev->driver_data;
const struct iis2mdc_config *cfg = dev->config->config_info;
const struct spi_config *spi_cfg = &cfg->spi_conf;
u8_t buffer_tx[2] = { reg_addr | IIS2MDC_SPI_READ, 0 };
const struct spi_buf tx_buf = {
.buf = buffer_tx,
.len = 2,
};
const struct spi_buf_set tx = {
.buffers = &tx_buf,
.count = 1
};
const struct spi_buf rx_buf[2] = {
{
.buf = NULL,
.len = 1,
},
{
.buf = value,
.len = len,
}
};
const struct spi_buf_set rx = {
.buffers = rx_buf,
.count = 2
};
if (len > 64) {
return -EIO;
}
if (spi_transceive(data->bus, spi_cfg, &tx, &rx)) {
return -EIO;
}
return 0;
}
static int iis2mdc_spi_write(struct device *dev, u8_t reg_addr,
u8_t *value, u8_t len)
{
struct iis2mdc_data *data = dev->driver_data;
const struct iis2mdc_config *cfg = dev->config->config_info;
const struct spi_config *spi_cfg = &cfg->spi_conf;
u8_t buffer_tx[1] = { reg_addr & ~IIS2MDC_SPI_READ };
const struct spi_buf tx_buf[2] = {
{
.buf = buffer_tx,
.len = 1,
},
{
.buf = value,
.len = len,
}
};
const struct spi_buf_set tx = {
.buffers = tx_buf,
.count = 2
};
if (len > 64) {
return -EIO;
}
if (spi_write(data->bus, spi_cfg, &tx)) {
return -EIO;
}
return 0;
}
int iis2mdc_spi_init(struct device *dev)
{
struct iis2mdc_data *data = dev->driver_data;
data->ctx_spi.read_reg = (stmdev_read_ptr) iis2mdc_spi_read;
data->ctx_spi.write_reg = (stmdev_write_ptr) iis2mdc_spi_write;
data->ctx = &data->ctx_spi;
data->ctx->handle = dev;
#if defined(DT_INST_0_ST_IIS2MDC_CS_GPIOS_CONTROLLER)
const struct iis2mdc_config *cfg = dev->config->config_info;
/* handle SPI CS thru GPIO if it is the case */
data->cs_ctrl.gpio_dev = device_get_binding(cfg->gpio_cs_port);
if (!data->cs_ctrl.gpio_dev) {
LOG_ERR("Unable to get GPIO SPI CS device");
return -ENODEV;
}
data->cs_ctrl.gpio_pin = cfg->cs_gpio;
data->cs_ctrl.delay = 0;
LOG_DBG("SPI GPIO CS configured on %s:%u",
cfg->gpio_cs_port, cfg->cs_gpio);
#endif
#if CONFIG_IIS2MDC_SPI_FULL_DUPLEX
/* Set SPI 4wires */
if (iis2mdc_spi_mode_set(data->ctx, IIS2MDC_SPI_4_WIRE) < 0) {
return -EIO;
}
#endif
return 0;
}
#endif /* DT_ST_IIS2MDC_BUS_SPI */

View file

@ -0,0 +1,151 @@
/* ST Microelectronics IIS2MDC 3-axis magnetometer sensor
*
* Copyright (c) 2020 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/iis2mdc.pdf
*/
#include <kernel.h>
#include <drivers/sensor.h>
#include <drivers/gpio.h>
#include <logging/log.h>
#include "iis2mdc.h"
LOG_MODULE_DECLARE(IIS2MDC, CONFIG_SENSOR_LOG_LEVEL);
static int iis2mdc_enable_int(struct device *dev, int enable)
{
struct iis2mdc_data *iis2mdc = dev->driver_data;
/* set interrupt on mag */
return iis2mdc_drdy_on_pin_set(iis2mdc->ctx, enable);
}
/* link external trigger to event data ready */
int iis2mdc_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
struct iis2mdc_data *iis2mdc = dev->driver_data;
union axis3bit16_t raw;
if (trig->chan == SENSOR_CHAN_MAGN_XYZ) {
iis2mdc->handler_drdy = handler;
if (handler) {
/* fetch raw data sample: re-trigger lost interrupt */
iis2mdc_magnetic_raw_get(iis2mdc->ctx, raw.u8bit);
return iis2mdc_enable_int(dev, 1);
} else {
return iis2mdc_enable_int(dev, 0);
}
}
return -ENOTSUP;
}
/* handle the drdy event: read data and call handler if registered any */
static void iis2mdc_handle_interrupt(void *arg)
{
struct device *dev = arg;
struct iis2mdc_data *iis2mdc = dev->driver_data;
const struct iis2mdc_config *const config =
dev->config->config_info;
struct sensor_trigger drdy_trigger = {
.type = SENSOR_TRIG_DATA_READY,
};
if (iis2mdc->handler_drdy != NULL) {
iis2mdc->handler_drdy(dev, &drdy_trigger);
}
gpio_pin_interrupt_configure(iis2mdc->gpio, config->drdy_pin,
GPIO_INT_EDGE_TO_ACTIVE);
}
static void iis2mdc_gpio_callback(struct device *dev,
struct gpio_callback *cb, u32_t pins)
{
struct iis2mdc_data *iis2mdc =
CONTAINER_OF(cb, struct iis2mdc_data, gpio_cb);
const struct iis2mdc_config *const config = dev->config->config_info;
ARG_UNUSED(pins);
gpio_pin_interrupt_configure(dev, config->drdy_pin, GPIO_INT_DISABLE);
#if defined(CONFIG_IIS2MDC_TRIGGER_OWN_THREAD)
k_sem_give(&iis2mdc->gpio_sem);
#elif defined(CONFIG_IIS2MDC_TRIGGER_GLOBAL_THREAD)
k_work_submit(&iis2mdc->work);
#endif
}
#ifdef CONFIG_IIS2MDC_TRIGGER_OWN_THREAD
static void iis2mdc_thread(int dev_ptr, int unused)
{
struct device *dev = INT_TO_POINTER(dev_ptr);
struct iis2mdc_data *iis2mdc = dev->driver_data;
ARG_UNUSED(unused);
while (1) {
k_sem_take(&iis2mdc->gpio_sem, K_FOREVER);
iis2mdc_handle_interrupt(dev);
}
}
#endif
#ifdef CONFIG_IIS2MDC_TRIGGER_GLOBAL_THREAD
static void iis2mdc_work_cb(struct k_work *work)
{
struct iis2mdc_data *iis2mdc =
CONTAINER_OF(work, struct iis2mdc_data, work);
iis2mdc_handle_interrupt(iis2mdc->dev);
}
#endif
int iis2mdc_init_interrupt(struct device *dev)
{
struct iis2mdc_data *iis2mdc = dev->driver_data;
const struct iis2mdc_config *const config = dev->config->config_info;
/* setup data ready gpio interrupt */
iis2mdc->gpio = device_get_binding(config->drdy_port);
if (iis2mdc->gpio == NULL) {
LOG_DBG("Cannot get pointer to %s device",
config->drdy_port);
return -EINVAL;
}
#if defined(CONFIG_IIS2MDC_TRIGGER_OWN_THREAD)
k_sem_init(&iis2mdc->gpio_sem, 0, UINT_MAX);
k_thread_create(&iis2mdc->thread, iis2mdc->thread_stack,
CONFIG_IIS2MDC_THREAD_STACK_SIZE,
(k_thread_entry_t)iis2mdc_thread, dev,
0, NULL, K_PRIO_COOP(CONFIG_IIS2MDC_THREAD_PRIORITY),
0, K_NO_WAIT);
#elif defined(CONFIG_IIS2MDC_TRIGGER_GLOBAL_THREAD)
iis2mdc->work.handler = iis2mdc_work_cb;
iis2mdc->dev = dev;
#endif
gpio_pin_configure(iis2mdc->gpio, config->drdy_pin,
GPIO_INPUT | config->drdy_flags);
gpio_init_callback(&iis2mdc->gpio_cb,
iis2mdc_gpio_callback,
BIT(config->drdy_pin));
if (gpio_add_callback(iis2mdc->gpio, &iis2mdc->gpio_cb) < 0) {
LOG_DBG("Could not set gpio callback");
return -EIO;
}
return gpio_pin_interrupt_configure(iis2mdc->gpio, config->drdy_pin,
GPIO_INT_EDGE_TO_ACTIVE);
}

View file

@ -0,0 +1,19 @@
# Copyright (c) 2018 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
description: |
STMicroelectronics IIS2MDC magnetometer accessed through I2C bus
compatible: "st,iis2mdc"
include: i2c-device.yaml
properties:
drdy-gpios:
type: phandle-array
required: false
description: DRDY pin
This pin defaults to active high when produced by the sensor.
The property value should ensure the flags properly describe
the signal that is presented to the driver.

View file

@ -0,0 +1,19 @@
# Copyright (c) 2019 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
description: |
STMicroelectronics IIS2MDC magnetometer accessed through SPI bus
compatible: "st,iis2mdc"
include: spi-device.yaml
properties:
drdy-gpios:
type: phandle-array
required: false
description: DRDY pin
This pin defaults to active high when produced by the sensor.
The property value should ensure the flags properly describe
the signal that is presented to the driver.

View file

@ -139,6 +139,16 @@
#define DT_ST_IIS2DLPC_BUS_I2C 1
#endif
#ifndef DT_INST_0_ST_IIS2MDC_LABEL
#define DT_INST_0_ST_IIS2MDC_LABEL ""
#define DT_INST_0_ST_IIS2MDC_BUS_NAME ""
#define DT_INST_0_ST_IIS2MDC_BASE_ADDRESS 0
#define DT_INST_0_ST_IIS2MDC_DRDY_GPIOS_FLAGS 0
#define DT_INST_0_ST_IIS2MDC_DRDY_GPIOS_PIN 0
#define DT_INST_0_ST_IIS2MDC_DRDY_GPIOS_CONTROLLER ""
#define DT_ST_IIS2MDC_BUS_I2C 1
#endif
#ifndef DT_INST_0_ST_LIS3MDL_MAGN_LABEL
#define DT_INST_0_ST_LIS3MDL_MAGN_LABEL ""
#define DT_INST_0_ST_LIS3MDL_MAGN_BUS_NAME ""
@ -527,6 +537,17 @@
#define DT_ST_ISM330DHCX_BUS_SPI 1
#endif
#ifndef DT_INST_0_ST_IIS2MDC_LABEL
#define DT_INST_0_ST_IIS2MDC_LABEL ""
#define DT_INST_0_ST_IIS2MDC_BUS_NAME ""
#define DT_INST_0_ST_IIS2MDC_SPI_MAX_FREQUENCY 100000
#define DT_INST_0_ST_IIS2MDC_BASE_ADDRESS 1
#define DT_INST_0_ST_IIS2MDC_DRDY_GPIOS_CONTROLLER ""
#define DT_INST_0_ST_IIS2MDC_DRDY_GPIOS_FLAGS 0
#define DT_INST_0_ST_IIS2MDC_DRDY_GPIOS_PIN 0
#define DT_ST_IIS2MDC_BUS_SPI 1
#endif
#ifndef DT_INST_0_ST_IIS3DHHC_LABEL
#define DT_INST_0_ST_IIS3DHHC_LABEL ""
#define DT_INST_0_ST_IIS3DHHC_BASE_ADDRESS 0

View file

@ -9,3 +9,4 @@ CONFIG_IIS2DLPC=y
CONFIG_LIS2DW12=y
CONFIG_STTS751=y
CONFIG_ISM330DHCX=y
CONFIG_IIS2MDC=y

View file

@ -13,3 +13,5 @@ CONFIG_STTS751=y
CONFIG_STTS751_TRIGGER_OWN_THREAD=y
CONFIG_ISM330DHCX=y
CONFIG_ISM330DHCX_TRIGGER_OWN_THREAD=y
CONFIG_IIS2MDC=y
CONFIG_IIS2MDC_TRIGGER_OWN_THREAD=y