From ce968e7da1f53239809f409ba6092b0269d44d54 Mon Sep 17 00:00:00 2001 From: Marcin Bukat Date: Mon, 5 Oct 2026 22:30:01 +0200 Subject: [PATCH] rk27xx: don't reprogram the codec PLL for an unchanged rate Every start of recording applies the sample rate again, mostly unchanged, and set_codec_freq() reprogrammed the codec PLL each time. That glitches MCLK and every I2S clock made of it, right before the recording receiver is reset and starts on them. Whether it then kept its framing came down to code timing: on the Samsung YP-CP3 the recording screen's peak meter showed one channel empty and the other saturated on some visits, and builds with debug code added never did. The PLL is now left alone when it already runs the rate asked for. On a real change the lock bit, which may still show the old lock at first, is polled only after the 0.3 ms the datasheet gives for locking, with a timeout of at least a full tick, and the clocks get 1 ms more to settle before anything starts on them. Tested on a YP-CP3, together with the codec as I2S master: the peak meter on every one of many visits to the recording screen, with the microphone and FM, and at 22 kHz. Co-Authored-By: Claude Opus 5.5 Change-Id: I2267e17c5bc7d8044715e762dbb6b92f45af4dcc --- firmware/target/arm/rk27xx/pcm-rk27xx.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/firmware/target/arm/rk27xx/pcm-rk27xx.c b/firmware/target/arm/rk27xx/pcm-rk27xx.c index f37eb194b0..2aa5979ce8 100644 --- a/firmware/target/arm/rk27xx/pcm-rk27xx.c +++ b/firmware/target/arm/rk27xx/pcm-rk27xx.c @@ -207,8 +207,17 @@ static void i2s_init(void) */ static void set_codec_freq(unsigned int freq) { + static unsigned int cur_freq = HW_NUM_FREQ; /* none yet */ long timeout; + /* Reprogramming the PLL glitches MCLK, and with it every clock the + * codec makes of it: an I2S side started on them can lose its framing. + * The rate is applied again on every start of recording, mostly + * unchanged. */ + if (freq == cur_freq) + return; + cur_freq = freq; + /* {CLKR, CLKF, CLKOD, CODECPLL_DIV} */ static const unsigned int pcm_freq_params[HW_NUM_FREQ][4] = { @@ -237,13 +246,18 @@ static void set_codec_freq(unsigned int freq) (pcm_freq_params[freq][2]<<1) ; /* CLKOD factor */ /* wait for CODEC PLL lock with 10 ms timeout - * datasheet states that pll lock should take approx. 0.3 ms + * datasheet states that pll lock should take approx. 0.3 ms; the lock bit + * may still show the old lock at first */ - timeout = current_tick + (HZ/100); + udelay(300); + timeout = current_tick + (HZ/100) + 1; while (!(SCU_STATUS & (1<<2))) if (TIME_AFTER(current_tick, timeout)) break; + /* let the codec's clocks settle before an I2S side starts on them */ + udelay(1000); + } #endif