sensors: ist8310: New driver

Adds support for the Isentek IST8310
3-axis magnetic sensor

Signed-off-by: Peter van der Perk <peter.vanderperk@nxp.com>
This commit is contained in:
Peter van der Perk 2023-07-19 23:13:31 -04:00 committed by Mahesh Mahadevan
commit 86812b1551
10 changed files with 389 additions and 0 deletions

View file

@ -54,6 +54,7 @@ add_subdirectory_ifdef(CONFIG_IIS3DHHC iis3dhhc)
add_subdirectory_ifdef(CONFIG_INA219 ina219) add_subdirectory_ifdef(CONFIG_INA219 ina219)
add_subdirectory_ifdef(CONFIG_INA23X ina23x) add_subdirectory_ifdef(CONFIG_INA23X ina23x)
add_subdirectory_ifdef(CONFIG_INA3221 ina3221) add_subdirectory_ifdef(CONFIG_INA3221 ina3221)
add_subdirectory_ifdef(CONFIG_IST8310 ist8310)
add_subdirectory_ifdef(CONFIG_ISL29035 isl29035) add_subdirectory_ifdef(CONFIG_ISL29035 isl29035)
add_subdirectory_ifdef(CONFIG_ISM330DHCX ism330dhcx) add_subdirectory_ifdef(CONFIG_ISM330DHCX ism330dhcx)
add_subdirectory_ifdef(CONFIG_ITDS wsen_itds) add_subdirectory_ifdef(CONFIG_ITDS wsen_itds)

View file

@ -110,6 +110,7 @@ source "drivers/sensor/ina219/Kconfig"
source "drivers/sensor/ina23x/Kconfig" source "drivers/sensor/ina23x/Kconfig"
source "drivers/sensor/ina3221/Kconfig" source "drivers/sensor/ina3221/Kconfig"
source "drivers/sensor/isl29035/Kconfig" source "drivers/sensor/isl29035/Kconfig"
source "drivers/sensor/ist8310/Kconfig"
source "drivers/sensor/ism330dhcx/Kconfig" source "drivers/sensor/ism330dhcx/Kconfig"
source "drivers/sensor/ite_tach_it8xxx2/Kconfig" source "drivers/sensor/ite_tach_it8xxx2/Kconfig"
source "drivers/sensor/ite_vcmp_it8xxx2/Kconfig" source "drivers/sensor/ite_vcmp_it8xxx2/Kconfig"

View file

@ -0,0 +1,4 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources(ist8310.c ist8310_i2c.c)

View file

@ -0,0 +1,13 @@
# IST8310 Geomagnetic sensor configuration options
# Copyright (c) 2023 NXP Semiconductors
# Copyright (c) 2023 Cognipilot Foundation
# SPDX-License-Identifier: Apache-2.0
config IST8310
bool "IST8310 I2C Geomagnetic Chip"
default y
depends on DT_HAS_ISENTEK_IST8310_ENABLED
select I2C
help
Enable driver for IST8310 I2C-based Geomagnetic sensor.

View file

