mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
iio: imu: st_lsm6dsx: introduce sw trigger support
There are some hw configuration where irq0 and/or irq1 pins are not connected to the SPI or I2C/I3C controller. In order to avoid polling the output register introduce iio-sw trigger support when irq line is not available (or hw FIFO is not supported). Suggested-by: Mario Tesi <mario.tesi@st.com> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> Link: https://lore.kernel.org/r/93ae6ff1150b531a9d7a4d3d1b1adb8383613717.1666955685.git.lorenzo@kernel.org Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
ea4b79e98a
commit
2cfb2180c3
3 changed files with 81 additions and 4 deletions
|
@ -424,7 +424,7 @@ struct st_lsm6dsx_hw {
|
|||
struct {
|
||||
__le16 channels[3];
|
||||
s64 ts __aligned(8);
|
||||
} scan[3];
|
||||
} scan[ST_LSM6DSX_ID_MAX];
|
||||
};
|
||||
|
||||
static __maybe_unused const struct iio_event_spec st_lsm6dsx_event = {
|
||||
|
@ -456,6 +456,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw);
|
|||
int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val);
|
||||
int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name);
|
||||
int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable);
|
||||
int st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data, int len);
|
||||
int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable);
|
||||
|
||||
static inline int
|
||||
|
|
|
@ -53,6 +53,8 @@
|
|||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/minmax.h>
|
||||
|
@ -2117,6 +2119,32 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
|
|||
return fifo_len || event ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static irqreturn_t st_lsm6dsx_sw_trigger_handler_thread(int irq,
|
||||
void *private)
|
||||
{
|
||||
struct iio_poll_func *pf = private;
|
||||
struct iio_dev *iio_dev = pf->indio_dev;
|
||||
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
|
||||
struct st_lsm6dsx_hw *hw = sensor->hw;
|
||||
|
||||
if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
|
||||
sensor->id == ST_LSM6DSX_ID_EXT1 ||
|
||||
sensor->id == ST_LSM6DSX_ID_EXT2)
|
||||
st_lsm6dsx_shub_read_output(hw,
|
||||
(u8 *)hw->scan[sensor->id].channels,
|
||||
sizeof(hw->scan[sensor->id].channels));
|
||||
else
|
||||
st_lsm6dsx_read_locked(hw, iio_dev->channels[0].address,
|
||||
hw->scan[sensor->id].channels,
|
||||
sizeof(hw->scan[sensor->id].channels));
|
||||
|
||||
iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan[sensor->id],
|
||||
iio_get_time_ns(iio_dev));
|
||||
iio_trigger_notify_done(iio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
|
||||
{
|
||||
struct st_sensors_platform_data *pdata;
|
||||
|
@ -2175,6 +2203,46 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_sw_buffer_preenable(struct iio_dev *iio_dev)
|
||||
{
|
||||
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
|
||||
|
||||
return st_lsm6dsx_device_set_enable(sensor, true);
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_sw_buffer_postdisable(struct iio_dev *iio_dev)
|
||||
{
|
||||
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
|
||||
|
||||
return st_lsm6dsx_device_set_enable(sensor, false);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops st_lsm6dsx_sw_buffer_ops = {
|
||||
.preenable = st_lsm6dsx_sw_buffer_preenable,
|
||||
.postdisable = st_lsm6dsx_sw_buffer_postdisable,
|
||||
};
|
||||
|
||||
static int st_lsm6dsx_sw_buffers_setup(struct st_lsm6dsx_hw *hw)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
|
||||
int err;
|
||||
|
||||
if (!hw->iio_devs[i])
|
||||
continue;
|
||||
|
||||
err = devm_iio_triggered_buffer_setup(hw->dev,
|
||||
hw->iio_devs[i], NULL,
|
||||
st_lsm6dsx_sw_trigger_handler_thread,
|
||||
&st_lsm6dsx_sw_buffer_ops);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_init_regulators(struct device *dev)
|
||||
{
|
||||
/* vdd-vddio power regulators */
|
||||
|
@ -2255,6 +2323,16 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!hw->irq || !hw->settings->fifo_ops.read_fifo) {
|
||||
/*
|
||||
* Rely on sw triggers (e.g. hr-timers) if irq pin is not
|
||||
* connected of if the device does not support HW FIFO
|
||||
*/
|
||||
err = st_lsm6dsx_sw_buffers_setup(hw);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = iio_read_mount_matrix(hw->dev, &hw->orientation);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -170,9 +170,7 @@ static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw)
|
|||
*
|
||||
* Read st_lsm6dsx i2c controller register
|
||||
*/
|
||||
static int
|
||||
st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data,
|
||||
int len)
|
||||
int st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data, int len)
|
||||
{
|
||||
const struct st_lsm6dsx_shub_settings *hub_settings;
|
||||
int err;
|
||||
|
|
Loading…
Reference in a new issue