return 0;
}
-static int set_ac97_em202_input(struct em28xx *dev)
+struct em28xx_input_table {
+ enum em28xx_amux amux;
+ u8 reg;
+};
+
+static struct em28xx_input_table inputs[] = {
+ { EM28XX_AMUX_VIDEO, AC97_VIDEO_VOL },
+ { EM28XX_AMUX_LINE_IN, AC97_LINEIN_VOL },
+ { EM28XX_AMUX_PHONE, AC97_PHONE_VOL },
+ { EM28XX_AMUX_MIC, AC97_MIC_VOL },
+ { EM28XX_AMUX_CD, AC97_CD_VOL },
+ { EM28XX_AMUX_AUX, AC97_AUX_VOL },
+ { EM28XX_AMUX_PCM_OUT, AC97_PCM_OUT_VOL },
+};
+
+static int set_ac97_input(struct em28xx *dev)
{
- int ret;
- u16 enable = 0x0808; /* 12 dB attenuation Left/Right */
- u16 disable = 0x8808; /* bit 15 - mute volumme */
- u16 video, line;
-
- if (dev->ctl_ainput == EM28XX_AMUX_VIDEO) {
- video = enable;
- line = disable;
- } else {
- video = disable;
- line = enable;
- }
+ int ret, i;
+ enum em28xx_amux amux = dev->ctl_ainput;
- /* Sets em202 AC97 mixer registers */
- ret = em28xx_write_ac97(dev, AC97_VIDEO_VOL, video);
- if (ret < 0)
- return ret;
+ /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that
+ em28xx should point to LINE IN, while AC97 should use VIDEO
+ */
+ if (amux == EM28XX_AMUX_VIDEO2)
+ amux = dev->ctl_ainput;
- ret = em28xx_write_ac97(dev, AC97_LINEIN_VOL, line);
+ /* Mute all entres but the one that were selected */
+ for (i = 0; i < ARRAY_SIZE(inputs); i++) {
+ if (amux == inputs[i].amux)
+ ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808);
+ else
+ ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000);
- return ret;
+ if (ret < 0)
+ em28xx_warn("couldn't setup AC97 register %d\n",
+ inputs[i].reg);
+ }
+ return 0;
}
static int em28xx_set_audio_source(struct em28xx *dev)
u8 input;
if (dev->is_em2800) {
- if (dev->ctl_ainput)
- input = EM2800_AUDIO_SRC_LINE;
- else
+ if (dev->ctl_ainput == EM28XX_AMUX_VIDEO)
input = EM2800_AUDIO_SRC_TUNER;
+ else
+ input = EM2800_AUDIO_SRC_LINE;
ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
if (ret < 0)
switch (dev->audio_mode.ac97) {
case EM28XX_NO_AC97:
break;
- case EM28XX_AC97_OTHER:
- /* We don't know how to handle this chip.
- Let's hope it is close enough to em202 to work
- */
- case EM28XX_AC97_EM202:
- ret = set_ac97_em202_input(dev);
- break;
+ default:
+ ret = set_ac97_input(dev);
}
- return 0;
+ return ret;
}
int em28xx_audio_analog_set(struct em28xx *dev)
if (!dev->audio_mode.has_audio)
return 0;
+ /* It is assumed that all devices use master volume for output.
+ It would be possible to use also line output.
+ */
if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
/* Mute */
ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, 0x8000);
/* Standard AC97 registers */
#define AC97_RESET 0x00
+
+ /* Output volumes */
#define AC97_MASTER_VOL 0x02
-#define AC97_LINE_LEVEL_VOL 0x04
+#define AC97_LINE_LEVEL_VOL 0x04 /* Some devices use for headphones */
#define AC97_MASTER_MONO_VOL 0x06
+ /* Input volumes */
#define AC97_PC_BEEP_VOL 0x0a
#define AC97_PHONE_VOL 0x0c
#define AC97_MIC_VOL 0x0e
#define AC97_VIDEO_VOL 0x14
#define AC97_AUX_VOL 0x16
#define AC97_PCM_OUT_VOL 0x18
+
+ /* capture registers */
#define AC97_RECORD_SELECT 0x1a
#define AC97_RECORD_GAIN 0x1c
+
+ /* control registers */
#define AC97_GENERAL_PURPOSE 0x20
#define AC97_3D_CTRL 0x22
#define AC97_AUD_INT_AND_PAG 0x24
#define AC97_PCM_OUT_SURR_SRATE 0x2e
#define AC97_PCM_OUT_LFE_SRATE 0x30
#define AC97_PCM_IN_SRATE 0x32
+
+ /* For devices with more than 2 channels, extra output volumes */
#define AC97_LFE_MASTER_VOL 0x36
#define AC97_SURR_MASTER_VOL 0x38
+
+ /* Digital SPDIF output control */
#define AC97_SPDIF_OUT_CTRL 0x3a
+ /* Vendor ID identifier */
#define AC97_VENDOR_ID1 0x7c
#define AC97_VENDOR_ID2 0x7e
unsigned int i2s_5rates:1;
};
+/* em28xx has two audio inputs: tuner and line in.
+ However, on most devices, an auxiliary AC97 codec device is used.
+ The AC97 device may have several different inputs and outputs,
+ depending on their model. So, it is possible to use AC97 mixer to
+ address more than two different entries.
+ */
enum em28xx_amux {
- EM28XX_AMUX_VIDEO,
- EM28XX_AMUX_LINE_IN,
+ /* This is the only entry for em28xx tuner input */
+ EM28XX_AMUX_VIDEO, /* em28xx tuner, AC97 mixer Video */
+
+ EM28XX_AMUX_LINE_IN, /* AC97 mixer Line In */
+
+ /* Some less-common mixer setups */
+ EM28XX_AMUX_VIDEO2, /* em28xx Line in, AC97 mixer Video */
+ EM28XX_AMUX_PHONE,
+ EM28XX_AMUX_MIC,
+ EM28XX_AMUX_CD,
+ EM28XX_AMUX_AUX,
+ EM28XX_AMUX_PCM_OUT,
};
struct em28xx_input {