目錄
方法一
裝置樹
代碼修改
方法二
裝置樹
代碼修改
lsm6dsl硬體上沒接中斷管腳,iio驅動修改方法。
方法一
裝置樹
硬體上并未接中斷管腳,裝置樹配置一沒有被使用的GPIO管腳作為中斷管腳。
&i2c2 {
status = "okay";
clock-frequency = <400000>;
lsm6dsl: [email protected] {
status = "okay";
compatible = "st,lsm6dsl";
reg = <0x6b>;
interrupt-parent = <&gpio0>;
interrupts = <30 IRQ_TYPE_EDGE_RISING>;
};
};
否則st_lsm6dsx_fifo_setup不會被調用。不會出現/sys/bus/iio/devices/iio\:device1/buffer目錄。
844 if (hw->irq > 0) {
845 err = st_lsm6dsx_fifo_setup(hw);
846 if (err < 0)
847 return err;
848 }
代碼修改
由于沒有連接配接中斷管腳,增加核心線程來采集資料。
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -161,6 +161,7 @@ struct st_lsm6dsx_hw {
struct iio_dev *iio_devs[ST_LSM6DSX_ID_MAX];
const struct st_lsm6dsx_settings *settings;
+ struct task_struct *task;
};
extern const struct dev_pm_ops st_lsm6dsx_pm_ops;
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -32,6 +32,7 @@
#include <linux/iio/buffer.h>
#include <linux/regmap.h>
#include <linux/bitfield.h>
+#include <linux/kthread.h>
#include <linux/platform_data/st_sensors_pdata.h>
@@ -414,6 +415,23 @@ int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
return err;
}
+static int kthread_read_fifo(void *arg)
+{
+ struct st_lsm6dsx_hw *hw = (struct st_lsm6dsx_hw *)arg;
+ int count;
+
+ while (!kthread_should_stop()) {
+ mutex_lock(&hw->fifo_lock);
+ count = st_lsm6dsx_read_fifo(hw);
+ mutex_unlock(&hw->fifo_lock);
+ if (count <= 0) {
+ schedule_timeout_interruptible(msecs_to_jiffies(10));
+ }
+ }
+
+ return 0;
+}
+
static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
{
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
@@ -457,6 +475,14 @@ static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
goto out;
err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
+ if (!hw->task) {
+ hw->task = kthread_run(kthread_read_fifo, hw, "lsm6dsxd");
+ }
+ } else {
+ if (hw->task) {
+ kthread_stop(hw->task);
+ hw->task = NULL;
+ }
}
out:
方法二
裝置樹
裝置樹不配置中斷管腳。
&i2c2 {
status = "okay";
clock-frequency = <400000>;
lsm6dsl: [email protected] {
status = "okay";
compatible = "st,lsm6dsl";
reg = <0x6b>;
};
};
代碼修改
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -161,6 +161,7 @@ struct st_lsm6dsx_hw {
struct iio_dev *iio_devs[ST_LSM6DSX_ID_MAX];
const struct st_lsm6dsx_settings *settings;
+ struct task_struct *task;
};
extern const struct dev_pm_ops st_lsm6dsx_pm_ops;
@@ -170,6 +171,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor);
int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor);
int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw);
+int st_lsm6dsx_fifo_setup_noirq(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
u16 watermark);
int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw);
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -32,6 +32,7 @@
#include <linux/iio/buffer.h>
#include <linux/regmap.h>
#include <linux/bitfield.h>
+#include <linux/kthread.h>
#include <linux/platform_data/st_sensors_pdata.h>
@@ -414,6 +415,23 @@ int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
return err;
}
+static int kthread_read_fifo(void *arg)
+{
+ struct st_lsm6dsx_hw *hw = (struct st_lsm6dsx_hw *)arg;
+ int count;
+
+ while (!kthread_should_stop()) {
+ mutex_lock(&hw->fifo_lock);
+ count = st_lsm6dsx_read_fifo(hw);
+ mutex_unlock(&hw->fifo_lock);
+ if (count <= 0) {
+ schedule_timeout_interruptible(msecs_to_jiffies(10));
+ }
+ }
+
+ return 0;
+}
+
static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
{
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
@@ -457,6 +475,14 @@ static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
goto out;
err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
+ if ((hw->irq <= 0) && (!hw->task)) {
+ hw->task = kthread_run(kthread_read_fifo, hw, "lsm6dsxd");
+ }
+ } else {
+ if (hw->task) {
+ kthread_stop(hw->task);
+ hw->task = NULL;
+ }
}
out:
@@ -567,3 +593,21 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
return 0;
}
+
+int st_lsm6dsx_fifo_setup_noirq(struct st_lsm6dsx_hw *hw)
+{
+ struct iio_buffer *buffer;
+ int i;
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ buffer = devm_iio_kfifo_allocate(hw->dev);
+ if (!buffer)
+ return -ENOMEM;
+
+ iio_device_attach_buffer(hw->iio_devs[i], buffer);
+ hw->iio_devs[i]->modes |= INDIO_BUFFER_SOFTWARE;
+ hw->iio_devs[i]->setup_ops = &st_lsm6dsx_buffer_ops;
+ }
+
+ return 0;
+}
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -845,6 +845,10 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
err = st_lsm6dsx_fifo_setup(hw);
if (err < 0)
return err;
+ } else {
+ err = st_lsm6dsx_fifo_setup_noirq(hw);
+ if (err < 0)
+ return err;
}
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {