driver: sensor: Add support for LIS2MDL Mag sensor
Added support to LIS2MDL Magnetometer sensor provided with following features: - I2C interface - Mag data - Temperature data - ODR configurable by config or at runtime - Trigger mode selectable by menuconfig - IRQ pin configurable (by dts or Kconfig) - Hard Iron offset setting at runtime - Include yaml file Tested on ST MEMS IKS01A2 + NUCLEO STM32F411RE board. LIS2MDL connected to I2C master interface (SPI 3 wire not supported yet). Test run with all ODR {10, 20, 50, 100} Hz in poll and trigger mode. GPIO IRQ dts configuration has been tested by adding to boards/arm/nucleo_f411re/nucleo_f411re.dts file this patch: &i2c1 { status = "ok"; clock-frequency = <I2C_BITRATE_FAST>; + + /* ST Microelectronics LIS2MDL mag sensor */ + lis2mdl-magn@1e { + compatible = "st,lis2mdl-magn"; + reg = <0x1e>; + irq-gpios = <&gpioa 4 0>; + label = "LIS2MDL"; + status = "ok"; + }; }; and adding boards/arm/nucleo_f411re/dts.fixup with following content: ST_STM32_I2C_V1_40005400_ST_LIS2MDL_MAGN_1E_LABEL ST_STM32_I2C_V1_40005400_ST_LIS2MDL_MAGN_1E_BASE_ADDRESS ST_STM32_I2C_V1_40005400_ST_LIS2MDL_MAGN_1E_BUS_NAME ST_STM32_I2C_V1_40005400_ST_LIS2MDL_MAGN_1E_IRQ_GPIOS_CONTROLLER ST_STM32_I2C_V1_40005400_ST_LIS2MDL_MAGN_1E_IRQ_GPIOS_PIN For more info on this LIS2MDL please follow this link: http://www.st.com/en/mems-and-sensors/lis2mdl.html Signed-off-by: Mario Tesi <mario.tesi@st.com>
This commit is contained in:
parent
3d72216bce
commit
5d8834bee4
10 changed files with 827 additions and 0 deletions
|
@ -20,6 +20,7 @@ add_subdirectory_ifdef(CONFIG_HP206C hp206c)
|
|||
add_subdirectory_ifdef(CONFIG_HTS221 hts221)
|
||||
add_subdirectory_ifdef(CONFIG_ISL29035 isl29035)
|
||||
add_subdirectory_ifdef(CONFIG_LIS2DH lis2dh)
|
||||
add_subdirectory_ifdef(CONFIG_LIS2MDL lis2mdl)
|
||||
add_subdirectory_ifdef(CONFIG_LIS3DH lis3dh)
|
||||
add_subdirectory_ifdef(CONFIG_LIS3MDL lis3mdl)
|
||||
add_subdirectory_ifdef(CONFIG_LPS22HB lps22hb)
|
||||
|
|
|
@ -79,6 +79,8 @@ source "drivers/sensor/isl29035/Kconfig"
|
|||
|
||||
source "drivers/sensor/lis2dh/Kconfig"
|
||||
|
||||
source "drivers/sensor/lis2mdl/Kconfig"
|
||||
|
||||
source "drivers/sensor/lis3dh/Kconfig"
|
||||
|
||||
source "drivers/sensor/lis3mdl/Kconfig"
|
||||
|
|
9
drivers/sensor/lis2mdl/CMakeLists.txt
Normal file
9
drivers/sensor/lis2mdl/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Copyright (c) 2018 STMicroelectronics
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_sources_ifdef(CONFIG_LIS2MDL lis2mdl.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_LIS2MDL_TRIGGER lis2mdl_trigger.c)
|
117
drivers/sensor/lis2mdl/Kconfig
Normal file
117
drivers/sensor/lis2mdl/Kconfig
Normal file
|
@ -0,0 +1,117 @@
|
|||
|
||||
# Copyright (c) 2018 STMicroelectronics
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
menuconfig LIS2MDL
|
||||
bool "LIS2MDL Magnetometer"
|
||||
depends on I2C
|
||||
help
|
||||
Enable driver for LIS2MDL I2C-based magnetometer sensor.
|
||||
|
||||
if LIS2MDL
|
||||
|
||||
config LIS2MDL_DEV_NAME
|
||||
string "Driver name"
|
||||
default "LIS2MDL"
|
||||
help
|
||||
Device name with which the LIS2MDL sensor is identified.
|
||||
|
||||
if !HAS_DTS_I2C
|
||||
|
||||
config LIS2MDL_I2C_ADDR
|
||||
hex "I2C address"
|
||||
default 0x1E
|
||||
help
|
||||
I2C address of the LIS2MDL sensor.
|
||||
|
||||
config LIS2MDL_I2C_MASTER_DEV_NAME
|
||||
string "I2C master where LIS2MDL is connected"
|
||||
default "I2C_0"
|
||||
help
|
||||
Specify the device name of the I2C master device to which LIS2MDL is
|
||||
connected.
|
||||
|
||||
endif # LIS2MDL_I2C_ADDR
|
||||
|
||||
choice
|
||||
prompt "Trigger mode"
|
||||
default LIS2MDL_TRIGGER_GLOBAL_THREAD
|
||||
help
|
||||
Specify the type of triggering to be used by the driver.
|
||||
|
||||
config LIS2MDL_TRIGGER_NONE
|
||||
bool "No trigger"
|
||||
|
||||
config LIS2MDL_TRIGGER_GLOBAL_THREAD
|
||||
bool "Use global thread"
|
||||
depends on GPIO
|
||||
select LIS2MDL_TRIGGER
|
||||
|
||||
config LIS2MDL_TRIGGER_OWN_THREAD
|
||||
bool "Use own thread"
|
||||
depends on GPIO
|
||||
select LIS2MDL_TRIGGER
|
||||
|
||||
endchoice
|
||||
|
||||
config LIS2MDL_TRIGGER
|
||||
bool
|
||||
|
||||
if !HAS_DTS_GPIO
|
||||
|
||||
config LIS2MDL_GPIO_DEV_NAME
|
||||
string "GPIO device"
|
||||
default "GPIO_0"
|
||||
depends on LIS2MDL_TRIGGER
|
||||
help
|
||||
The device name of the GPIO device to which the LIS2MDL interrupt pins
|
||||
are connected.
|
||||
|
||||
config LIS2MDL_GPIO_PIN_NUM
|
||||
int "Interrupt GPIO pin number"
|
||||
default 0
|
||||
depends on LIS2MDL_TRIGGER
|
||||
help
|
||||
The number of the GPIO on which the interrupt signal from the LIS2MDL
|
||||
chip will be received.
|
||||
|
||||
endif # !HAS_DTS_GPIO
|
||||
|
||||
config LIS2MDL_THREAD_PRIORITY
|
||||
int "Thread priority"
|
||||
depends on LIS2MDL_TRIGGER_OWN_THREAD
|
||||
default 10
|
||||
help
|
||||
Priority of thread used by the driver to handle interrupts.
|
||||
|
||||
config LIS2MDL_THREAD_STACK_SIZE
|
||||
int "Thread stack size"
|
||||
depends on LIS2MDL_TRIGGER_OWN_THREAD
|
||||
default 1024
|
||||
help
|
||||
Stack size of thread used by the driver to handle interrupts.
|
||||
|
||||
choice
|
||||
prompt "Magnetometer sampling frequency (ODR)"
|
||||
default LIS2MDL_MAG_ODR_RUNTIME
|
||||
|
||||
config LIS2MDL_MAG_ODR_RUNTIME
|
||||
bool "Set ODR at runtime (default 10 Hz)"
|
||||
|
||||
config LIS2MDL_MAG_ODR_10
|
||||
bool "10 Hz"
|
||||
|
||||
config LIS2MDL_MAG_ODR_20
|
||||
bool "20 Hz"
|
||||
|
||||
config LIS2MDL_MAG_ODR_50
|
||||
bool "50 Hz"
|
||||
|
||||
config LIS2MDL_MAG_ODR_100
|
||||
bool "100 Hz"
|
||||
|
||||
endchoice
|
||||
|
||||
endif # LIS2MDL
|
375
drivers/sensor/lis2mdl/lis2mdl.c
Normal file
375
drivers/sensor/lis2mdl/lis2mdl.c
Normal file
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
* Copyright (c) 2018 STMicroelectronics
|
||||
*
|
||||
* LIS2MDL mag driver
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <init.h>
|
||||
#include <misc/__assert.h>
|
||||
#include <misc/byteorder.h>
|
||||
#include <sensor.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lis2mdl.h"
|
||||
|
||||
struct lis2mdl_data lis2mdl_device_data;
|
||||
|
||||
#ifdef CONFIG_LIS2MDL_MAG_ODR_RUNTIME
|
||||
static const struct {
|
||||
u16_t odr;
|
||||
u8_t regval;
|
||||
} lis2mdl_odr_reg[] = {
|
||||
{
|
||||
.odr = 10,
|
||||
.regval = LIS2MDL_ODR10_HZ,
|
||||
},
|
||||
{
|
||||
.odr = 20,
|
||||
.regval = LIS2MDL_ODR20_HZ,
|
||||
},
|
||||
{
|
||||
.odr = 50,
|
||||
.regval = LIS2MDL_ODR50_HZ,
|
||||
},
|
||||
{
|
||||
.odr = 100,
|
||||
.regval = LIS2MDL_ODR100_HZ,
|
||||
},
|
||||
};
|
||||
|
||||
static int lis2mdl_freq_to_odr_val(u16_t odr)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lis2mdl_odr_reg); i++) {
|
||||
if (odr == lis2mdl_odr_reg[i].odr) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int lis2mdl_set_odr(struct device *dev, u16_t odr)
|
||||
{
|
||||
int odr_idx;
|
||||
struct lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
|
||||
/* check if power off */
|
||||
if (odr == 0) {
|
||||
/* power off mag */
|
||||
return i2c_reg_update_byte(lis2mdl->i2c,
|
||||
lis2mdl->i2c_addr,
|
||||
LIS2MDL_CFG_REG_A,
|
||||
LIS2MDL_MAG_MODE_MASK,
|
||||
LIS2MDL_MD_IDLE1_MODE);
|
||||
}
|
||||
|
||||
odr_idx = lis2mdl_freq_to_odr_val(odr);
|
||||
if (odr_idx < 0) {
|
||||
return odr_idx;
|
||||
}
|
||||
|
||||
return i2c_reg_update_byte(lis2mdl->i2c,
|
||||
lis2mdl->i2c_addr,
|
||||
LIS2MDL_CFG_REG_A,
|
||||
LIS2MDL_ODR_MASK,
|
||||
lis2mdl_odr_reg[odr_idx].regval);
|
||||
}
|
||||
#endif /* CONFIG_LIS2MDL_MAG_ODR_RUNTIME */
|
||||
|
||||
static int lis2mdl_set_hard_iron(struct device *dev, enum sensor_channel chan,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
struct lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
u8_t regs = LIS2MDL_OFFSET_X_REG_L;
|
||||
u8_t i;
|
||||
s16_t offs;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < LIS2MDL_NUM_AXIS; i++) {
|
||||
offs = sys_cpu_to_le16(val->val1);
|
||||
ret = i2c_burst_write(lis2mdl->i2c, lis2mdl->i2c_addr,
|
||||
regs, (u8_t *)&offs, sizeof(offs));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
regs += sizeof(offs);
|
||||
val++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lis2mdl_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 lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
struct sensor_value *pval = val;
|
||||
|
||||
switch (chan) {
|
||||
case SENSOR_CHAN_MAGN_X:
|
||||
ofs_start = ofs_stop = 0;
|
||||
break;
|
||||
case SENSOR_CHAN_MAGN_Y:
|
||||
ofs_start = ofs_stop = 1;
|
||||
break;
|
||||
case SENSOR_CHAN_MAGN_Z:
|
||||
ofs_start = ofs_stop = 2;
|
||||
break;
|
||||
default:
|
||||
ofs_start = 0; ofs_stop = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = ofs_start; i <= ofs_stop; i++) {
|
||||
cval = lis2mdl->mag[i] * lis2mdl->mag_fs_sensitivity;
|
||||
pval->val1 = cval / 1000000;
|
||||
pval->val2 = cval % 1000000;
|
||||
pval++;
|
||||
}
|
||||
}
|
||||
|
||||
/* read internal temperature */
|
||||
static void lis2mdl_channel_get_temp(struct device *dev,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
struct lis2mdl_data *drv_data = dev->driver_data;
|
||||
|
||||
val->val1 = drv_data->temp_sample / 100;
|
||||
val->val2 = drv_data->temp_sample % 100;
|
||||
}
|
||||
|
||||
static int lis2mdl_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:
|
||||
lis2mdl_channel_get_mag(dev, chan, val);
|
||||
break;
|
||||
case SENSOR_CHAN_DIE_TEMP:
|
||||
lis2mdl_channel_get_temp(dev, val);
|
||||
break;
|
||||
default:
|
||||
SYS_LOG_DBG("Channel not supported");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lis2mdl_config(struct device *dev, enum sensor_channel chan,
|
||||
enum sensor_attribute attr,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
switch (attr) {
|
||||
#ifdef CONFIG_LIS2MDL_MAG_ODR_RUNTIME
|
||||
case SENSOR_ATTR_SAMPLING_FREQUENCY:
|
||||
return lis2mdl_set_odr(dev, val->val1);
|
||||
#endif /* CONFIG_LIS2MDL_MAG_ODR_RUNTIME */
|
||||
case SENSOR_ATTR_OFFSET:
|
||||
return lis2mdl_set_hard_iron(dev, chan, val);
|
||||
default:
|
||||
SYS_LOG_DBG("Mag attribute not supported");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lis2mdl_attr_set(struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
enum sensor_attribute attr,
|
||||
const 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:
|
||||
return lis2mdl_config(dev, chan, attr, val);
|
||||
default:
|
||||
SYS_LOG_DBG("attr_set() not supported on %d channel", chan);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lis2mdl_sample_fetch_mag(struct device *dev)
|
||||
{
|
||||
struct lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
|
||||
union {
|
||||
u8_t raw[LIS2MDL_OUT_REG_SIZE];
|
||||
struct {
|
||||
s16_t m_axis[3];
|
||||
};
|
||||
} buf __aligned(2);
|
||||
|
||||
/* fetch raw data sample */
|
||||
if (i2c_burst_read(lis2mdl->i2c, lis2mdl->i2c_addr,
|
||||
LIS2MDL_OUT_REG, buf.raw,
|
||||
sizeof(buf)) < 0) {
|
||||
SYS_LOG_DBG("Failed to fetch raw mag sample");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
lis2mdl->mag[0] = sys_le16_to_cpu(buf.m_axis[0]);
|
||||
lis2mdl->mag[1] = sys_le16_to_cpu(buf.m_axis[1]);
|
||||
lis2mdl->mag[2] = sys_le16_to_cpu(buf.m_axis[2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lis2mdl_sample_fetch_temp(struct device *dev)
|
||||
{
|
||||
struct lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
u16_t temp_raw;
|
||||
s32_t temp;
|
||||
int ret;
|
||||
|
||||
/* fetch raw temperature sample */
|
||||
ret = i2c_burst_read(lis2mdl->i2c, lis2mdl->i2c_addr,
|
||||
LIS2MDL_TEMP_OUT_L_REG,
|
||||
(u8_t *)&temp_raw, sizeof(temp_raw));
|
||||
if (ret < 0) {
|
||||
SYS_LOG_DBG("Failed to fetch raw temp sample");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* formula is temp = 25 + (temp / 8) C */
|
||||
temp = (sys_le16_to_cpu(temp_raw) & 0x8FFF);
|
||||
lis2mdl->temp_sample = 2500 + (temp * 100) / 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lis2mdl_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:
|
||||
lis2mdl_sample_fetch_mag(dev);
|
||||
break;
|
||||
case SENSOR_CHAN_DIE_TEMP:
|
||||
lis2mdl_sample_fetch_temp(dev);
|
||||
break;
|
||||
case SENSOR_CHAN_ALL:
|
||||
lis2mdl_sample_fetch_mag(dev);
|
||||
lis2mdl_sample_fetch_temp(dev);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sensor_driver_api lis2mdl_driver_api = {
|
||||
.attr_set = lis2mdl_attr_set,
|
||||
#if CONFIG_LIS2MDL_TRIGGER
|
||||
.trigger_set = lis2mdl_trigger_set,
|
||||
#endif
|
||||
.sample_fetch = lis2mdl_sample_fetch,
|
||||
.channel_get = lis2mdl_channel_get,
|
||||
};
|
||||
|
||||
static int lis2mdl_init_interface(struct device *dev)
|
||||
{
|
||||
const struct lis2mdl_device_config *const config =
|
||||
dev->config->config_info;
|
||||
struct lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
|
||||
lis2mdl->i2c = device_get_binding(config->master_dev_name);
|
||||
if (!lis2mdl->i2c) {
|
||||
SYS_LOG_DBG("Could not get pointer to %s device",
|
||||
config->master_dev_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lis2mdl->i2c_addr = config->i2c_addr_config;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct lis2mdl_device_config lis2mdl_dev_config = {
|
||||
.master_dev_name = CONFIG_LIS2MDL_I2C_MASTER_DEV_NAME,
|
||||
#ifdef CONFIG_LIS2MDL_TRIGGER
|
||||
.gpio_name = CONFIG_LIS2MDL_GPIO_DEV_NAME,
|
||||
.gpio_pin = CONFIG_LIS2MDL_GPIO_PIN_NUM,
|
||||
#endif /* CONFIG_LIS2MDL_TRIGGER */
|
||||
.i2c_addr_config = CONFIG_LIS2MDL_I2C_ADDR,
|
||||
};
|
||||
|
||||
static int lis2mdl_init(struct device *dev)
|
||||
{
|
||||
struct lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
u8_t wai;
|
||||
|
||||
if (lis2mdl_init_interface(dev)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* check chip ID */
|
||||
if (i2c_reg_read_byte(lis2mdl->i2c, lis2mdl->i2c_addr,
|
||||
LIS2MDL_WHO_AM_I_REG, &wai) < 0) {
|
||||
SYS_LOG_DBG("Failed to read chip ID");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (wai != LIS2MDL_WHOAMI_VAL) {
|
||||
SYS_LOG_DBG("Invalid chip ID");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* reset sensor configuration */
|
||||
if (i2c_reg_write_byte(lis2mdl->i2c, lis2mdl->i2c_addr,
|
||||
LIS2MDL_CFG_REG_A, LIS2MDL_SOFT_RST)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
k_busy_wait(100);
|
||||
|
||||
/* enable BDU */
|
||||
if (i2c_reg_update_byte(lis2mdl->i2c, lis2mdl->i2c_addr,
|
||||
LIS2MDL_CFG_REG_C, LIS2MDL_BDU_MASK,
|
||||
LIS2MDL_BDU_BIT)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* set continuous MODE in default ODR, enable temperature comp. */
|
||||
if (i2c_reg_write_byte(lis2mdl->i2c, lis2mdl->i2c_addr,
|
||||
LIS2MDL_CFG_REG_A,
|
||||
LIS2MDL_MD_CONT_MODE | LIS2MDL_DEFAULT_ODR |
|
||||
LIS2MDL_COMP_TEMP_MASK)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
lis2mdl->mag_fs_sensitivity = LIS2MDL_SENSITIVITY;
|
||||
|
||||
#ifdef CONFIG_LIS2MDL_TRIGGER
|
||||
if (lis2mdl_init_interrupt(dev) < 0) {
|
||||
SYS_LOG_DBG("Failed to initialize interrupts");
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEVICE_AND_API_INIT(lis2mdl, CONFIG_LIS2MDL_DEV_NAME, lis2mdl_init,
|
||||
&lis2mdl_device_data, &lis2mdl_dev_config, POST_KERNEL,
|
||||
CONFIG_SENSOR_INIT_PRIORITY, &lis2mdl_driver_api);
|
141
drivers/sensor/lis2mdl/lis2mdl.h
Normal file
141
drivers/sensor/lis2mdl/lis2mdl.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2018 STMicroelectronics
|
||||
*
|
||||
* LIS2MDL mag header file
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __MAG_LIS2MDL_H
|
||||
#define __MAG_LIS2MDL_H
|
||||
|
||||
#include <gpio.h>
|
||||
#include <misc/util.h>
|
||||
#include <i2c.h>
|
||||
|
||||
#define SYS_LOG_DOMAIN "LIS2MDL"
|
||||
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SENSOR_LEVEL
|
||||
#include <logging/sys_log.h>
|
||||
|
||||
#define LIS2MDL_EN_BIT 1
|
||||
#define LIS2MDL_DIS_BIT 0
|
||||
#define LIS2MDL_I2C_ADDR(__x) (__x << 1)
|
||||
|
||||
#define LIS2MDL_AUTO_INCREMENT 0x80
|
||||
|
||||
/* Registers */
|
||||
#define LIS2MDL_WHO_AM_I_REG 0x4f
|
||||
#define LIS2MDL_WHOAMI_VAL 0x40
|
||||
|
||||
#define LIS2MDL_CFG_REG_A 0x60
|
||||
/* Device supported modes */
|
||||
#define LIS2MDL_MD_CONT_MODE 0x00
|
||||
#define LIS2MDL_MD_SINGLE_MODE 0x01
|
||||
#define LIS2MDL_MD_IDLE1_MODE 0x02
|
||||
#define LIS2MDL_MD_IDLE2_MODE 0x03
|
||||
#define LIS2MDL_MAG_MODE_MASK 0x03
|
||||
/* Device supported ODRs */
|
||||
#define LIS2MDL_ODR10_HZ 0x00
|
||||
#define LIS2MDL_ODR20_HZ 0x04
|
||||
#define LIS2MDL_ODR50_HZ 0x08
|
||||
#define LIS2MDL_ODR100_HZ 0x0c
|
||||
#define LIS2MDL_ODR_MASK 0x0c
|
||||
|
||||
#if defined(CONFIG_LIS2MDL_MAG_ODR_10) || \
|
||||
defined(CONFIG_LIS2MDL_MAG_ODR_RUNTIME)
|
||||
#define LIS2MDL_DEFAULT_ODR LIS2MDL_ODR10_HZ
|
||||
#elif defined(CONFIG_LIS2MDL_MAG_ODR_20)
|
||||
#define LIS2MDL_DEFAULT_ODR LIS2MDL_ODR20_HZ
|
||||
#elif defined(CONFIG_LIS2MDL_MAG_ODR_50)
|
||||
#define LIS2MDL_DEFAULT_ODR LIS2MDL_ODR50_HZ
|
||||
#elif defined(CONFIG_LIS2MDL_MAG_ODR_100)
|
||||
#define LIS2MDL_DEFAULT_ODR LIS2MDL_ODR100_HZ
|
||||
#endif
|
||||
|
||||
/* Sensors registers */
|
||||
#define LIS2MDL_OFFSET_X_REG_L 0x45
|
||||
#define LIS2MDL_OFFSET_X_REG_H 0x46
|
||||
#define LIS2MDL_OFFSET_Y_REG_L 0x47
|
||||
#define LIS2MDL_OFFSET_Y_REG_H 0x48
|
||||
#define LIS2MDL_OFFSET_Z_REG_L 0x49
|
||||
#define LIS2MDL_OFFSET_Z_REG_H 0x4A
|
||||
#define LIS2MDL_CFG_REG_B 0x61
|
||||
#define LIS2MDL_CFG_REG_C 0x62
|
||||
#define LIS2MDL_INT_CTRL_REG 0x63
|
||||
#define LIS2MDL_STATUS_REG 0x67
|
||||
#define LIS2MDL_OUT_REG 0x68
|
||||
#define LIS2MDL_TEMP_OUT_L_REG 0x6E
|
||||
#define LIS2MDL_TEMP_OUT_H_REG 0x6F
|
||||
|
||||
/* Registers bitmask */
|
||||
#define LIS2MDL_STS_MDA_UP 0x08
|
||||
#define LIS2MDL_REBOOT 0x40
|
||||
#define LIS2MDL_SOFT_RST 0x20
|
||||
#define LIS2MDL_BDU_MASK 0x10
|
||||
#define LIS2MDL_BDU_BIT 0x10
|
||||
#define LIS2MDL_INT_MAG_PIN 0x40
|
||||
#define LIS2MDL_INT_MAG_PIN_MASK 0x40
|
||||
#define LIS2MDL_INT_MAG 0x01
|
||||
#define LIS2MDL_INT_MAG_MASK 0x01
|
||||
#define LIS2MDL_MODE_MASK 0x03
|
||||
#define LIS2MDL_LP_MASK 0x10
|
||||
#define LIS2MDL_IEA 0x04
|
||||
#define LIS2MDL_IEL 0x02
|
||||
#define LIS2MDL_IEN 0x01
|
||||
#define LIS2MDL_COMP_TEMP_MASK 0x80
|
||||
|
||||
/* Output data size */
|
||||
#define LIS2MDL_OUT_REG_SIZE 6
|
||||
#define LIS2MDL_NUM_AXIS 3
|
||||
|
||||
/* Define ODR supported range */
|
||||
#define LIS2MDL_MAX_ODR 100
|
||||
#define LIS2MDL_MIN_ODR 10
|
||||
|
||||
/* Sensor sensitivity in uGa/LSB */
|
||||
#define LIS2MDL_SENSITIVITY 1500
|
||||
|
||||
struct lis2mdl_device_config {
|
||||
char *master_dev_name;
|
||||
#ifdef CONFIG_LIS2MDL_TRIGGER
|
||||
char *gpio_name;
|
||||
u32_t gpio_pin;
|
||||
#endif /* CONFIG_LIS2MDL_TRIGGER */
|
||||
u16_t i2c_addr_config;
|
||||
};
|
||||
|
||||
/* Sensor data */
|
||||
struct lis2mdl_data {
|
||||
struct device *i2c;
|
||||
u16_t i2c_addr;
|
||||
s16_t mag[3];
|
||||
s32_t temp_sample;
|
||||
|
||||
/* save sensitivity */
|
||||
u16_t mag_fs_sensitivity;
|
||||
|
||||
#ifdef CONFIG_LIS2MDL_TRIGGER
|
||||
struct device *gpio;
|
||||
struct gpio_callback gpio_cb;
|
||||
|
||||
sensor_trigger_handler_t handler_drdy;
|
||||
|
||||
#if defined(CONFIG_LIS2MDL_TRIGGER_OWN_THREAD)
|
||||
K_THREAD_STACK_MEMBER(thread_stack, CONFIG_LIS2MDL_THREAD_STACK_SIZE);
|
||||
struct k_thread thread;
|
||||
struct k_sem gpio_sem;
|
||||
#elif defined(CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD)
|
||||
struct k_work work;
|
||||
struct device *dev;
|
||||
#endif /* CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD */
|
||||
#endif /* CONFIG_LIS2MDL_TRIGGER */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_LIS2MDL_TRIGGER
|
||||
int lis2mdl_init_interrupt(struct device *dev);
|
||||
int lis2mdl_trigger_set(struct device *dev,
|
||||
const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler);
|
||||
#endif /* CONFIG_LIS2MDL_TRIGGER */
|
||||
|
||||
#endif /* __MAG_LIS2MDL_H */
|
154
drivers/sensor/lis2mdl/lis2mdl_trigger.c
Normal file
154
drivers/sensor/lis2mdl/lis2mdl_trigger.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (c) 2018 STMicroelectronics
|
||||
*
|
||||
* LIS2MDL mag interrupt configuration and management
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <sensor.h>
|
||||
#include <gpio.h>
|
||||
|
||||
#include "lis2mdl.h"
|
||||
|
||||
static int lis2mdl_enable_int(struct device *dev, int enable)
|
||||
{
|
||||
struct lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
|
||||
/* set interrupt on mag */
|
||||
return i2c_reg_update_byte(lis2mdl->i2c, lis2mdl->i2c_addr,
|
||||
LIS2MDL_CFG_REG_C,
|
||||
LIS2MDL_INT_MAG_MASK,
|
||||
enable ? LIS2MDL_INT_MAG : 0);
|
||||
}
|
||||
|
||||
/* link external trigger to event data ready */
|
||||
int lis2mdl_trigger_set(struct device *dev,
|
||||
const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler)
|
||||
{
|
||||
struct lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
u8_t raw[LIS2MDL_OUT_REG_SIZE];
|
||||
|
||||
if (trig->chan == SENSOR_CHAN_MAGN_XYZ) {
|
||||
lis2mdl->handler_drdy = handler;
|
||||
if (handler) {
|
||||
/* fetch raw data sample: re-trigger lost interrupt */
|
||||
i2c_burst_read(lis2mdl->i2c, lis2mdl->i2c_addr,
|
||||
LIS2MDL_OUT_REG,
|
||||
raw, sizeof(raw));
|
||||
return lis2mdl_enable_int(dev, 1);
|
||||
} else {
|
||||
return lis2mdl_enable_int(dev, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* handle the drdy event: read data and call handler if registered any */
|
||||
static void lis2mdl_handle_interrupt(void *arg)
|
||||
{
|
||||
struct device *dev = arg;
|
||||
struct lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
const struct lis2mdl_device_config *const config =
|
||||
dev->config->config_info;
|
||||
struct sensor_trigger drdy_trigger = {
|
||||
.type = SENSOR_TRIG_DATA_READY,
|
||||
};
|
||||
|
||||
if (lis2mdl->handler_drdy != NULL) {
|
||||
lis2mdl->handler_drdy(dev, &drdy_trigger);
|
||||
}
|
||||
|
||||
gpio_pin_enable_callback(lis2mdl->gpio, config->gpio_pin);
|
||||
}
|
||||
|
||||
static void lis2mdl_gpio_callback(struct device *dev,
|
||||
struct gpio_callback *cb, uint32_t pins)
|
||||
{
|
||||
struct lis2mdl_data *lis2mdl =
|
||||
CONTAINER_OF(cb, struct lis2mdl_data, gpio_cb);
|
||||
const struct lis2mdl_device_config *const config =
|
||||
dev->config->config_info;
|
||||
|
||||
ARG_UNUSED(pins);
|
||||
|
||||
gpio_pin_disable_callback(dev, config->gpio_pin);
|
||||
|
||||
#if defined(CONFIG_LIS2MDL_TRIGGER_OWN_THREAD)
|
||||
k_sem_give(&lis2mdl->gpio_sem);
|
||||
#elif defined(CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD)
|
||||
k_work_submit(&lis2mdl->work);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIS2MDL_TRIGGER_OWN_THREAD
|
||||
static void lis2mdl_thread(int dev_ptr, int unused)
|
||||
{
|
||||
struct device *dev = INT_TO_POINTER(dev_ptr);
|
||||
struct lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
|
||||
ARG_UNUSED(unused);
|
||||
|
||||
while (1) {
|
||||
k_sem_take(&lis2mdl->gpio_sem, K_FOREVER);
|
||||
lis2mdl_handle_interrupt(dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD
|
||||
static void lis2mdl_work_cb(struct k_work *work)
|
||||
{
|
||||
struct lis2mdl_data *lis2mdl =
|
||||
CONTAINER_OF(work, struct lis2mdl_data, work);
|
||||
|
||||
lis2mdl_handle_interrupt(lis2mdl->dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
int lis2mdl_init_interrupt(struct device *dev)
|
||||
{
|
||||
struct lis2mdl_data *lis2mdl = dev->driver_data;
|
||||
const struct lis2mdl_device_config *const config =
|
||||
dev->config->config_info;
|
||||
|
||||
/* setup data ready gpio interrupt */
|
||||
lis2mdl->gpio = device_get_binding(config->gpio_name);
|
||||
if (lis2mdl->gpio == NULL) {
|
||||
SYS_LOG_DBG("Cannot get pointer to %s device",
|
||||
config->gpio_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio_pin_configure(lis2mdl->gpio, config->gpio_pin,
|
||||
GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
|
||||
GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE);
|
||||
|
||||
gpio_init_callback(&lis2mdl->gpio_cb,
|
||||
lis2mdl_gpio_callback,
|
||||
BIT(config->gpio_pin));
|
||||
|
||||
if (gpio_add_callback(lis2mdl->gpio, &lis2mdl->gpio_cb) < 0) {
|
||||
SYS_LOG_DBG("Could not set gpio callback");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_LIS2MDL_TRIGGER_OWN_THREAD)
|
||||
k_sem_init(&lis2mdl->gpio_sem, 0, UINT_MAX);
|
||||
k_thread_create(&lis2mdl->thread, lis2mdl->thread_stack,
|
||||
CONFIG_LIS2MDL_THREAD_STACK_SIZE,
|
||||
(k_thread_entry_t)lis2mdl_thread, dev,
|
||||
0, NULL, K_PRIO_COOP(CONFIG_LIS2MDL_THREAD_PRIORITY),
|
||||
0, 0);
|
||||
#elif defined(CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD)
|
||||
lis2mdl->work.handler = lis2mdl_work_cb;
|
||||
lis2mdl->dev = dev;
|
||||
#endif
|
||||
|
||||
gpio_pin_enable_callback(lis2mdl->gpio, config->gpio_pin);
|
||||
|
||||
return 0;
|
||||
}
|
25
dts/bindings/sensor/st,lis2mdl-magn.yaml
Normal file
25
dts/bindings/sensor/st,lis2mdl-magn.yaml
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
# Copyright (c) 2018 STMicroelectronics
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
---
|
||||
title: STMicroelectronics MEMS sensors LIS2MDL
|
||||
id: st,lis2mdl-magn
|
||||
version: 0.1
|
||||
|
||||
description: >
|
||||
This binding gives a base representation of LIS2MDL magnetometer
|
||||
|
||||
inherits:
|
||||
!include i2c-device.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
constraint: "st,lis2mdl-magn"
|
||||
|
||||
irq-gpios:
|
||||
type: compound
|
||||
category: required
|
||||
generation: define, use-prop-name
|
||||
...
|
|
@ -8,6 +8,7 @@ CONFIG_SYS_LOG_SENSOR_LEVEL=4
|
|||
|
||||
CONFIG_ISL29035=y
|
||||
CONFIG_LIS2DH=y
|
||||
CONFIG_LIS2MDL=y
|
||||
CONFIG_LIS3DH=y
|
||||
CONFIG_LIS3MDL=y
|
||||
CONFIG_LPS22HB=y
|
||||
|
|
|
@ -8,6 +8,8 @@ CONFIG_ISL29035=y
|
|||
CONFIG_ISL29035_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_LIS2DH=y
|
||||
CONFIG_LIS2DH_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_LIS2MDL=y
|
||||
CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_LIS3DH=y
|
||||
CONFIG_LIS3DH_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_LSM6DSL=y
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue