ALSA: emu10k1: make available E-MU clock sources card-specific
The actually available clock sources depend on the available audio input ports and dedicated clock input ports. This includes refactoring the code to be data-driven to remain manageable. Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de> Link: https://lore.kernel.org/r/20230612191325.1315854-3-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
1359886227
commit
60985241bf
|
@ -1668,6 +1668,7 @@ struct snd_emu1010 {
|
|||
unsigned char input_source[NUM_INPUT_DESTS];
|
||||
unsigned int adc_pads; /* bit mask */
|
||||
unsigned int dac_pads; /* bit mask */
|
||||
unsigned int wclock; /* Cached register value */
|
||||
unsigned int clock_source;
|
||||
unsigned int clock_fallback;
|
||||
unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
|
||||
|
@ -1824,6 +1825,7 @@ void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
|
|||
void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value);
|
||||
void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src);
|
||||
u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst);
|
||||
void snd_emu1010_update_clock(struct snd_emu10k1 *emu);
|
||||
unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
|
||||
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
|
||||
void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb);
|
||||
|
|
|
@ -905,10 +905,10 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
|
|||
/* Default WCLK set to 48kHz. */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K);
|
||||
/* Word Clock source, Internal 48kHz x1 */
|
||||
emu->emu1010.wclock = EMU_HANA_WCLOCK_INT_48K;
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K);
|
||||
/* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */
|
||||
/* Audio Dock LEDs. */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_LOCK | EMU_HANA_DOCK_LEDS_2_48K);
|
||||
snd_emu1010_update_clock(emu);
|
||||
|
||||
// The routes are all set to EMU_SRC_SILENCE due to the reset,
|
||||
// so it is safe to simply enable the outputs.
|
||||
|
|
|
@ -887,15 +887,79 @@ static const struct snd_emu1010_pads_info emu1010_pads_info[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const char * const emu1010_clock_texts[] = {
|
||||
"44100", "48000", "SPDIF", "ADAT", "Dock", "BNC"
|
||||
};
|
||||
|
||||
static const u8 emu1010_clock_vals[] = {
|
||||
EMU_HANA_WCLOCK_INT_44_1K,
|
||||
EMU_HANA_WCLOCK_INT_48K,
|
||||
EMU_HANA_WCLOCK_HANA_SPDIF_IN,
|
||||
EMU_HANA_WCLOCK_HANA_ADAT_IN,
|
||||
EMU_HANA_WCLOCK_2ND_HANA,
|
||||
EMU_HANA_WCLOCK_SYNC_BNC,
|
||||
};
|
||||
|
||||
static const char * const emu0404_clock_texts[] = {
|
||||
"44100", "48000", "SPDIF", "BNC"
|
||||
};
|
||||
|
||||
static const u8 emu0404_clock_vals[] = {
|
||||
EMU_HANA_WCLOCK_INT_44_1K,
|
||||
EMU_HANA_WCLOCK_INT_48K,
|
||||
EMU_HANA_WCLOCK_HANA_SPDIF_IN,
|
||||
EMU_HANA_WCLOCK_SYNC_BNC,
|
||||
};
|
||||
|
||||
struct snd_emu1010_clock_info {
|
||||
const char * const *texts;
|
||||
const u8 *vals;
|
||||
unsigned num;
|
||||
};
|
||||
|
||||
static const struct snd_emu1010_clock_info emu1010_clock_info[] = {
|
||||
{
|
||||
// rev1 1010
|
||||
.texts = emu1010_clock_texts,
|
||||
.vals = emu1010_clock_vals,
|
||||
.num = ARRAY_SIZE(emu1010_clock_vals),
|
||||
},
|
||||
{
|
||||
// rev2 1010
|
||||
.texts = emu1010_clock_texts,
|
||||
.vals = emu1010_clock_vals,
|
||||
.num = ARRAY_SIZE(emu1010_clock_vals) - 1,
|
||||
},
|
||||
{
|
||||
// 1616(m) CardBus
|
||||
.texts = emu1010_clock_texts,
|
||||
// TODO: determine what is actually available.
|
||||
// Pedantically, *every* source comes from the 2nd FPGA, as the
|
||||
// card itself has no own (digital) audio ports. The user manual
|
||||
// claims that ADAT and S/PDIF clock sources are separate, which
|
||||
// can mean two things: either E-MU mapped the dock's sources to
|
||||
// the primary ones, or they determine the meaning of the "Dock"
|
||||
// source depending on how the ports are actually configured
|
||||
// (which the 2nd FPGA must be doing anyway).
|
||||
.vals = emu1010_clock_vals,
|
||||
.num = ARRAY_SIZE(emu1010_clock_vals),
|
||||
},
|
||||
{
|
||||
// 0404
|
||||
.texts = emu0404_clock_texts,
|
||||
.vals = emu0404_clock_vals,
|
||||
.num = ARRAY_SIZE(emu0404_clock_vals),
|
||||
},
|
||||
};
|
||||
|
||||
static int snd_emu1010_clock_source_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static const char * const texts[4] = {
|
||||
"44100", "48000", "SPDIF", "ADAT"
|
||||
};
|
||||
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
|
||||
const struct snd_emu1010_clock_info *emu_ci =
|
||||
&emu1010_clock_info[emu1010_idx(emu)];
|
||||
|
||||
return snd_ctl_enum_info(uinfo, 1, 4, texts);
|
||||
return snd_ctl_enum_info(uinfo, 1, emu_ci->num, emu_ci->texts);
|
||||
}
|
||||
|
||||
static int snd_emu1010_clock_source_get(struct snd_kcontrol *kcontrol,
|
||||
|
@ -911,84 +975,27 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
|
||||
const struct snd_emu1010_clock_info *emu_ci =
|
||||
&emu1010_clock_info[emu1010_idx(emu)];
|
||||
unsigned int val;
|
||||
int change = 0;
|
||||
|
||||
val = ucontrol->value.enumerated.item[0] ;
|
||||
/* Limit: uinfo->value.enumerated.items = 4; */
|
||||
if (val >= 4)
|
||||
if (val >= emu_ci->num)
|
||||
return -EINVAL;
|
||||
change = (emu->emu1010.clock_source != val);
|
||||
if (change) {
|
||||
emu->emu1010.clock_source = val;
|
||||
switch (val) {
|
||||
case 0:
|
||||
/* 44100 */
|
||||
/* Mute all */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
|
||||
/* Word Clock source, Internal 44.1kHz x1 */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
|
||||
EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
|
||||
/* Set LEDs on Audio Dock */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
|
||||
EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
|
||||
/* Allow DLL to settle */
|
||||
msleep(10);
|
||||
/* Unmute all */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
|
||||
break;
|
||||
case 1:
|
||||
/* 48000 */
|
||||
/* Mute all */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
|
||||
/* Word Clock source, Internal 48kHz x1 */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
|
||||
EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
|
||||
/* Set LEDs on Audio Dock */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
|
||||
EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
|
||||
/* Allow DLL to settle */
|
||||
msleep(10);
|
||||
/* Unmute all */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
|
||||
break;
|
||||
|
||||
case 2: /* Take clock from S/PDIF IN */
|
||||
/* Mute all */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
|
||||
/* Word Clock source, sync to S/PDIF input */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
|
||||
EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
|
||||
/* Set LEDs on Audio Dock */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
|
||||
EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
|
||||
/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
|
||||
/* Allow DLL to settle */
|
||||
msleep(10);
|
||||
/* Unmute all */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
|
||||
break;
|
||||
|
||||
case 3:
|
||||
/* Take clock from ADAT IN */
|
||||
/* Mute all */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
|
||||
/* Word Clock source, sync to ADAT input */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
|
||||
EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
|
||||
/* Set LEDs on Audio Dock */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
|
||||
/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
|
||||
/* Allow DLL to settle */
|
||||
msleep(10);
|
||||
/* Unmute all */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
emu->emu1010.wclock = emu_ci->vals[val];
|
||||
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE);
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, emu->emu1010.wclock);
|
||||
msleep(10); // Allow DLL to settle
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
|
||||
|
||||
snd_emu1010_update_clock(emu);
|
||||
}
|
||||
return change;
|
||||
return change;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new snd_emu1010_clock_source =
|
||||
|
|
|
@ -357,6 +357,29 @@ u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst)
|
|||
return (hi << 8) | lo;
|
||||
}
|
||||
|
||||
void snd_emu1010_update_clock(struct snd_emu10k1 *emu)
|
||||
{
|
||||
u32 leds;
|
||||
|
||||
switch (emu->emu1010.wclock) {
|
||||
case EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X:
|
||||
leds = EMU_HANA_DOCK_LEDS_2_44K;
|
||||
break;
|
||||
case EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X:
|
||||
leds = EMU_HANA_DOCK_LEDS_2_48K;
|
||||
break;
|
||||
default:
|
||||
leds = EMU_HANA_DOCK_LEDS_2_EXT;
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME: this should probably represent the AND of all currently
|
||||
// used sources' lock status. But we don't know how to get that ...
|
||||
leds |= EMU_HANA_DOCK_LEDS_2_LOCK;
|
||||
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, leds);
|
||||
}
|
||||
|
||||
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
|
Loading…
Reference in New Issue