@ -0,0 +1,221 @@
/* ist8310.c - Driver for Isentek IST8310 Geomagnetic Sensor */
/*
* Copyright (c) 2023 NXP Semiconductors
* Copyright (c) 2023 Cognipilot Foundation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/sys/byteorder.h>
#include <zephyr/logging/log.h>
#include "ist8310.h"
LOG_MODULE_REGISTER(IST8310, CONFIG_SENSOR_LOG_LEVEL);
static inline int ist8310_bus_check(const struct device *dev)
{
const struct ist8310_config *cfg = dev->config;
return cfg->bus_io->check(&cfg->bus);
}
static inline int ist8310_reg_read(const struct device *dev, uint8_t start, uint8_t *buf, int size)
{
const struct ist8310_config *cfg = dev->config;
return cfg->bus_io->read(&cfg->bus, start, buf, size);
}
static inline int ist8310_reg_write(const struct device *dev, uint8_t reg, uint8_t val)
{
const struct ist8310_config *cfg = dev->config;
return cfg->bus_io->write(&cfg->bus, reg, val);
}
static int ist8310_sample_fetch(const struct device *dev, enum sensor_channel chan)
{
struct ist8310_data *drv_data = dev->data;
uint8_t buff[6];
if (ist8310_reg_read(dev, IST8310_STATUS_REGISTER1, (uint8_t *)buff, 1) < 0) {
LOG_ERR("failed to read status register 1");
return -EIO;
}
if ((buff[0] & STAT1_DRDY) == 0) {
LOG_ERR("Data not ready");
if (ist8310_reg_write(dev, IST8310_CONTROL_REGISTER1, CTRL1_MODE_SINGLE) < 0) {
LOG_ERR("failed to set single");
return -EIO;
}
return -EIO;
}
if (ist8310_reg_read(dev, IST8310_OUTPUT_VALUE_X_L, (uint8_t *)buff, 6) < 0) {
LOG_ERR("failed to read mag values");
return -EIO;
}
drv_data->sample_x = (sys_le16_to_cpu(*(uint16_t *)&buff[0]));
drv_data->sample_y = (sys_le16_to_cpu(*(uint16_t *)&buff[2]));
drv_data->sample_z = (sys_le16_to_cpu(*(uint16_t *)&buff[4]));
if (ist8310_reg_write(dev, IST8310_CONTROL_REGISTER1, CTRL1_MODE_SINGLE) < 0) {
LOG_ERR("failed to set single");
return -EIO;
}
return 0;
}
static int ist8310_channel_get(const struct device *dev, enum sensor_channel chan,
struct sensor_value *val)
{
struct ist8310_data *drv_data = dev->data;
switch (chan) {
case SENSOR_CHAN_MAGN_X:
sensor_value_from_float(val, drv_data->sample_x * (1.0f / 1320));
break;
case SENSOR_CHAN_MAGN_Y:
sensor_value_from_float(val, drv_data->sample_y * (1.0f / 1320));
break;
case SENSOR_CHAN_MAGN_Z:
sensor_value_from_float(val, drv_data->sample_z * (1.0f / 1320));
break;
case SENSOR_CHAN_MAGN_XYZ:
sensor_value_from_float(val, drv_data->sample_x * (1.0f / 1320));
sensor_value_from_float(val + 1, drv_data->sample_y * (1.0f / 1320));
sensor_value_from_float(val + 2, drv_data->sample_z * (1.0f / 1320));
break;
default:
return -EINVAL;
}
return 0;
}
static const struct sensor_driver_api ist8310_api_funcs = {
.sample_fetch = ist8310_sample_fetch,
.channel_get = ist8310_channel_get,
};
static int ist8310_init_chip(const struct device *dev)
{
uint8_t reg;
/* Read chip ID (can only be read in sleep mode)*/
if (ist8310_reg_read(dev, IST8310_WHO_AM_I, &reg, 1) < 0) {
LOG_ERR("failed reading chip id");
return -EIO;
}
if (ist8310_reg_read(dev, IST8310_WHO_AM_I, &reg, 1) < 0) {
LOG_ERR("failed reading chip id");
return -EIO;
}
if (ist8310_reg_read(dev, IST8310_WHO_AM_I, &reg, 1) < 0) {
LOG_ERR("failed reading chip id");
return -EIO;
}
if (reg != IST8310_WHO_AM_I_VALUE) {
LOG_ERR("invalid chip id 0x%x", reg);
return -EIO;
}
if (ist8310_reg_read(dev, IST8310_CONTROL_REGISTER2, &reg, 1) < 0) {
LOG_ERR("failed reading chip reg2");
return -EIO;
}
reg &= ~CTRL2_SRST;
if (ist8310_reg_write(dev, IST8310_CONTROL_REGISTER2, reg) < 0) {
LOG_ERR("failed to set REG2 to %d", reg);
return -EIO;
}
k_sleep(K_MSEC(3));
if (ist8310_reg_read(dev, IST8310_CONTROL_REGISTER3, &reg, 1) < 0) {
LOG_ERR("failed reading chip reg3");
return -EIO;
}
reg |= X_16BIT | Y_16BIT | Z_16BIT;
if (ist8310_reg_write(dev, IST8310_CONTROL_REGISTER3, reg) < 0) {
LOG_ERR("failed to set REG3 to %d", reg);
return -EIO;
}
if (ist8310_reg_write(dev, IST8310_AVG_REGISTER, XZ_16TIMES_CLEAR | Y_16TIMES_CLEAR) < 0) {
LOG_ERR("failed to set AVG");
return -EIO;
}
if (ist8310_reg_write(dev, IST8310_AVG_REGISTER, XZ_16TIMES_SET | Y_16TIMES_SET) < 0) {
LOG_ERR("failed to set AVG");
return -EIO;
}
if (ist8310_reg_write(dev, IST8310_PDCNTL_REGISTER, PULSE_NORMAL) < 0) {
LOG_ERR("failed to set AVG");
return -EIO;
}
k_sleep(K_MSEC(3));
if (ist8310_reg_write(dev, IST8310_CONTROL_REGISTER1, CTRL1_MODE_SINGLE) < 0) {
LOG_ERR("failed to set single");
return -EIO;
}
return 0;
}
static int ist8310_init(const struct device *dev)
{
int err = 0;
err = ist8310_bus_check(dev);
if (err < 0) {
LOG_DBG("bus check failed: %d", err);
return err;
}
if (ist8310_init_chip(dev) < 0) {
LOG_ERR("failed to initialize chip");
return -EIO;
}
return 0;
}
/* Initializes a struct ist8310_config for an instance on an I2C bus. */
#define IST8310_CONFIG_I2C(inst) \
.bus.i2c = I2C_DT_SPEC_INST_GET(inst), .bus_io = &ist8310_bus_io_i2c,
#define IST8310_BUS_CFG(inst) \
COND_CODE_1(DT_INST_ON_BUS(inst, i2c), (IST8310_CONFIG_I2C(inst)), \
(IST8310_CONFIG_SPI(inst)))
/*
* Main instantiation macro, which selects the correct bus-specific
* instantiation macros for the instance.
*/
#define IST8310_DEFINE(inst) \
static struct ist8310_data ist8310_data_##inst; \
static const struct ist8310_config ist8310_config_##inst = {IST8310_BUS_CFG(inst)}; \
\
SENSOR_DEVICE_DT_INST_DEFINE(inst, ist8310_init, NULL, &ist8310_data_##inst, \
&ist8310_config_##inst, POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, &ist8310_api_funcs);
/* Create the struct device for every status "okay" node in the devicetree. */
DT_INST_FOREACH_STATUS_OKAY(IST8310_DEFINE)

View file

@ -0,0 +1,99 @@
/* ist8310.h - header file for IST8310 Geomagnetic sensor driver */
/*
* Copyright (c) 2023 NXP Semiconductors
* Copyright (c) 2023 Cognipilot Foundation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_IST8310_IST8310_H_
#define ZEPHYR_DRIVERS_SENSOR_IST8310_IST8310_H_
#include <zephyr/types.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/sys/util.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/drivers/gpio.h>
#include <stdint.h>
#define DT_DRV_COMPAT isentek_ist8310
#define IST8310_BUS_I2C DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
union ist8310_bus {
struct i2c_dt_spec i2c;
};
typedef int (*ist8310_bus_check_fn)(const union ist8310_bus *bus);
typedef int (*ist8310_reg_read_fn)(const union ist8310_bus *bus,
uint8_t start, uint8_t *buf, int size);
typedef int (*ist8310_reg_write_fn)(const union ist8310_bus *bus,
uint8_t reg, uint8_t val);
struct ist8310_bus_io {
ist8310_bus_check_fn check;
ist8310_reg_read_fn read;
ist8310_reg_write_fn write;
};
extern const struct ist8310_bus_io ist8310_bus_io_i2c;
#define IST8310_WHO_AM_I 0x00
#define IST8310_WHO_AM_I_VALUE 0x10
#define IST8310_STATUS_REGISTER1 0x02
#define STAT1_DRDY 0x01
#define STAT1_DRO 0x02
#define IST8310_OUTPUT_VALUE_X_L 0x03
#define IST8310_OUTPUT_VALUE_X_H 0x04
#define IST8310_OUTPUT_VALUE_Y_L 0x05
#define IST8310_OUTPUT_VALUE_Y_H 0x06
#define IST8310_OUTPUT_VALUE_Z_L 0x07
#define IST8310_OUTPUT_VALUE_Z_H 0x08
#define IST8310_CONTROL_REGISTER1 0x0A
#define CTRL1_MODE_SINGLE 0x1
#define IST8310_CONTROL_REGISTER2 0x0B
#define CTRL2_SRST 0x01
#define IST8310_OUTPUT_VALUE_T_L 0x1C
#define IST8310_OUTPUT_VALUE_T_H 0x1D
#define IST8310_CONTROL_REGISTER3 0x0d
#define Z_16BIT 0x40
#define Y_16BIT 0x20
#define X_16BIT 0x10
#define IST8310_AVG_REGISTER 0x41
#define Y_16TIMES_SET 0x20
#define Y_16TIMES_CLEAR 0x18
#define XZ_16TIMES_SET 0x04
#define XZ_16TIMES_CLEAR 0x03
#define IST8310_PDCNTL_REGISTER 0x42
#define PULSE_NORMAL 0xC0
struct ist8310_config {
union ist8310_bus bus;
const struct ist8310_bus_io *bus_io;
};
struct ist8310_data {
struct k_sem sem;
int16_t sample_x, sample_y, sample_z;
};
int ist8310_reg_update_byte(const struct device *dev, uint8_t reg,
uint8_t mask, uint8_t value);
#endif /* __SENSOR_IST8310_H__ */

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2023 NXP Semiconductors
* Copyright (c) 2023 Cognipilot Foundation
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Bus-specific functionality for IST8310 accessed via I2C.
*/
#include "ist8310.h"
static int ist8310_bus_check_i2c(const union ist8310_bus *bus)
{
return i2c_is_ready_dt(&bus->i2c) ? 0 : -ENODEV;
}
static int ist8310_reg_read_i2c(const union ist8310_bus *bus, uint8_t start, uint8_t *buf, int size)
{
return i2c_burst_read_dt(&bus->i2c, start, buf, size);
}
static int ist8310_reg_write_i2c(const union ist8310_bus *bus, uint8_t reg, uint8_t val)
{
return i2c_reg_write_byte_dt(&bus->i2c, reg, val);
}
const struct ist8310_bus_io ist8310_bus_io_i2c = {
.check = ist8310_bus_check_i2c,
.read = ist8310_reg_read_i2c,
.write = ist8310_reg_write_i2c,
};

View file

@ -0,0 +1,10 @@
# Copyright (c) 2019, Linaro Limited
# SPDX-License-Identifier: Apache-2.0
description: |
Istentek ist8310 Geomagnetic sensor. See more info at:
https://isentek.com/products_view.php?PID=10&sn=13
compatible: "isentek,ist8310"
include: ["i2c-device.yaml", "sensor-device.yaml"]

View file

@ -292,6 +292,7 @@ invensense InvenSense Inc.
inversepath Inverse Path inversepath Inverse Path
iom Iomega Corporation iom Iomega Corporation
isee ISEE 2007 S.L. isee ISEE 2007 S.L.
isentek Isentek Inc.
isil Intersil isil Intersil
issi Integrated Silicon Solutions Inc. issi Integrated Silicon Solutions Inc.
ite ITE Tech. Inc. ite ITE Tech. Inc.

View file

@ -738,3 +738,9 @@ test_i2c_bmi08x_gyro: bmi08x@6e {
gyro-hz = "1000_116"; gyro-hz = "1000_116";
gyro-fs = <1000>; gyro-fs = <1000>;
}; };
test_i2c_ist8310@6f {
compatible = "isentek,ist8310";
reg = <0x6f>;
status = "okay";
};