YP-CP3: Si4703 FM radio

The YP-CP3's tuner is a Silicon Labs Si470x at I2C address 0x20, an
Si4703 by the RDS the original firmware enables. The firmware drives it
the Si470x way - writes from register 2, reads from 0x0A - starts its
oscillator with TEST1 = 0x8100 and a 500 ms wait before ENABLE, and has
no power or reset line for it.

- config: CONFIG_TUNER SI4700 with RDS, polled (no interrupt line
  needed), and FM radio as an input source
- si4700.c: the YP-CP3 starts the oscillator as the Sansas do
- power-ypcp3.c: tuner power stubs - there is nothing to switch
- the rk27xx tuner I2C glue, and "radio" in the target's configure entry
- wm8751.c: audiohw_set_monitor() for a WM8750 target that plays the
  radio but cannot record (rk27xx has no recording yet). The tuner, on
  LINPUT1/RINPUT1, goes through the input PGA at +12 dB - as in the
  original firmware - into the output mixers, the DAC staying in the mix.
  The existing monitor routing lives in the recording code and switches
  OUT2 off, which is the YP-CP3's headphone output.

Tested on a YP-CP3: stations tune and play at a sane level.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ic097fc85dbd7fb71fcc28c97a9d378fa09599e79
This commit is contained in:
Marcin Bukat 2026-09-25 15:43:35 +02:00
parent a35f344eef
commit c922ef98c3
6 changed files with 66 additions and 2 deletions

View file

@ -1739,6 +1739,9 @@ target/arm/rk27xx/ypcp3/lcd-ypcp3.c
#ifndef BOOTLOADER
target/arm/rk27xx/ypcp3/wmcodec-ypcp3.c
#endif
#if CONFIG_TUNER
target/arm/rk27xx/rk27generic/fmradio-i2c-rk27generic.c
#endif
#endif
#if CONFIG_CPU == JZ4732

View file

@ -427,6 +427,43 @@ void audiohw_set_depth_3d(int val)
}
#endif
#if defined(HAVE_WM8750) && defined(HAVE_FMRADIO_IN) && !defined(HAVE_RECORDING)
/* The FM tuner, on LINPUT1/RINPUT1, played through the analog bypass into
* the output mixers - for a target that plays the radio but cannot record
* it. As on the YP-CP3's original firmware, the signal goes through the
* input PGA at +12 dB, which the tuner's low line level needs. The DAC
* stays in the mix. */
void audiohw_set_monitor(bool enable)
{
if (enable)
{
wmcodec_set_masked(ADCL, ADCL_LINSEL_LINPUT1, ADCL_LINSEL_MASK);
wmcodec_set_masked(ADCR, ADCR_RINSEL_RINPUT1, ADCR_RINSEL_MASK);
wmcodec_set_reg(LINVOL, LINVOL_LIZC | LINVOL_LINVOL(0x27));
wmcodec_set_reg(RINVOL, RINVOL_RIVU | RINVOL_RIZC |
RINVOL_RINVOL(0x27));
wmcodec_set_bits(PWRMGMT1, PWRMGMT1_AINL | PWRMGMT1_AINR);
wmcodec_set_masked(LEFTMIX1, LEFTMIX1_LMIXSEL_ADCLIN |
LEFTMIX1_LI2LOVOL(0x20),
0x7 | LEFTMIX1_LI2LOVOL_MASK);
wmcodec_set_bits(LEFTMIX1, LEFTMIX1_LI2LO);
wmcodec_set_masked(RIGHTMIX1, RIGHTMIX1_RMIXSEL_ADCRIN, 0x7);
wmcodec_set_masked(RIGHTMIX2, RIGHTMIX2_RI2ROVOL(0x20),
RIGHTMIX2_RI2ROVOL_MASK);
wmcodec_set_bits(RIGHTMIX2, RIGHTMIX2_RI2RO);
}
else
{
wmcodec_clear_bits(LEFTMIX1, LEFTMIX1_LI2LO);
wmcodec_clear_bits(RIGHTMIX2, RIGHTMIX2_RI2RO);
wmcodec_set_bits(LINVOL, LINVOL_LINMUTE);
wmcodec_set_bits(RINVOL, RINVOL_RIVU | RINVOL_RINMUTE);
wmcodec_clear_bits(PWRMGMT1, PWRMGMT1_AINL | PWRMGMT1_AINR);
}
}
#endif
#ifdef HAVE_RECORDING
#if 0
static void audiohw_set_ngat(int ngath, int type, bool enable)

View file

@ -34,7 +34,7 @@
#include "backlight.h"
#if defined(SANSA_CLIP) || defined(SANSA_E200V2) || defined(SANSA_FUZE) || defined(SANSA_C200V2) \
|| defined(SANSA_FUZEPLUS)
|| defined(SANSA_FUZEPLUS) || defined(SAMSUNG_YPCP3)
/* some models use the internal 32 kHz oscillator which needs special attention
during initialisation, power-up and power-down. */
#define SI4700_USE_INTERNAL_OSCILLATOR

View file

@ -108,6 +108,15 @@
* original firmware */
#define CONFIG_RTC RTC_S35390A
/* Silicon Labs Si4703 FM tuner on I2C, with RDS. It has no power control -
* the original firmware has none either - and its audio reaches the codec
* on LINPUT1/RINPUT1. RDS is polled, which needs no interrupt line. */
#define CONFIG_TUNER SI4700
#define HAVE_RDS_CAP
#define CONFIG_RDS (RDS_CFG_POLL | RDS_CFG_PROCESS)
#define CONFIG_RDS_POLL_TICKS 4
#define INPUT_SRC_CAPS SRC_CAP_FMRADIO
/* Define this for LCD backlight available */
#define HAVE_BACKLIGHT
#define HAVE_BACKLIGHT_BRIGHTNESS

View file

@ -44,6 +44,21 @@ void power_off(void)
}
}
#if CONFIG_TUNER
/* The tuner has no power switch; the original firmware does not switch it
* either, it only puts the chip to sleep over I2C. */
bool tuner_power(bool status)
{
(void)status;
return true;
}
bool tuner_powered(void)
{
return true;
}
#endif
unsigned int power_input_status(void)
{
return (usb_detect() == USB_INSERTED) ? POWER_INPUT_MAIN_CHARGER : POWER_INPUT_NONE;

2
tools/configure vendored
View file

@ -3050,7 +3050,7 @@ fi
bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
output="rockbox.rkw"
bootoutput="bootloader.rkw"
appextra="recorder:gui"
appextra="recorder:gui:radio"
plugins=""
# toolset is the tools within the tools directory that we build for
# this particular target.