us144mkii_playback: clamp feedback PLL to prevent DAC underflow noise
Ignore transient bad device feedback that would drive freq_q16 to zero or an unrealistic value, and clamp freq_q16 within 75%%-125%% of nominal. Also force a minimal nominal packet if a zero-length playback URB is produced, preventing the device DAC from underflowing and outputting persistent noise.
This commit is contained in:
parent
32986d7934
commit
db1de1f9c1
|
|
@ -256,6 +256,22 @@ void playback_urb_complete(struct urb *urb)
|
||||||
}
|
}
|
||||||
urb->transfer_buffer_length = total_bytes;
|
urb->transfer_buffer_length = total_bytes;
|
||||||
|
|
||||||
|
/* A stuck PLL can produce all-zero-length packets, which makes the
|
||||||
|
* device underflow and output persistent noise. Force a minimal
|
||||||
|
* nominal packet if that happens.
|
||||||
|
*/
|
||||||
|
if (total_bytes == 0) {
|
||||||
|
tascam->freq_q16 = div_u64(((u64)tascam->current_rate << 16), 8000);
|
||||||
|
tascam->phase_accum = 0;
|
||||||
|
frames = min((u32)(tascam->current_rate / 8000), (u32)MAX_FRAMES_PER_PACKET);
|
||||||
|
if (frames == 0)
|
||||||
|
frames = 1;
|
||||||
|
urb->iso_frame_desc[0].offset = 0;
|
||||||
|
urb->iso_frame_desc[0].length = frames * PLAYBACK_FRAME_SIZE;
|
||||||
|
total_bytes = urb->iso_frame_desc[0].length;
|
||||||
|
urb->transfer_buffer_length = total_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
/* Ghost Playback: Send Silence */
|
/* Ghost Playback: Send Silence */
|
||||||
if (!atomic_read(&tascam->playback_active)) {
|
if (!atomic_read(&tascam->playback_active)) {
|
||||||
if (tascam->running_ghost_playback) {
|
if (tascam->running_ghost_playback) {
|
||||||
|
|
@ -342,9 +358,22 @@ void feedback_urb_complete(struct urb *urb)
|
||||||
u8 *d = urb->transfer_buffer + urb->iso_frame_desc[p].offset;
|
u8 *d = urb->transfer_buffer + urb->iso_frame_desc[p].offset;
|
||||||
u32 val = (urb->iso_frame_desc[p].actual_length >= 3) ? (d[0] + d[1] + d[2]) : (d[0] * 3);
|
u32 val = (urb->iso_frame_desc[p].actual_length >= 3) ? (d[0] + d[1] + d[2]) : (d[0] * 3);
|
||||||
u32 target = (val << 16) / 24;
|
u32 target = (val << 16) / 24;
|
||||||
tascam->freq_q16 = (tascam->freq_q16 * PLL_FILTER_OLD_WEIGHT +
|
u32 nominal = div_u64(((u64)tascam->current_rate << 16), 8000);
|
||||||
target * PLL_FILTER_NEW_WEIGHT) / PLL_FILTER_DIVISOR;
|
u32 min_freq = nominal - (nominal >> 2);
|
||||||
tascam->feedback_synced = true;
|
u32 max_freq = nominal + (nominal >> 2);
|
||||||
|
|
||||||
|
/* Ignore transient bad feedback that would drive the PLL to
|
||||||
|
* zero or an unrealistic value and cause DAC underflow noise.
|
||||||
|
*/
|
||||||
|
if (tascam->current_rate > 0 && target >= min_freq && target <= max_freq) {
|
||||||
|
tascam->freq_q16 = (tascam->freq_q16 * PLL_FILTER_OLD_WEIGHT +
|
||||||
|
target * PLL_FILTER_NEW_WEIGHT) / PLL_FILTER_DIVISOR;
|
||||||
|
if (tascam->freq_q16 < min_freq)
|
||||||
|
tascam->freq_q16 = min_freq;
|
||||||
|
else if (tascam->freq_q16 > max_freq)
|
||||||
|
tascam->freq_q16 = max_freq;
|
||||||
|
tascam->feedback_synced = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue