On Wed, 03 Aug 2016 18:06:14 +0200, Vinod Koul wrote:
+static int azx_get_sync_time(ktime_t *device,
struct system_counterval_t *system, void *ctx)+{
- struct snd_pcm_substream *substream = (struct snd_pcm_substream *)ctx;
Superfluous cast.
- struct azx_dev *azx_dev = get_azx_dev(substream);
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct azx *chip = apcm->chip;
- struct snd_pcm_runtime *runtime;
- u64 ll_counter, ll_counter_l, ll_counter_h;
- u64 tsc_counter, tsc_counter_l, tsc_counter_h;
- u32 wallclk_ctr, wallclk_cycles;
- bool direction;
- u32 dma_select;
- u32 timeout = 200;
- u32 retry_count = 0;
- runtime = substream->runtime;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
direction = 1;- else
direction = 0;- /* 0th stream tag is not used, so DMA ch 0 is for 1st stream tag */
- do {
timeout = 100;dma_select = (direction << GTSCC_CDMAS_DMA_DIR_SHIFT) |(azx_dev->core.stream_tag - 1);_snd_hdac_chip_write(l, azx_bus(chip), AZX_REG_GTSCC,dma_select);
You can use snd_hdac_chip_writel(azx_bus(chip), GTSCC, dma_select);
The use of _snd_hdac_chip_write() is for non-constant registers. When you pass AZX_REG_XXX, you can use the standard macro. For example:
/* Enable the capture */_snd_hdac_chip_write(l, azx_bus(chip), AZX_REG_GTSCC,_snd_hdac_chip_read(l, azx_bus(chip),AZX_REG_GTSCC) | GTSCC_TSCCI_MASK);
This can be simplified with snd_hdac_chip_updatel().
while (timeout) {if (_snd_hdac_chip_read(l, azx_bus(chip),AZX_REG_GTSCC) & GTSCC_TSCCD_MASK)break;timeout--;}if (!timeout) {dev_err(chip->card->dev, "GTSCC capture Timedout!\n");return -EIO;}/* Read wall clock counter */wallclk_ctr = _snd_hdac_chip_read(l, azx_bus(chip),AZX_REG_WALFCC);/* Read TSC counter */tsc_counter_l = _snd_hdac_chip_read(l, azx_bus(chip),AZX_REG_TSCCL);tsc_counter_h = _snd_hdac_chip_read(l, azx_bus(chip),AZX_REG_TSCCU);/* Read Link counter */ll_counter_l = _snd_hdac_chip_read(l, azx_bus(chip),AZX_REG_LLPCL);ll_counter_h = _snd_hdac_chip_read(l, azx_bus(chip),AZX_REG_LLPCU);/* Ack: registers read done */_snd_hdac_chip_write(l, azx_bus(chip),AZX_REG_GTSCC,(0x1 << GTSCC_TSCCD_SHIFT));tsc_counter = (tsc_counter_h << TSCCU_CCU_SHIFT) |tsc_counter_l;ll_counter = (ll_counter_h << LLPC_CCU_SHIFT) | ll_counter_l;wallclk_cycles = wallclk_ctr & WALFCC_CIF_MASK;/** An error occurs near frame "rollover". The clocks in* frame value indicates whether this error may have* occurred. Here we use the value of 10 i.e.,* HDA_MAX_CYCLE_OFFSET*/if (wallclk_cycles < HDA_MAX_CYCLE_VALUE - HDA_MAX_CYCLE_OFFSET&& wallclk_cycles > HDA_MAX_CYCLE_OFFSET)break;/** Sleep before we read again, else we may again get* value near to MAX_CYCLE. Try to sleep for different* amount of time so we dont hit the same number again*/udelay(retry_count++);- } while (retry_count != HDA_MAX_CYCLE_READ_RETRY);
- if (retry_count == HDA_MAX_CYCLE_READ_RETRY) {
dev_err(chip->card->dev, "Error in WALFCC cycle count\n");
Hrm, this has a danger to spew huge amount of error messages, since this gets called so often.
return -EIO;- }
- *device = ns_to_ktime(azx_scale64(ll_counter,
NSEC_PER_SEC, runtime->rate));- *device = ktime_add_ns(*device, (wallclk_cycles * NSEC_PER_SEC) /
((HDA_MAX_CYCLE_VALUE + 1) * runtime->rate));- *system = convert_art_to_tsc(tsc_counter);
- return 0;
+}
+#else +static int azx_get_sync_time(ktime_t *device,
struct system_counterval_t *system, void *ctx)+{
- return -ENXIO;
+} +#endif
+static int azx_get_crosststamp(struct snd_pcm_substream *substream,
struct system_device_crosststamp *xtstamp)+{
- return get_device_system_crosststamp(azx_get_sync_time,
substream, NULL, xtstamp);+}
static int azx_get_time_info(struct snd_pcm_substream *substream, struct timespec *system_ts, struct timespec *audio_ts, struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_report *audio_tstamp_report) { struct azx_dev *azx_dev = get_azx_dev(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct system_device_crosststamp xtstamp; u64 nsec;
if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) &&
@@ -361,8 +524,38 @@ static int azx_get_time_info(struct snd_pcm_substream *substream, audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */ audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */
- } else
- } else if ((runtime->hw.info &
SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME) &&(audio_tstamp_config->type_requested ==SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED)) {
The indentation is hard to follow here...
azx_get_crosststamp(substream, &xtstamp);
No error check?
thanks,
Takashi
switch (runtime->tstamp_type) {case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC:return -EINVAL;case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW:*system_ts = ktime_to_timespec(xtstamp.sys_monoraw);break;default:*system_ts = ktime_to_timespec(xtstamp.sys_realtime);break;}*audio_ts = ktime_to_timespec(xtstamp.device);audio_tstamp_report->actual_type =SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED;audio_tstamp_report->accuracy_report = 1;/* 24 MHz WallClock == 42ns resolution */audio_tstamp_report->accuracy = 42;} else { audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
}
return 0;
}
1.9.1