Some hardware units capture a timestamp for the counted event. To increase precision add a variant of counter_push_event() that allows passing this timestamp. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx> --- Hello, the difficulty is that the captured timer value is in a unit different from the one provided by ktime_get_ns(). So maybe some helper functions will be needed to convert the local timer value to a ktime timestamp? So usage would be something like: ktime_now = ktime_get_ns(); local_now = readl(CNT); local_event = readl(...); ktime_event = ktime_now - (local_now - local_event) * somefactor >> someshift; counter_push_event_ts(count, event, channel, ktime_event); This improves the precision because irq latency doesn't influence the resulting timestamp. The precision then only depends on the timer resolution and the delay between ktime_get_ns() and readl(CNT); I don't have a driver (yet) that makes use of this, the hardware where this will matter will be stm32mp1. Best regards Uwe drivers/counter/counter-chrdev.c | 25 +++++++++++++++++++++---- include/linux/counter.h | 2 ++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/counter/counter-chrdev.c b/drivers/counter/counter-chrdev.c index b7c62f957a6a..6381f7246d59 100644 --- a/drivers/counter/counter-chrdev.c +++ b/drivers/counter/counter-chrdev.c @@ -521,16 +521,17 @@ static int counter_get_data(struct counter_device *const counter, } /** - * counter_push_event - queue event for userspace reading + * counter_push_event_ts - queue event with a timestamp for userspace reading * @counter: pointer to Counter structure * @event: triggered event * @channel: event channel + * @timestamp: the ktime when the event occurred * * Note: If no one is watching for the respective event, it is silently * discarded. */ -void counter_push_event(struct counter_device *const counter, const u8 event, - const u8 channel) +void counter_push_event_ts(struct counter_device *const counter, const u8 event, + const u8 channel, u64 timestamp) { struct counter_event ev; unsigned int copied = 0; @@ -538,7 +539,7 @@ void counter_push_event(struct counter_device *const counter, const u8 event, struct counter_event_node *event_node; struct counter_comp_node *comp_node; - ev.timestamp = ktime_get_ns(); + ev.timestamp = timestamp; ev.watch.event = event; ev.watch.channel = channel; @@ -570,4 +571,20 @@ void counter_push_event(struct counter_device *const counter, const u8 event, if (copied) wake_up_poll(&counter->events_wait, EPOLLIN); } +EXPORT_SYMBOL_GPL(counter_push_event_ts); + +/** + * counter_push_event - queue event for userspace reading + * @counter: pointer to Counter structure + * @event: triggered event + * @channel: event channel + * + * Note: If no one is watching for the respective event, it is silently + * discarded. + */ +void counter_push_event(struct counter_device *const counter, const u8 event, + const u8 channel) +{ + counter_push_event_ts(counter, event, channel, ktime_get_ns()); +} EXPORT_SYMBOL_GPL(counter_push_event); diff --git a/include/linux/counter.h b/include/linux/counter.h index b7d0a00a61cf..596e7e58e463 100644 --- a/include/linux/counter.h +++ b/include/linux/counter.h @@ -333,6 +333,8 @@ int counter_register(struct counter_device *const counter); void counter_unregister(struct counter_device *const counter); int devm_counter_register(struct device *dev, struct counter_device *const counter); +void counter_push_event_ts(struct counter_device *const counter, const u8 event, + const u8 channel, u64 timestamp) void counter_push_event(struct counter_device *const counter, const u8 event, const u8 channel); -- 2.30.2