drivers:iio:stm:pressure: Add support to ST MEMS LPS22DF pressure sensor
Added support to LPS22DF ST MEMS pressure and temperature sensor List of supported features: - Configurable ODRs [Power_Off ... 200] Hz - Sensor Event Timestamp support - Read single raw data values for pressure and temperature - FIFO: > Pressure data stored in FIFO > HW Watermark configuration > Custom Flush command / event support Signed-off-by: mario tesi <mario.tesi@st.com> Change-Id: Ia3be1f93498c6c46345a067c6323968a94014662
This commit is contained in:
parent
d5a9842abc
commit
28089ed3d7
@ -25,4 +25,26 @@ config ST_LPS22HH_SPI_IIO
|
||||
tristate
|
||||
depends on ST_LPS22HH_IIO
|
||||
|
||||
config ST_LPS22DF_IIO
|
||||
tristate "STMicroelectronics LPS22DF sensor"
|
||||
depends on (I2C || SPI_MASTER) && SYSFS
|
||||
select IIO_BUFFER
|
||||
select IIO_KFIFO_BUF
|
||||
select ST_LPS22DF_I2C_IIO if (I2C)
|
||||
select ST_LPS22DF_SPI_IIO if (SPI)
|
||||
help
|
||||
Say yes here to build support for the ST MEMS LPS22DF pressure and
|
||||
temperature sensor.
|
||||
|
||||
This driver can be built as a module. The module will be called
|
||||
st-lps22df.
|
||||
|
||||
config ST_LPS22DF_I2C_IIO
|
||||
tristate
|
||||
depends on ST_LPS22DF_IIO
|
||||
|
||||
config ST_LPS22DF_SPI_IIO
|
||||
tristate
|
||||
depends on ST_LPS22DF_IIO
|
||||
|
||||
endmenu
|
||||
|
@ -9,3 +9,10 @@ obj-$(CONFIG_ST_LPS22HH_I2C_IIO) += st_lps22hh_i2c.o
|
||||
obj-$(CONFIG_ST_LPS22HH_SPI_IIO) += st_lps22hh_spi.o
|
||||
|
||||
st_lps22hh-y += st_lps22hh_core.o st_lps22hh_buffer.o
|
||||
|
||||
obj-$(CONFIG_ST_LPS22DF_IIO) += st_lps22df.o
|
||||
obj-$(CONFIG_ST_LPS22DF_I2C_IIO) += st_lps22df_i2c.o
|
||||
obj-$(CONFIG_ST_LPS22DF_SPI_IIO) += st_lps22df_spi.o
|
||||
|
||||
st_lps22df-y += st_lps22df_core.o st_lps22df_buffer.o
|
||||
|
||||
|
138
drivers/iio/stm/pressure/st_lps22df.h
Normal file
138
drivers/iio/stm/pressure/st_lps22df.h
Normal file
@ -0,0 +1,138 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* STMicroelectronics lps22df driver
|
||||
*
|
||||
* Copyright 2021 STMicroelectronics Inc.
|
||||
*
|
||||
* Mario Tesi <mario.tesi@st.com>
|
||||
*/
|
||||
|
||||
#ifndef __ST_LPS22DF_H
|
||||
#define __ST_LPS22DF_H
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
|
||||
#define ST_LPS22DF_MAX_FIFO_LENGTH 127
|
||||
|
||||
#define ST_LPS22DF_INTERRUPT_CFG_ADDR 0x0b
|
||||
#define ST_LPS22DF_LIR_MASK BIT(2)
|
||||
|
||||
#define ST_LPS22DF_WHO_AM_I_ADDR 0x0f
|
||||
#define ST_LPS22DF_WHO_AM_I_VAL 0xb4
|
||||
|
||||
#define ST_LPS22DF_CTRL_REG1_ADDR 0x10
|
||||
#define ST_LPS22DF_AVG_MASK GENMASK(2, 0)
|
||||
#define ST_LPS22DF_ODR_MASK GENMASK(6, 3)
|
||||
|
||||
#define ST_LPS22DF_CTRL_REG2_ADDR 0x11
|
||||
#define ST_LPS22DF_SWRESET_MASK BIT(2)
|
||||
#define ST_LPS22DF_BDU_MASK BIT(3)
|
||||
#define ST_LPS22DF_EN_LPFP_MASK BIT(4)
|
||||
#define ST_LPS22DF_BOOT_MASK BIT(7)
|
||||
|
||||
#define ST_LPS22DF_CTRL3_ADDR 0x12
|
||||
#define ST_LPS22DF_IF_ADD_INC_MASK BIT(0)
|
||||
#define ST_LPS22DF_PP_OD_MASK BIT(1)
|
||||
#define ST_LPS22DF_INT_H_L_MASK BIT(3)
|
||||
|
||||
#define ST_LPS22DF_CTRL4_ADDR 0x13
|
||||
#define ST_LPS22DF_INT_F_WTM_MASK BIT(1)
|
||||
|
||||
#define ST_LPS22DF_FIFO_CTRL_ADDR 0x14
|
||||
#define ST_LPS22DF_FIFO_MODE_MASK GENMASK(1, 0)
|
||||
|
||||
#define ST_LPS22DF_FIFO_WTM_ADDR 0x15
|
||||
#define ST_LPS22DF_FIFO_THS_MASK GENMASK(6, 0)
|
||||
|
||||
#define ST_LPS22DF_FIFO_STATUS1_ADDR 0x25
|
||||
#define ST_LPS22DF_FIFO_SRC_DIFF_MASK GENMASK(7, 0)
|
||||
|
||||
#define ST_LPS22DF_FIFO_STATUS2_ADDR 0x26
|
||||
#define ST_LPS22DF_FIFO_WTM_IA_MASK BIT(7)
|
||||
|
||||
#define ST_LPS22DF_PRESS_OUT_XL_ADDR 0x28
|
||||
|
||||
#define ST_LPS22DF_TEMP_OUT_L_ADDR 0x2b
|
||||
|
||||
#define ST_LPS22DF_FIFO_DATA_OUT_PRESS_XL_ADDR 0x78
|
||||
|
||||
#define ST_LPS22DF_PRESS_FS_AVL_GAIN (1000000000UL / 4096UL)
|
||||
#define ST_LPS22DF_TEMP_FS_AVL_GAIN (1000000000UL / 100UL)
|
||||
|
||||
#define ST_LPS22DF_ODR_LIST_NUM 9
|
||||
|
||||
enum st_lps22df_sensor_type {
|
||||
ST_LPS22DF_PRESS = 0,
|
||||
ST_LPS22DF_TEMP,
|
||||
ST_LPS22DF_SENSORS_NUMB,
|
||||
};
|
||||
|
||||
enum st_lps22df_fifo_mode {
|
||||
ST_LPS22DF_BYPASS = 0x0,
|
||||
ST_LPS22DF_STREAM = 0x2,
|
||||
};
|
||||
|
||||
#define ST_LPS22DF_PRESS_SAMPLE_LEN 3
|
||||
#define ST_LPS22DF_TEMP_SAMPLE_LEN 2
|
||||
|
||||
#define ST_LPS22DF_TX_MAX_LENGTH 64
|
||||
#define ST_LPS22DF_RX_MAX_LENGTH ((ST_LPS22DF_MAX_FIFO_LENGTH + 1) * \
|
||||
ST_LPS22DF_PRESS_SAMPLE_LEN)
|
||||
|
||||
struct st_lps22df_transfer_buffer {
|
||||
u8 rx_buf[ST_LPS22DF_RX_MAX_LENGTH];
|
||||
u8 tx_buf[ST_LPS22DF_TX_MAX_LENGTH] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
struct st_lps22df_transfer_function {
|
||||
int (*write)(struct device *dev, u8 addr, int len, u8 *data);
|
||||
int (*read)(struct device *dev, u8 addr, int len, u8 *data);
|
||||
};
|
||||
|
||||
struct st_lps22df_hw {
|
||||
struct device *dev;
|
||||
int irq;
|
||||
|
||||
struct mutex fifo_lock;
|
||||
struct mutex lock;
|
||||
u8 watermark;
|
||||
|
||||
struct iio_dev *iio_devs[ST_LPS22DF_SENSORS_NUMB];
|
||||
u8 enable_mask;
|
||||
u8 odr;
|
||||
|
||||
s64 last_fifo_ts;
|
||||
s64 delta_ts;
|
||||
s64 ts_irq;
|
||||
s64 ts;
|
||||
|
||||
const struct st_lps22df_transfer_function *tf;
|
||||
struct st_lps22df_transfer_buffer tb;
|
||||
};
|
||||
|
||||
struct st_lps22df_sensor {
|
||||
struct st_lps22df_hw *hw;
|
||||
enum st_lps22df_sensor_type type;
|
||||
char name[32];
|
||||
|
||||
u32 gain;
|
||||
u8 odr;
|
||||
};
|
||||
|
||||
int st_lps22df_common_probe(struct device *dev, int irq, const char *name,
|
||||
const struct st_lps22df_transfer_function *tf_ops);
|
||||
int st_lps22df_write_with_mask(struct st_lps22df_hw *hw, u8 addr, u8 mask,
|
||||
u8 data);
|
||||
int st_lps22df_allocate_buffers(struct st_lps22df_hw *hw);
|
||||
int st_lps22df_set_enable(struct st_lps22df_sensor *sensor, bool enable);
|
||||
ssize_t st_lps22df_sysfs_set_hwfifo_watermark(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
ssize_t st_lps22df_sysfs_flush_fifo(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size);
|
||||
|
||||
#endif /* __ST_LPS22DF_H */
|
299
drivers/iio/stm/pressure/st_lps22df_buffer.c
Normal file
299
drivers/iio/stm/pressure/st_lps22df_buffer.c
Normal file
@ -0,0 +1,299 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics lps22df buffer driver
|
||||
*
|
||||
* Copyright 2021 STMicroelectronics Inc.
|
||||
*
|
||||
* Mario Tesi <mario.tesi@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/iio/events.h>
|
||||
|
||||
#include "st_lps22df.h"
|
||||
|
||||
#define ST_LPS22DF_EWMA_LEVEL 96
|
||||
#define ST_LPS22DF_EWMA_DIV 128
|
||||
|
||||
static inline s64 st_lps22df_ewma(s64 old, s64 new, int weight)
|
||||
{
|
||||
s64 diff, incr;
|
||||
|
||||
diff = new - old;
|
||||
incr = div_s64((ST_LPS22DF_EWMA_DIV - weight) * diff,
|
||||
ST_LPS22DF_EWMA_DIV);
|
||||
|
||||
return old + incr;
|
||||
}
|
||||
|
||||
static inline s64 st_lps22df_get_time_ns(struct st_lps22df_hw *hw)
|
||||
{
|
||||
return iio_get_time_ns(hw->iio_devs[ST_LPS22DF_PRESS]);
|
||||
}
|
||||
|
||||
static int st_lps22df_set_fifo_mode(struct st_lps22df_hw *hw,
|
||||
enum st_lps22df_fifo_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case ST_LPS22DF_BYPASS:
|
||||
case ST_LPS22DF_STREAM:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return st_lps22df_write_with_mask(hw, ST_LPS22DF_FIFO_CTRL_ADDR,
|
||||
ST_LPS22DF_FIFO_MODE_MASK, mode);
|
||||
}
|
||||
|
||||
static int st_lps22df_update_fifo_watermark(struct st_lps22df_hw *hw, u8 val)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = st_lps22df_write_with_mask(hw, ST_LPS22DF_FIFO_WTM_ADDR,
|
||||
ST_LPS22DF_FIFO_THS_MASK, val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hw->watermark = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t st_lps22df_sysfs_set_hwfifo_watermark(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct st_lps22df_sensor *sensor = iio_priv(dev_get_drvdata(dev));
|
||||
int err, watermark;
|
||||
|
||||
err = kstrtoint(buf, 10, &watermark);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (watermark < 1 || watermark > ST_LPS22DF_MAX_FIFO_LENGTH)
|
||||
return -EINVAL;
|
||||
|
||||
err = st_lps22df_update_fifo_watermark(sensor->hw, watermark);
|
||||
|
||||
return err < 0 ? err : count;
|
||||
}
|
||||
|
||||
static int st_lps22df_read_fifo(struct st_lps22df_hw *hw, s64 delta_ts)
|
||||
{
|
||||
u8 iio_buff[ALIGN(sizeof(u32) + sizeof(s64), sizeof(s64))];
|
||||
u8 buff[ST_LPS22DF_RX_MAX_LENGTH];
|
||||
int err, i, read_len;
|
||||
__le16 fifo_status;
|
||||
|
||||
err = hw->tf->read(hw->dev, ST_LPS22DF_FIFO_STATUS1_ADDR,
|
||||
sizeof(fifo_status), (u8 *)&fifo_status);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
read_len = (le16_to_cpu(fifo_status) & ST_LPS22DF_FIFO_SRC_DIFF_MASK) *
|
||||
ST_LPS22DF_PRESS_SAMPLE_LEN;
|
||||
if (!read_len)
|
||||
return 0;
|
||||
|
||||
err = hw->tf->read(hw->dev, ST_LPS22DF_FIFO_DATA_OUT_PRESS_XL_ADDR,
|
||||
read_len, buff);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < read_len; i += ST_LPS22DF_PRESS_SAMPLE_LEN) {
|
||||
memcpy(iio_buff, buff + i, ST_LPS22DF_PRESS_SAMPLE_LEN);
|
||||
iio_push_to_buffers_with_timestamp(
|
||||
hw->iio_devs[ST_LPS22DF_PRESS],
|
||||
iio_buff, hw->ts);
|
||||
hw->ts += delta_ts;
|
||||
}
|
||||
|
||||
hw->last_fifo_ts = hw->ts;
|
||||
|
||||
return read_len;
|
||||
}
|
||||
|
||||
ssize_t st_lps22df_sysfs_flush_fifo(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct st_lps22df_sensor *sensor = iio_priv(indio_dev);
|
||||
struct st_lps22df_hw *hw = sensor->hw;
|
||||
int len, dir;
|
||||
s64 fts;
|
||||
|
||||
mutex_lock(&hw->fifo_lock);
|
||||
len = st_lps22df_read_fifo(hw, hw->delta_ts);
|
||||
hw->ts = st_lps22df_get_time_ns(hw);
|
||||
hw->ts_irq = hw->ts;
|
||||
|
||||
/* flush event timestamp must match with last sample pushed in fifo */
|
||||
if (len)
|
||||
fts = hw->ts;
|
||||
else
|
||||
fts = hw->last_fifo_ts;
|
||||
|
||||
mutex_unlock(&hw->fifo_lock);
|
||||
|
||||
dir = len > 0 ? IIO_EV_DIR_FIFO_DATA : IIO_EV_DIR_FIFO_EMPTY;
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_PRESSURE, -1,
|
||||
IIO_EV_TYPE_FIFO_FLUSH, dir),
|
||||
fts);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static irqreturn_t st_lps22df_irq_handler(int irq, void *private)
|
||||
{
|
||||
struct st_lps22df_hw *hw = private;
|
||||
s64 delta_ts, ts = st_lps22df_get_time_ns(hw);
|
||||
|
||||
delta_ts = div_s64((ts - hw->ts_irq), hw->watermark);
|
||||
if (hw->odr >= 50)
|
||||
hw->delta_ts = st_lps22df_ewma(hw->delta_ts, delta_ts,
|
||||
ST_LPS22DF_EWMA_LEVEL);
|
||||
else
|
||||
hw->delta_ts = delta_ts;
|
||||
|
||||
hw->ts_irq = ts;
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t st_lps22df_irq_thread(int irq, void *private)
|
||||
{
|
||||
struct st_lps22df_hw *hw = private;
|
||||
|
||||
mutex_lock(&hw->fifo_lock);
|
||||
st_lps22df_read_fifo(hw, hw->delta_ts);
|
||||
mutex_unlock(&hw->fifo_lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int st_lps22df_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_lps22df_sensor *sensor = iio_priv(indio_dev);
|
||||
struct st_lps22df_hw *hw = sensor->hw;
|
||||
int err;
|
||||
|
||||
err = st_lps22df_set_fifo_mode(sensor->hw, ST_LPS22DF_STREAM);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = st_lps22df_update_fifo_watermark(hw, hw->watermark);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = st_lps22df_write_with_mask(sensor->hw, ST_LPS22DF_CTRL4_ADDR,
|
||||
ST_LPS22DF_INT_F_WTM_MASK, true);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = st_lps22df_set_enable(sensor, true);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hw->delta_ts = div_s64(1000000000UL, hw->odr);
|
||||
hw->ts = st_lps22df_get_time_ns(hw);
|
||||
hw->ts_irq = hw->ts;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_lps22df_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_lps22df_sensor *sensor = iio_priv(indio_dev);
|
||||
int err;
|
||||
|
||||
err = st_lps22df_set_fifo_mode(sensor->hw, ST_LPS22DF_BYPASS);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = st_lps22df_write_with_mask(sensor->hw, ST_LPS22DF_CTRL4_ADDR,
|
||||
ST_LPS22DF_INT_F_WTM_MASK, false);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return st_lps22df_set_enable(sensor, false);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops st_lps22df_buffer_ops = {
|
||||
.preenable = st_lps22df_buffer_preenable,
|
||||
.postdisable = st_lps22df_buffer_postdisable,
|
||||
};
|
||||
|
||||
int st_lps22df_allocate_buffers(struct st_lps22df_hw *hw)
|
||||
{
|
||||
struct iio_buffer *buffer;
|
||||
unsigned long irq_type;
|
||||
u8 int_active = 0;
|
||||
int err;
|
||||
|
||||
irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
|
||||
|
||||
switch (irq_type) {
|
||||
case IRQF_TRIGGER_HIGH:
|
||||
case IRQF_TRIGGER_RISING:
|
||||
int_active = 0;
|
||||
break;
|
||||
case IRQF_TRIGGER_LOW:
|
||||
case IRQF_TRIGGER_FALLING:
|
||||
int_active = 1;
|
||||
break;
|
||||
default:
|
||||
dev_info(hw->dev, "mode %lx unsupported\n", irq_type);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* int pin active low */
|
||||
if (device_property_read_bool(hw->dev, "int-active-low")) {
|
||||
err = st_lps22df_write_with_mask(hw, ST_LPS22DF_CTRL3_ADDR,
|
||||
ST_LPS22DF_INT_H_L_MASK, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* int pin open drain configuration */
|
||||
if (device_property_read_bool(hw->dev, "int-open-drain")) {
|
||||
err = st_lps22df_write_with_mask(hw, ST_LPS22DF_CTRL3_ADDR,
|
||||
ST_LPS22DF_PP_OD_MASK, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = st_lps22df_write_with_mask(hw, ST_LPS22DF_CTRL3_ADDR,
|
||||
ST_LPS22DF_INT_H_L_MASK,
|
||||
int_active);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = devm_request_threaded_irq(hw->dev, hw->irq,
|
||||
st_lps22df_irq_handler,
|
||||
st_lps22df_irq_thread,
|
||||
irq_type | IRQF_ONESHOT,
|
||||
"lps22df", hw);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
buffer = devm_iio_kfifo_allocate(hw->dev);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
iio_device_attach_buffer(hw->iio_devs[ST_LPS22DF_PRESS], buffer);
|
||||
hw->iio_devs[ST_LPS22DF_PRESS]->modes |= INDIO_BUFFER_SOFTWARE;
|
||||
hw->iio_devs[ST_LPS22DF_PRESS]->setup_ops = &st_lps22df_buffer_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("STMicroelectronics lps22df buffer driver");
|
||||
MODULE_AUTHOR("Mario Tesi <mario.tesi@st.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
461
drivers/iio/stm/pressure/st_lps22df_core.c
Normal file
461
drivers/iio/stm/pressure/st_lps22df_core.c
Normal file
@ -0,0 +1,461 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics lps22df driver
|
||||
*
|
||||
* Copyright 2021 STMicroelectronics Inc.
|
||||
*
|
||||
* Mario Tesi <mario.tesi@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "st_lps22df.h"
|
||||
|
||||
struct st_lps22df_odr_table_t {
|
||||
u8 addr;
|
||||
u8 mask;
|
||||
u8 odr_avl[ST_LPS22DF_ODR_LIST_NUM];
|
||||
};
|
||||
|
||||
const static struct st_lps22df_odr_table_t st_lps22df_odr_table = {
|
||||
.addr = ST_LPS22DF_CTRL_REG1_ADDR,
|
||||
.mask = ST_LPS22DF_ODR_MASK,
|
||||
.odr_avl = { 0, 1, 4, 10, 25, 50, 75, 100, 200 },
|
||||
};
|
||||
|
||||
const struct iio_event_spec st_lps22df_fifo_flush_event = {
|
||||
.type = IIO_EV_TYPE_FIFO_FLUSH,
|
||||
.dir = IIO_EV_DIR_EITHER,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec st_lps22df_press_channels[] = {
|
||||
{
|
||||
.type = IIO_PRESSURE,
|
||||
.address = ST_LPS22DF_PRESS_OUT_XL_ADDR,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.channel2 = IIO_NO_MOD,
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 24,
|
||||
.storagebits = 32,
|
||||
.endianness = IIO_LE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = IIO_PRESSURE,
|
||||
.scan_index = -1,
|
||||
.indexed = -1,
|
||||
.event_spec = &st_lps22df_fifo_flush_event,
|
||||
.num_event_specs = 1,
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1)
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec st_lps22df_temp_channels[] = {
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.address = ST_LPS22DF_TEMP_OUT_L_ADDR,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.channel2 = IIO_NO_MOD,
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_LE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
int st_lps22df_write_with_mask(struct st_lps22df_hw *hw, u8 addr, u8 mask,
|
||||
u8 val)
|
||||
{
|
||||
int err;
|
||||
u8 data;
|
||||
|
||||
mutex_lock(&hw->lock);
|
||||
|
||||
err = hw->tf->read(hw->dev, addr, sizeof(data), &data);
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
|
||||
data = (data & ~mask) | ((val << __ffs(mask)) & mask);
|
||||
err = hw->tf->write(hw->dev, addr, sizeof(data), &data);
|
||||
unlock:
|
||||
mutex_unlock(&hw->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int st_lps22df_check_whoami(struct st_lps22df_hw *hw)
|
||||
{
|
||||
int err;
|
||||
u8 data;
|
||||
|
||||
err = hw->tf->read(hw->dev, ST_LPS22DF_WHO_AM_I_ADDR, sizeof(data),
|
||||
&data);
|
||||
if (err < 0) {
|
||||
dev_err(hw->dev, "failed to read Who-Am-I register\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
if (data != ST_LPS22DF_WHO_AM_I_VAL) {
|
||||
dev_err(hw->dev, "Who-Am-I value not valid (%x)\n", data);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_lps22df_get_odr(struct st_lps22df_sensor *sensor, u8 odr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ST_LPS22DF_ODR_LIST_NUM; i++) {
|
||||
if (st_lps22df_odr_table.odr_avl[i] == odr)
|
||||
break;
|
||||
}
|
||||
|
||||
return i == ST_LPS22DF_ODR_LIST_NUM ? -EINVAL : i;
|
||||
}
|
||||
|
||||
int st_lps22df_set_enable(struct st_lps22df_sensor *sensor, bool enable)
|
||||
{
|
||||
struct st_lps22df_hw *hw = sensor->hw;
|
||||
u32 max_odr = enable ? sensor->odr : 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ST_LPS22DF_SENSORS_NUMB; i++) {
|
||||
if (sensor->type == i)
|
||||
continue;
|
||||
|
||||
if (hw->enable_mask & BIT(i)) {
|
||||
struct st_lps22df_sensor *temp;
|
||||
|
||||
temp = iio_priv(hw->iio_devs[i]);
|
||||
max_odr = max_t(u32, max_odr, temp->odr);
|
||||
}
|
||||
}
|
||||
|
||||
if (max_odr != hw->odr) {
|
||||
int err, ret;
|
||||
|
||||
ret = st_lps22df_get_odr(sensor, max_odr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
err = st_lps22df_write_with_mask(hw, st_lps22df_odr_table.addr,
|
||||
st_lps22df_odr_table.mask,
|
||||
ret);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hw->odr = max_odr;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
hw->enable_mask |= BIT(sensor->type);
|
||||
else
|
||||
hw->enable_mask &= ~BIT(sensor->type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_lps22df_init_sensors(struct st_lps22df_hw *hw)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* reboot memory content */
|
||||
err = st_lps22df_write_with_mask(hw, ST_LPS22DF_CTRL_REG2_ADDR,
|
||||
ST_LPS22DF_BOOT_MASK, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
usleep_range(8000, 10000);
|
||||
|
||||
/* soft reset the device on power on */
|
||||
err = st_lps22df_write_with_mask(hw, ST_LPS22DF_CTRL_REG2_ADDR,
|
||||
ST_LPS22DF_SWRESET_MASK, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
usleep_range(100, 200);
|
||||
|
||||
/* enable latched interrupt mode */
|
||||
err = st_lps22df_write_with_mask(hw, ST_LPS22DF_INTERRUPT_CFG_ADDR,
|
||||
ST_LPS22DF_LIR_MASK, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* enable BDU */
|
||||
return st_lps22df_write_with_mask(hw, ST_LPS22DF_CTRL_REG2_ADDR,
|
||||
ST_LPS22DF_BDU_MASK, 1);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
st_lps22df_get_sampling_frequency_avail(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int i, len = 0;
|
||||
|
||||
for (i = 1; i < ST_LPS22DF_ODR_LIST_NUM; i++) {
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
|
||||
st_lps22df_odr_table.odr_avl[i]);
|
||||
}
|
||||
|
||||
buf[len - 1] = '\n';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
st_lps22df_sysfs_get_hwfifo_watermark(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct st_lps22df_sensor *sensor = iio_priv(dev_get_drvdata(dev));
|
||||
|
||||
return sprintf(buf, "%d\n", sensor->hw->watermark);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
st_lps22df_sysfs_get_hwfifo_watermark_max(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", ST_LPS22DF_MAX_FIFO_LENGTH);
|
||||
}
|
||||
|
||||
static int st_lps22df_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *ch,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct st_lps22df_sensor *sensor = iio_priv(indio_dev);
|
||||
struct st_lps22df_hw *hw = sensor->hw;
|
||||
int ret, delay;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW: {
|
||||
u8 data[4] = {};
|
||||
u8 len;
|
||||
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = st_lps22df_set_enable(sensor, true);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
/* wait at least 10% more than one odr */
|
||||
delay = 1100000 / sensor->odr;
|
||||
usleep_range(delay, 2 * delay);
|
||||
len = ch->scan_type.realbits >> 3;
|
||||
ret = hw->tf->read(hw->dev, ch->address, len, data);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
if (sensor->type == ST_LPS22DF_PRESS)
|
||||
*val = (s32)get_unaligned_le32(data);
|
||||
else if (sensor->type == ST_LPS22DF_TEMP)
|
||||
*val = (s16)get_unaligned_le16(data);
|
||||
|
||||
unlock:
|
||||
ret = st_lps22df_set_enable(sensor, false);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
|
||||
ret = ret < 0 ? ret : IIO_VAL_INT;
|
||||
break;
|
||||
}
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (ch->type) {
|
||||
case IIO_TEMP:
|
||||
*val = 1000;
|
||||
*val2 = sensor->gain;
|
||||
ret = IIO_VAL_FRACTIONAL;
|
||||
break;
|
||||
case IIO_PRESSURE:
|
||||
*val = 0;
|
||||
*val2 = sensor->gain;
|
||||
ret = IIO_VAL_INT_PLUS_NANO;
|
||||
break;
|
||||
default:
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = sensor->odr;
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int st_lps22df_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *ch,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct st_lps22df_sensor *sensor = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = st_lps22df_get_odr(sensor, val);
|
||||
if (ret > 0)
|
||||
sensor->odr = val;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lps22df_get_sampling_frequency_avail);
|
||||
static IIO_DEVICE_ATTR(hwfifo_watermark, 0644,
|
||||
st_lps22df_sysfs_get_hwfifo_watermark,
|
||||
st_lps22df_sysfs_set_hwfifo_watermark, 0);
|
||||
static IIO_DEVICE_ATTR(hwfifo_watermark_max, 0444,
|
||||
st_lps22df_sysfs_get_hwfifo_watermark_max, NULL, 0);
|
||||
static IIO_DEVICE_ATTR(hwfifo_flush, 0200, NULL,
|
||||
st_lps22df_sysfs_flush_fifo, 0);
|
||||
|
||||
static struct attribute *st_lps22df_press_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_dev_attr_hwfifo_watermark.dev_attr.attr,
|
||||
&iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
|
||||
&iio_dev_attr_hwfifo_flush.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *st_lps22df_temp_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group st_lps22df_press_attribute_group = {
|
||||
.attrs = st_lps22df_press_attributes,
|
||||
};
|
||||
static const struct attribute_group st_lps22df_temp_attribute_group = {
|
||||
.attrs = st_lps22df_temp_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info st_lps22df_press_info = {
|
||||
.attrs = &st_lps22df_press_attribute_group,
|
||||
.read_raw = st_lps22df_read_raw,
|
||||
.write_raw = st_lps22df_write_raw,
|
||||
};
|
||||
|
||||
static const struct iio_info st_lps22df_temp_info = {
|
||||
.attrs = &st_lps22df_temp_attribute_group,
|
||||
.read_raw = st_lps22df_read_raw,
|
||||
.write_raw = st_lps22df_write_raw,
|
||||
};
|
||||
|
||||
int st_lps22df_common_probe(struct device *dev, int irq, const char *name,
|
||||
const struct st_lps22df_transfer_function *tf_ops)
|
||||
{
|
||||
struct st_lps22df_sensor *sensor;
|
||||
struct st_lps22df_hw *hw;
|
||||
struct iio_dev *iio_dev;
|
||||
int err, i;
|
||||
|
||||
hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
|
||||
if (!hw)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, (void *)hw);
|
||||
hw->dev = dev;
|
||||
hw->tf = tf_ops;
|
||||
hw->irq = irq;
|
||||
|
||||
/* set initial watermark */
|
||||
hw->watermark = 1;
|
||||
|
||||
mutex_init(&hw->lock);
|
||||
mutex_init(&hw->fifo_lock);
|
||||
|
||||
err = st_lps22df_check_whoami(hw);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < ST_LPS22DF_SENSORS_NUMB; i++) {
|
||||
iio_dev = devm_iio_device_alloc(dev, sizeof(*sensor));
|
||||
if (!iio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
hw->iio_devs[i] = iio_dev;
|
||||
sensor = iio_priv(iio_dev);
|
||||
sensor->hw = hw;
|
||||
sensor->type = i;
|
||||
sensor->odr = 1;
|
||||
|
||||
switch (i) {
|
||||
case ST_LPS22DF_PRESS:
|
||||
sensor->gain = ST_LPS22DF_PRESS_FS_AVL_GAIN;
|
||||
scnprintf(sensor->name, sizeof(sensor->name),
|
||||
"%s_press", name);
|
||||
iio_dev->channels = st_lps22df_press_channels;
|
||||
iio_dev->num_channels =
|
||||
ARRAY_SIZE(st_lps22df_press_channels);
|
||||
iio_dev->info = &st_lps22df_press_info;
|
||||
break;
|
||||
case ST_LPS22DF_TEMP:
|
||||
sensor->gain = ST_LPS22DF_TEMP_FS_AVL_GAIN;
|
||||
scnprintf(sensor->name, sizeof(sensor->name),
|
||||
"%s_temp", name);
|
||||
iio_dev->channels = st_lps22df_temp_channels;
|
||||
iio_dev->num_channels =
|
||||
ARRAY_SIZE(st_lps22df_temp_channels);
|
||||
iio_dev->info = &st_lps22df_temp_info;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iio_dev->name = sensor->name;
|
||||
iio_dev->modes = INDIO_DIRECT_MODE;
|
||||
}
|
||||
|
||||
err = st_lps22df_init_sensors(hw);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (irq > 0) {
|
||||
err = st_lps22df_allocate_buffers(hw);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < ST_LPS22DF_SENSORS_NUMB; i++) {
|
||||
err = devm_iio_device_register(dev, hw->iio_devs[i]);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(st_lps22df_common_probe);
|
||||
|
||||
MODULE_DESCRIPTION("STMicroelectronics lps22df driver");
|
||||
MODULE_AUTHOR("Mario Tesi <mario.tesi@st.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
103
drivers/iio/stm/pressure/st_lps22df_i2c.c
Normal file
103
drivers/iio/stm/pressure/st_lps22df_i2c.c
Normal file
@ -0,0 +1,103 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics lps22df i2c driver
|
||||
*
|
||||
* Copyright 2021 STMicroelectronics Inc.
|
||||
*
|
||||
* Mario Tesi <mario.tesi@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include "st_lps22df.h"
|
||||
|
||||
static int st_lps22df_i2c_read(struct device *dev, u8 addr, int len, u8 *data)
|
||||
{
|
||||
struct st_lps22df_hw *hw = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_msg msg[2];
|
||||
int ret;
|
||||
|
||||
if (len >= ST_LPS22DF_RX_MAX_LENGTH)
|
||||
return -ENOMEM;
|
||||
|
||||
msg[0].addr = client->addr;
|
||||
msg[0].flags = client->flags;
|
||||
msg[0].len = 1;
|
||||
msg[0].buf = &addr;
|
||||
|
||||
msg[1].addr = client->addr;
|
||||
msg[1].flags = client->flags | I2C_M_RD;
|
||||
msg[1].len = len;
|
||||
msg[1].buf = hw->tb.rx_buf;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msg, 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
memcpy(data, hw->tb.rx_buf, len * sizeof(u8));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_lps22df_i2c_write(struct device *dev, u8 addr, int len, u8 *data)
|
||||
{
|
||||
struct st_lps22df_hw *hw = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_msg msg;
|
||||
int ret;
|
||||
|
||||
if (len >= ST_LPS22DF_TX_MAX_LENGTH)
|
||||
return -ENOMEM;
|
||||
|
||||
hw->tb.tx_buf[0] = addr;
|
||||
memcpy(&hw->tb.tx_buf[1], data, len);
|
||||
|
||||
msg.addr = client->addr;
|
||||
msg.flags = client->flags;
|
||||
msg.len = len + 1;
|
||||
msg.buf = hw->tb.tx_buf;
|
||||
|
||||
ret = i2c_transfer(client->adapter, &msg, 1);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static const struct st_lps22df_transfer_function st_lps22df_tf_i2c = {
|
||||
.write = st_lps22df_i2c_write,
|
||||
.read = st_lps22df_i2c_read,
|
||||
};
|
||||
|
||||
static int st_lps22df_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
return st_lps22df_common_probe(&client->dev, client->irq, client->name,
|
||||
&st_lps22df_tf_i2c);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id st_lps22df_ids[] = {
|
||||
{ "lps22df" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, st_lps22df_ids);
|
||||
|
||||
static const struct of_device_id st_lps22df_id_table[] = {
|
||||
{ .compatible = "st,lps22df" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_lps22df_id_table);
|
||||
|
||||
static struct i2c_driver st_lps22df_i2c_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "st_lps22df_i2c",
|
||||
.of_match_table = of_match_ptr(st_lps22df_id_table),
|
||||
},
|
||||
.probe = st_lps22df_i2c_probe,
|
||||
.id_table = st_lps22df_ids,
|
||||
};
|
||||
module_i2c_driver(st_lps22df_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("STMicroelectronics lps22df i2c driver");
|
||||
MODULE_AUTHOR("Mario Tesi <mario.tesi@st.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
100
drivers/iio/stm/pressure/st_lps22df_spi.c
Normal file
100
drivers/iio/stm/pressure/st_lps22df_spi.c
Normal file
@ -0,0 +1,100 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics lps22df spi driver
|
||||
*
|
||||
* Copyright 2021 STMicroelectronics Inc.
|
||||
*
|
||||
* Mario Tesi <mario.tesi@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include "st_lps22df.h"
|
||||
|
||||
#define ST_SENSORS_SPI_READ 0x80
|
||||
|
||||
static int st_lps22df_spi_read(struct device *dev, u8 addr, int len, u8 *data)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
struct st_lps22df_hw *hw = spi_get_drvdata(spi);
|
||||
struct spi_transfer xfers[] = {
|
||||
{
|
||||
.tx_buf = hw->tb.tx_buf,
|
||||
.bits_per_word = 8,
|
||||
.len = 1,
|
||||
},
|
||||
{
|
||||
.rx_buf = hw->tb.rx_buf,
|
||||
.bits_per_word = 8,
|
||||
.len = len,
|
||||
}
|
||||
};
|
||||
int err;
|
||||
|
||||
if (len >= ST_LPS22DF_RX_MAX_LENGTH)
|
||||
return -ENOMEM;
|
||||
|
||||
hw->tb.tx_buf[0] = addr | ST_SENSORS_SPI_READ;
|
||||
err = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memcpy(data, hw->tb.rx_buf, len);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int st_lps22df_spi_write(struct device *dev, u8 addr, int len, u8 *data)
|
||||
{
|
||||
struct st_lps22df_hw *hw;
|
||||
struct spi_device *spi;
|
||||
|
||||
if (len >= ST_LPS22DF_TX_MAX_LENGTH)
|
||||
return -ENOMEM;
|
||||
|
||||
spi = to_spi_device(dev);
|
||||
hw = spi_get_drvdata(spi);
|
||||
|
||||
hw->tb.tx_buf[0] = addr;
|
||||
memcpy(&hw->tb.tx_buf[1], data, len);
|
||||
|
||||
return spi_write(spi, hw->tb.tx_buf, len + 1);
|
||||
}
|
||||
|
||||
static const struct st_lps22df_transfer_function st_lps22df_tf_spi = {
|
||||
.write = st_lps22df_spi_write,
|
||||
.read = st_lps22df_spi_read,
|
||||
};
|
||||
|
||||
static int st_lps22df_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
return st_lps22df_common_probe(&spi->dev, spi->irq, spi->modalias,
|
||||
&st_lps22df_tf_spi);
|
||||
}
|
||||
|
||||
static const struct spi_device_id st_lps22df_ids[] = {
|
||||
{ "lps22df" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, st_lps22df_ids);
|
||||
|
||||
static const struct of_device_id st_lps22df_id_table[] = {
|
||||
{ .compatible = "st,lps22df" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_lps22df_id_table);
|
||||
|
||||
static struct spi_driver st_lps22df_spi_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "st_lps22df_spi",
|
||||
.of_match_table = of_match_ptr(st_lps22df_id_table),
|
||||
},
|
||||
.probe = st_lps22df_spi_probe,
|
||||
.id_table = st_lps22df_ids,
|
||||
};
|
||||
module_spi_driver(st_lps22df_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("STMicroelectronics lps22df spi driver");
|
||||
MODULE_AUTHOR("Mario Tesi <mario.tesi@st.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
3
stm_iio_configs/lps22df_defconfig
Normal file
3
stm_iio_configs/lps22df_defconfig
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_ST_LPS22DF_IIO=m
|
||||
CONFIG_ST_LPS22DF_I2C_IIO=m
|
||||
CONFIG_ST_LPS22DF_SPI_IIO=m
|
Loading…
Reference in New Issue
Block a user