Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef8d7656 authored by Puneet Yatnal's avatar Puneet Yatnal Committed by Gerrit - the friendly Code Review server
Browse files

drivers: iio: imu: Fix cpu latency issue for asm330 irq



CPU is taking 500us to 1ms time to come out of deep state of lpm mode to
serve the irq. Due to latency of asm330 IRQ handler, there is drift
b/w the timestamp of data samples. To avoid this changed cpu state
to idle state with timer till IRQ get served.

Change-Id: I31ba873afaae633327de32853b49cce78e9b81ab
Signed-off-by: default avatarPuneet Yatnal <puneet@codeaurora.org>
parent 547c2f50
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -244,6 +244,8 @@ struct st_asm330lhh_hw {
	const struct st_asm330lhh_transfer_function *tf;
	struct st_asm330lhh_transfer_buffer tb;
	int enable_gpio;
	int asm330_hrtimer;
	struct hrtimer st_asm330lhh_hrtimer;
};

extern const struct dev_pm_ops st_asm330lhh_pm_ops;
@@ -294,4 +296,6 @@ int st_asm330lhh_update_watermark(struct st_asm330lhh_sensor *sensor,
int st_asm330lhh_update_fifo(struct iio_dev *iio_dev, bool enable);
int asm330_check_acc_gyro_early_buff_enable_flag(
		struct st_asm330lhh_sensor *sensor);
void st_asm330lhh_set_cpu_idle_state(bool value);
void st_asm330lhh_hrtimer_reset(struct st_asm330lhh_hw *hw, s64 irq_delta_ts);
#endif /* ST_ASM330LHH_H */
+9 −0
Original line number Diff line number Diff line
@@ -66,6 +66,9 @@ static inline int st_asm330lhh_reset_hwts(struct st_asm330lhh_hw *hw)
	hw->hw_ts_high = 0;
	hw->tsample = 0ull;

	if (hw->asm330_hrtimer)
		st_asm330lhh_set_cpu_idle_state(true);

	return hw->tf->write(hw->dev, ST_ASM330LHH_REG_TS2_ADDR, sizeof(data),
			     &data);
}
@@ -475,6 +478,9 @@ static irqreturn_t st_asm330lhh_handler_irq(int irq, void *private)
	hw->delta_ts = ts - hw->ts;
	hw->ts = ts;

	if (hw->asm330_hrtimer)
		st_asm330lhh_hrtimer_reset(hw, hw->delta_ts);

	return IRQ_WAKE_THREAD;
}

@@ -487,6 +493,9 @@ static irqreturn_t st_asm330lhh_handler_thread(int irq, void *private)
	clear_bit(ST_ASM330LHH_HW_FLUSH, &hw->state);
	mutex_unlock(&hw->fifo_lock);

	if (hw->asm330_hrtimer)
		st_asm330lhh_set_cpu_idle_state(false);

	return IRQ_HANDLED;
}

+36 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/version.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/cpu.h>

#include <linux/platform_data/st_sensors_pdata.h>

@@ -192,6 +193,33 @@ static const struct iio_chan_spec st_asm330lhh_temp_channels[] = {
	},
};

void st_asm330lhh_set_cpu_idle_state(bool value)
{
	cpu_idle_poll_ctrl(value);
}
static enum hrtimer_restart st_asm330lhh_timer_function(
		struct hrtimer *timer)
{
	st_asm330lhh_set_cpu_idle_state(true);

	return HRTIMER_NORESTART;
}
void st_asm330lhh_hrtimer_reset(struct st_asm330lhh_hw *hw,
		s64 irq_delta_ts)
{
	hrtimer_cancel(&hw->st_asm330lhh_hrtimer);
	/*forward HRTIMER just before 1ms of irq arrival*/
	hrtimer_forward(&hw->st_asm330lhh_hrtimer, ktime_get(),
			ns_to_ktime(irq_delta_ts - 1000000));
	hrtimer_restart(&hw->st_asm330lhh_hrtimer);
}
static void st_asm330lhh_hrtimer_init(struct st_asm330lhh_hw *hw)
{
	hrtimer_init(&hw->st_asm330lhh_hrtimer, CLOCK_MONOTONIC,
			HRTIMER_MODE_REL);
	hw->st_asm330lhh_hrtimer.function = st_asm330lhh_timer_function;
}

int st_asm330lhh_write_with_mask(struct st_asm330lhh_hw *hw, u8 addr, u8 mask,
				 u8 val)
{
@@ -1101,6 +1129,11 @@ int st_asm330lhh_probe(struct device *dev, int irq,
		msleep(ST_ASM330LHH_TURN_ON_TIME);
	}

	/* use hrtimer if property is enabled */
	if (of_property_read_u32(np, "qcom,asm330_hrtimer",
				&hw->asm330_hrtimer))
		hw->asm330_hrtimer = 0; //force to 0 if not in dt

	dev_info(hw->dev, "Ver: %s\n", ST_ASM330LHH_VERSION);
	err = st_asm330lhh_check_whoami(hw);
	if (err < 0)
@@ -1139,6 +1172,9 @@ int st_asm330lhh_probe(struct device *dev, int irq,
	if (!err)
		return err;

	if (hw->asm330_hrtimer)
		st_asm330lhh_hrtimer_init(hw);

	st_asm330lhh_enable_acc_gyro(hw);

	dev_info(hw->dev, "probe ok\n");