diff options
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r-- | sound/pci/hda/hda_intel.c | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index bcd40ee488e3..7b213d589ef6 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -1889,6 +1889,26 @@ static void azx_timecounter_init(struct snd_pcm_substream *substream, | |||
1889 | tc->cycle_last = last; | 1889 | tc->cycle_last = last; |
1890 | } | 1890 | } |
1891 | 1891 | ||
1892 | static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream, | ||
1893 | u64 nsec) | ||
1894 | { | ||
1895 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
1896 | struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; | ||
1897 | u64 codec_frames, codec_nsecs; | ||
1898 | |||
1899 | if (!hinfo->ops.get_delay) | ||
1900 | return nsec; | ||
1901 | |||
1902 | codec_frames = hinfo->ops.get_delay(hinfo, apcm->codec, substream); | ||
1903 | codec_nsecs = div_u64(codec_frames * 1000000000LL, | ||
1904 | substream->runtime->rate); | ||
1905 | |||
1906 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
1907 | return nsec + codec_nsecs; | ||
1908 | |||
1909 | return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; | ||
1910 | } | ||
1911 | |||
1892 | static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream, | 1912 | static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream, |
1893 | struct timespec *ts) | 1913 | struct timespec *ts) |
1894 | { | 1914 | { |
@@ -1897,6 +1917,7 @@ static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream, | |||
1897 | 1917 | ||
1898 | nsec = timecounter_read(&azx_dev->azx_tc); | 1918 | nsec = timecounter_read(&azx_dev->azx_tc); |
1899 | nsec = div_u64(nsec, 3); /* can be optimized */ | 1919 | nsec = div_u64(nsec, 3); /* can be optimized */ |
1920 | nsec = azx_adjust_codec_delay(substream, nsec); | ||
1900 | 1921 | ||
1901 | *ts = ns_to_timespec(nsec); | 1922 | *ts = ns_to_timespec(nsec); |
1902 | 1923 | ||
@@ -2349,8 +2370,11 @@ static unsigned int azx_get_position(struct azx *chip, | |||
2349 | struct azx_dev *azx_dev, | 2370 | struct azx_dev *azx_dev, |
2350 | bool with_check) | 2371 | bool with_check) |
2351 | { | 2372 | { |
2373 | struct snd_pcm_substream *substream = azx_dev->substream; | ||
2374 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
2352 | unsigned int pos; | 2375 | unsigned int pos; |
2353 | int stream = azx_dev->substream->stream; | 2376 | int stream = substream->stream; |
2377 | struct hda_pcm_stream *hinfo = apcm->hinfo[stream]; | ||
2354 | int delay = 0; | 2378 | int delay = 0; |
2355 | 2379 | ||
2356 | switch (chip->position_fix[stream]) { | 2380 | switch (chip->position_fix[stream]) { |
@@ -2381,7 +2405,7 @@ static unsigned int azx_get_position(struct azx *chip, | |||
2381 | pos = 0; | 2405 | pos = 0; |
2382 | 2406 | ||
2383 | /* calculate runtime delay from LPIB */ | 2407 | /* calculate runtime delay from LPIB */ |
2384 | if (azx_dev->substream->runtime && | 2408 | if (substream->runtime && |
2385 | chip->position_fix[stream] == POS_FIX_POSBUF && | 2409 | chip->position_fix[stream] == POS_FIX_POSBUF && |
2386 | (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { | 2410 | (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { |
2387 | unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB); | 2411 | unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB); |
@@ -2399,9 +2423,16 @@ static unsigned int azx_get_position(struct azx *chip, | |||
2399 | delay = 0; | 2423 | delay = 0; |
2400 | chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; | 2424 | chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; |
2401 | } | 2425 | } |
2402 | azx_dev->substream->runtime->delay = | 2426 | delay = bytes_to_frames(substream->runtime, delay); |
2403 | bytes_to_frames(azx_dev->substream->runtime, delay); | ||
2404 | } | 2427 | } |
2428 | |||
2429 | if (substream->runtime) { | ||
2430 | if (hinfo->ops.get_delay) | ||
2431 | delay += hinfo->ops.get_delay(hinfo, apcm->codec, | ||
2432 | substream); | ||
2433 | substream->runtime->delay = delay; | ||
2434 | } | ||
2435 | |||
2405 | trace_azx_get_position(chip, azx_dev, pos, delay); | 2436 | trace_azx_get_position(chip, azx_dev, pos, delay); |
2406 | return pos; | 2437 | return pos; |
2407 | } | 2438 | } |