diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-core.c | 73 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-reg.h | 14 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 20 |
3 files changed, 74 insertions, 33 deletions
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index b0a238421f2b..1cf5b443092c 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -298,29 +298,44 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val) 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) @@ -329,10 +344,10 @@ 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) @@ -360,16 +375,11 @@ static int em28xx_set_audio_source(struct em28xx *dev) 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) @@ -380,6 +390,9 @@ 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); diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index 12c9132b099e..9727f3828dba 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h @@ -130,10 +130,13 @@ enum em28xx_chip_id { /* 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 @@ -142,8 +145,12 @@ enum em28xx_chip_id { #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 @@ -158,10 +165,15 @@ enum em28xx_chip_id { #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 diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index d965caba63e3..6d04ebf46e7c 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -274,9 +274,25 @@ struct em28xx_audio_mode { 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 { |