From 19caf2756756c9cf35484dc30afb94c594548c42 Mon Sep 17 00:00:00 2001 From: Marcin Bukat Date: Wed, 30 Sep 2026 07:57:50 +0200 Subject: [PATCH] rk27xx codec: mix in only the tuner's line, keep the DAC audiohw_set_monitor() switched the output mixer from the DAC to both line bypasses: voice and beeps went silent while the radio played, and a line nobody listened to was mixed in, with its noise. Both line inputs were also powered from start-up on. - the target names the line its tuner is on, RK27XX_CODEC_FM_LINE (1 or 2); both are used where it does not say - monitoring adds that line's bypass to the DAC instead of replacing it - the line inputs stay in standby until monitored, and go back after Only rk27generic uses the internal codec - the other rk27xx targets have external DACs or codecs. Tested on rk27generic: the radio plays through the monitored line, key clicks stay audible over it, and playback is unaffected. Co-Authored-By: Claude Opus 5.5 Change-Id: I177fdf605e4d997159898c868b2186c9584eb19a --- firmware/drivers/audio/rk27xx_codec.c | 40 +++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/firmware/drivers/audio/rk27xx_codec.c b/firmware/drivers/audio/rk27xx_codec.c index 4357a4c356..3b06d2ba40 100644 --- a/firmware/drivers/audio/rk27xx_codec.c +++ b/firmware/drivers/audio/rk27xx_codec.c @@ -39,8 +39,28 @@ static int codec_read(uint8_t reg, uint8_t *val) } #endif +/* The line input the FM tuner is wired to: RK27XX_CODEC_FM_LINE, 1 or 2, + * from the target config; both when the target does not say. Only the + * tuner's line is bypassed to the output mixer and powered, and only while + * it is being listened to. */ +#if defined(RK27XX_CODEC_FM_LINE) && RK27XX_CODEC_FM_LINE == 1 +#define FM_BYPASS BYPASS1 +#define FM_IN_SB SB_IN1 +#elif defined(RK27XX_CODEC_FM_LINE) && RK27XX_CODEC_FM_LINE == 2 +#define FM_BYPASS BYPASS2 +#define FM_IN_SB SB_IN2 +#else +#define FM_BYPASS (BYPASS1|BYPASS2) +#define FM_IN_SB (SB_IN1|SB_IN2) +#endif + +/* what feeds the output mixer: the DAC, and the tuner's line while the + * radio plays - the DAC stays in the mix, for voice and beeps */ static uint8_t cr1_sel = DACSEL; +/* power: the line inputs in standby unless monitored */ +static uint8_t pmr1 = SB_ADC|SB_MIC|SB_IND|SB_IN1|SB_IN2; + static void audiohw_mute(bool mute) { if (mute) @@ -95,7 +115,7 @@ void audiohw_postinit(void) udelay(1000); /* power up output stage */ - codec_write(PMR1, SB_ADC|SB_MIC|SB_IND); + codec_write(PMR1, pmr1); sleep(HZ/10); GPIO_PDDR |= (1<<7); /* PD7 high */ @@ -152,6 +172,20 @@ void audiohw_set_volume(int vol_l, int vol_r) void audiohw_set_monitor(bool enable) { - cr1_sel = enable ? BYPASS1|BYPASS2 : DACSEL; - codec_write(CR1, cr1_sel|SB_MICBIAS); + if (enable) + { + /* input up before it is mixed in */ + pmr1 &= ~FM_IN_SB; + codec_write(PMR1, pmr1); + cr1_sel = DACSEL|FM_BYPASS; + codec_write(CR1, cr1_sel|SB_MICBIAS); + } + else + { + /* out of the mix before the input goes down */ + cr1_sel = DACSEL; + codec_write(CR1, cr1_sel|SB_MICBIAS); + pmr1 |= FM_IN_SB; + codec_write(PMR1, pmr1); + } }