remarkable-linux/drivers/staging/greybus/timesync.h
Bryan O'Donoghue 00fdbae1a9 greybus: timesync: Add gb_timesync_frame_time_to_timespec()
This patch adds gb_timesync_to_timespec_by_svc() and
gb_timesync_to_timespec_by_interface() respectively. These routines will
convert from a given FrameTime to a ktime/timespec within an envelope of
about 17 seconds. The purpose of this routine is to enable reporting of a
FrameTime from a Module such as a Camera Module and to allow the AP to
then convert this timestamp into a Linux-native timestamp such as ktime.
This is useful and required in the v4l layer.

At 19.2MHz the accuracy of this conversion is about .3 femtoseconds per
count, which means at a 1 second offset from the reference the cumulative
error is about 1.59 nanoseconds. 1.59 nanoseconds is still less than 1
clock's worth of error @ 19.2MHz where each clock is 52.0833~ nanoseconds.

We're aiming for a maximum error rate of 30 nanoseconds which means at the
clock rate we are running at, the conversion from a FrameTime to a Linux
ktime/timespec can be plus-or-minus about 17 seconds from the reference
FrameTime/ktime pair before the routine will refuse to convert.

A realistic use-case for this routine is envisaged to be

- Greybus message received
- Some processing takes place - taking milliseconds
- Call into this routine is made
- Actual time between event in Module and conversion in AP < 1 second
- Error rate in conversion at 1.59 nanoseconds is less than 1 clock
  @ 19.2MHz

This routine is not designed to allow for conversions for events with
large gaps between the event time and the current reference time for
conversion. Since FrameTime can be a very large integer we cannot convert
an arbitrarily large FrameTime to ktime, the feeling and objective here is
to make an over-provisioned envelope that in practical terms can never be
exceeded by expected use-cases. To convert longer gaps more work would have
to be done but ultimately some limit needs to be imposed and right now 0.3
femotseconds per clock on MSM8994 is both accurate and generous.

Adds:
- timesync.c::gb_timesync_frame_time_to_timespec_by_svc(
						 struct gb_svc *,
						 u64 frame_time,
                                                 struct timespec *ts)
  - gb_svc is a pointer to a standard greybus SVC data structure
  - frame_time is a system FrameTime.
  - ts is an output parameter which represents the converted FrameTime
    as a CLOCK_MONOTONIC timespec value.
  - Returns 0 on success or a negative number indicating the type of
    error on failure.

- timesync.c::gb_timesync_frame_time_to_timespec_by_interface(
						 struct gb_interface *,
						 u64 frame_time,
                                                 struct timespec *ts)
  - gb_svc is a pointer to a standard greybus Interface data structure
  - frame_time is a system FrameTime.
  - ts is an output parameter which represents the converted FrameTime
    as a CLOCK_MONOTONIC timespec value.
  - Returns 0 on success or a negative number indicating the type of
    error on failure.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Acked-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
2016-06-06 20:50:08 -07:00

46 lines
1.4 KiB
C

/*
* TimeSync API driver.
*
* Copyright 2016 Google Inc.
* Copyright 2016 Linaro Ltd.
*
* Released under the GPLv2 only.
*/
#ifndef __TIMESYNC_H
#define __TIMESYNC_H
struct gb_svc;
struct gb_interface;
struct gb_timesync_svc;
/* Platform */
u64 gb_timesync_platform_get_counter(void);
u32 gb_timesync_platform_get_clock_rate(void);
int gb_timesync_platform_lock_bus(struct gb_timesync_svc *pdata);
void gb_timesync_platform_unlock_bus(void);
int gb_timesync_platform_init(void);
void gb_timesync_platform_exit(void);
/* Core API */
int gb_timesync_interface_add(struct gb_interface *interface);
void gb_timesync_interface_remove(struct gb_interface *interface);
int gb_timesync_svc_add(struct gb_svc *svc);
void gb_timesync_svc_remove(struct gb_svc *svc);
u64 gb_timesync_get_frame_time_by_interface(struct gb_interface *interface);
u64 gb_timesync_get_frame_time_by_svc(struct gb_svc *svc);
int gb_timesync_to_timespec_by_svc(struct gb_svc *svc, u64 frame_time,
struct timespec *ts);
int gb_timesync_to_timespec_by_interface(struct gb_interface *interface,
u64 frame_time, struct timespec *ts);
int gb_timesync_schedule_synchronous(struct gb_interface *intf);
void gb_timesync_schedule_asynchronous(struct gb_interface *intf);
void gb_timesync_irq(struct gb_timesync_svc *timesync_svc);
int gb_timesync_init(void);
void gb_timesync_exit(void);
#endif /* __TIMESYNC_H */