aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video/cx18
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx18')
-rw-r--r--drivers/media/video/cx18/cx18-audio.c44
-rw-r--r--drivers/media/video/cx18/cx18-av-firmware.c32
2 files changed, 68 insertions, 8 deletions
diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c
index 7a8ad5963de..35268923911 100644
--- a/drivers/media/video/cx18/cx18-audio.c
+++ b/drivers/media/video/cx18/cx18-audio.c
@@ -26,14 +26,18 @@
#include "cx18-cards.h"
#include "cx18-audio.h"
-#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_AI1_MUX_MASK 0x30
+#define CX18_AI1_MUX_I2S1 0x00
+#define CX18_AI1_MUX_I2S2 0x10
+#define CX18_AI1_MUX_843_I2S 0x20
/* Selects the audio input and output according to the current
settings. */
int cx18_audio_set_io(struct cx18 *cx)
{
const struct cx18_card_audio_input *in;
- u32 val;
+ u32 u, v;
int err;
/* Determine which input to use */
@@ -52,9 +56,37 @@ int cx18_audio_set_io(struct cx18 *cx)
return err;
/* FIXME - this internal mux should be abstracted to a subdev */
- val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30;
- val |= (in->audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
- (in->audio_input << 4);
- cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30);
+ u = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+ v = u & ~CX18_AI1_MUX_MASK;
+ switch (in->audio_input) {
+ case CX18_AV_AUDIO_SERIAL1:
+ v |= CX18_AI1_MUX_I2S1;
+ break;
+ case CX18_AV_AUDIO_SERIAL2:
+ v |= CX18_AI1_MUX_I2S2;
+ break;
+ default:
+ v |= CX18_AI1_MUX_843_I2S;
+ break;
+ }
+ if (v == u) {
+ /* force a toggle of some AI1 MUX control bits */
+ u &= ~CX18_AI1_MUX_MASK;
+ switch (in->audio_input) {
+ case CX18_AV_AUDIO_SERIAL1:
+ u |= CX18_AI1_MUX_843_I2S;
+ break;
+ case CX18_AV_AUDIO_SERIAL2:
+ u |= CX18_AI1_MUX_843_I2S;
+ break;
+ default:
+ u |= CX18_AI1_MUX_I2S1;
+ break;
+ }
+ cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE,
+ u, CX18_AI1_MUX_MASK);
+ }
+ cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+ v, CX18_AI1_MUX_MASK);
return 0;
}
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
index ab99030dc18..b9e8cc5d264 100644
--- a/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -24,7 +24,13 @@
#include "cx18-io.h"
#include <linux/firmware.h>
-#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_AI1_MUX_MASK 0x30
+#define CX18_AI1_MUX_I2S1 0x00
+#define CX18_AI1_MUX_I2S2 0x10
+#define CX18_AI1_MUX_843_I2S 0x20
+#define CX18_AI1_MUX_INVALID 0x30
+
#define FWFILE "v4l-cx23418-dig.fw"
static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw)
@@ -74,7 +80,7 @@ int cx18_av_loadfw(struct cx18 *cx)
struct v4l2_subdev *sd = &cx->av_state.sd;
const struct firmware *fw = NULL;
u32 size;
- u32 v;
+ u32 u, v;
const u8 *ptr;
int i;
int retries1 = 0;
@@ -183,6 +189,28 @@ int cx18_av_loadfw(struct cx18 *cx)
cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
0, 0x400);
+ /* Toggle the AI1 MUX */
+ v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+ u = v & CX18_AI1_MUX_MASK;
+ v &= ~CX18_AI1_MUX_MASK;
+ if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) {
+ /* Switch to I2S1 */
+ v |= CX18_AI1_MUX_I2S1;
+ cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+ v, CX18_AI1_MUX_MASK);
+ /* Switch back to the A/V decoder core I2S output */
+ v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S;
+ } else {
+ /* Switch to the A/V decoder core I2S output */
+ v |= CX18_AI1_MUX_843_I2S;
+ cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+ v, CX18_AI1_MUX_MASK);
+ /* Switch back to I2S1 or I2S2 */
+ v = (v & ~CX18_AI1_MUX_MASK) | u;
+ }
+ cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+ v, CX18_AI1_MUX_MASK);
+
/* Enable WW auto audio standard detection */
v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
v |= 0xFF; /* Auto by default */