[alsa-devel] [PATCH v2 3/3] ALSA: hda: support for wallclock timestamps
Takashi Iwai
tiwai at suse.de
Tue Oct 9 11:40:25 CEST 2012
At Mon, 8 Oct 2012 12:11:58 -0500,
Pierre-Louis Bossart wrote:
>
> Reuse code from clocksource to handle wall clock counter.
> Since wrapparound occurs, the audio timestamp is reinitialized
> to zero on a trigger. Synchronized linked devices will
> start counting from same reference to avoid any drift.
>
> Max buffer time is limited to 178 seconds to make sure
> wall clock counter does not overflow
>
> Wallclock timestamps are disabled on capture streams
> until we figure out how to handle digital inputs.
>
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
> ---
> sound/pci/hda/hda_intel.c | 95 +++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 95 insertions(+)
>
> diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
> index b682442..0245382 100644
> --- a/sound/pci/hda/hda_intel.c
> +++ b/sound/pci/hda/hda_intel.c
> @@ -46,6 +46,10 @@
> #include <linux/mutex.h>
> #include <linux/reboot.h>
> #include <linux/io.h>
> +
> +#include <linux/clocksource.h>
> +#include <linux/time.h>
> +
> #ifdef CONFIG_X86
> /* for snoop control */
> #include <asm/pgtable.h>
> @@ -406,6 +410,9 @@ struct azx_dev {
> */
> unsigned int insufficient :1;
> unsigned int wc_marked:1;
> +
> + struct timecounter azx_tc;
> + struct cyclecounter azx_cc;
> };
>
> /* CORB/RIRB */
> @@ -1703,6 +1710,64 @@ static inline void azx_release_device(struct azx_dev *azx_dev)
> azx_dev->opened = 0;
> }
>
> +static cycle_t azx_cc_read(const struct cyclecounter *cc)
> +{
> + struct azx_dev *azx_dev = container_of(cc, struct azx_dev, azx_cc);
> + struct snd_pcm_substream *substream = azx_dev->substream;
> + struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
> + struct azx *chip = apcm->chip;
> +
> + return azx_readl(chip, WALLCLK);
> +}
> +
> +static void azx_timecounter_init(struct snd_pcm_substream *substream,
> + bool force, cycle_t last)
> +{
> + struct azx_dev *azx_dev = get_azx_dev(substream);
> + struct timecounter *tc = &azx_dev->azx_tc;
> + struct cyclecounter *cc = &azx_dev->azx_cc;
> + u64 nsec;
> +
> + cc->read = azx_cc_read;
> + cc->mask = CLOCKSOURCE_MASK(32);
> +
> + /*
> + * Converting from 24 MHz to ns means applying a 125/3 factor.
> + * To avoid any saturation issues in intermediate operations,
> + * the 125 factor is applied first. The division is applied
> + * last after reading the timecounter value.
> + * Applying the 1/3 factor as part of the multiplication
> + * requires at least 20 bits for a decent precision, however
> + * overflows occur after about 4 hours or less, not a option.
> + */
> +
> + cc->mult = 125; /* saturation after 195 years */
> + cc->shift = 0;
> +
> + nsec = 0; /* audio time is elapsed time since trigger */
> + timecounter_init(tc, cc, nsec);
> + if (force)
> + /*
> + * force timecounter to use predefined value,
> + * used for synchronized starts
> + */
> + tc->cycle_last = last;
> +}
> +
> +static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream,
> + struct timespec *ts)
> +{
> + struct azx_dev *azx_dev = get_azx_dev(substream);
> + u64 nsec;
> +
> + nsec = timecounter_read(&azx_dev->azx_tc);
> + nsec /= 3; /* can be optimized */
Use div_u64() instead.
Takashi
More information about the Alsa-devel
mailing list