Commit dafcf4ed authored by Gwendal Grignou's avatar Gwendal Grignou Committed by Jonathan Cameron
Browse files

iio: hrtimer: Allow sub Hz granularity



Allow setting frequency below 1Hz or sub 1Hz precision.
Useful for slow sensors like ALS.

Test frequency is set properly:
modprobe iio-trig-hrtimer && \
mkdir /sys/kernel/config/iio/triggers/hrtimer/t1 && \
cd /sys/bus/iio/devices/triggerX ;
for i in 1 .1 .01 .001 ; do
  echo $i > sampling_frequency
  cat sampling_frequency
done

Signed-off-by: default avatarGwendal Grignou <gwendal@chromium.org>
Reviewed-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20210226014733.2108544-1-gwendal@chromium.org


Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent 7b3589f4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -99,3 +99,4 @@ Each trigger can have one or more attributes specific to the trigger type.

"hrtimer" trigger type doesn't have any configurable attribute from /config dir.
It does introduce the sampling_frequency attribute to trigger directory.
That attribute sets the polling frequency in Hz, with mHz precision.
+23 −10
Original line number Diff line number Diff line
@@ -16,13 +16,16 @@
#include <linux/iio/trigger.h>
#include <linux/iio/sw_trigger.h>

/* Defined locally, not in time64.h yet. */
#define PSEC_PER_SEC   1000000000000LL

/* default sampling frequency - 100Hz */
#define HRTIMER_DEFAULT_SAMPLING_FREQUENCY 100

struct iio_hrtimer_info {
	struct iio_sw_trigger swt;
	struct hrtimer timer;
	unsigned long sampling_frequency;
	int sampling_frequency[2];
	ktime_t period;
};

@@ -38,7 +41,9 @@ ssize_t iio_hrtimer_show_sampling_frequency(struct device *dev,
	struct iio_trigger *trig = to_iio_trigger(dev);
	struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig);

	return snprintf(buf, PAGE_SIZE, "%lu\n", info->sampling_frequency);
	return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO,
			ARRAY_SIZE(info->sampling_frequency),
			info->sampling_frequency);
}

static
@@ -48,18 +53,26 @@ ssize_t iio_hrtimer_store_sampling_frequency(struct device *dev,
{
	struct iio_trigger *trig = to_iio_trigger(dev);
	struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig);
	unsigned long val;
	int ret;
	unsigned long long val;
	u64 period;
	int integer, fract, ret;

	ret = kstrtoul(buf, 10, &val);
	ret = iio_str_to_fixpoint(buf, 100, &integer, &fract);
	if (ret)
		return ret;
	if (integer < 0 || fract < 0)
		return -ERANGE;

	val = fract + 1000 * integer;  /* mHz */

	if (!val || val > NSEC_PER_SEC)
	if (!val || val > UINT_MAX)
		return -EINVAL;

	info->sampling_frequency = val;
	info->period = NSEC_PER_SEC / val;
	info->sampling_frequency[0] = integer;  /* Hz */
	info->sampling_frequency[1] = fract * 1000;  /* uHz */
	period = PSEC_PER_SEC;
	do_div(period, val);
	info->period = period;  /* nS */

	return len;
}
@@ -135,8 +148,8 @@ static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name)
	hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
	trig_info->timer.function = iio_hrtimer_trig_handler;

	trig_info->sampling_frequency = HRTIMER_DEFAULT_SAMPLING_FREQUENCY;
	trig_info->period = NSEC_PER_SEC / trig_info->sampling_frequency;
	trig_info->sampling_frequency[0] = HRTIMER_DEFAULT_SAMPLING_FREQUENCY;
	trig_info->period = NSEC_PER_SEC / trig_info->sampling_frequency[0];

	ret = iio_trigger_register(trig_info->swt.trigger);
	if (ret)