V4L/DVB (6947): Improve audio setup handling

It is possible to select audio inputs via em28xx or via ac97 functions.
This patch allows configuring a board to use either one way.

It also do some cleanups at audio setup configurations.

Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index d56484f..70c5ec2 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -252,7 +252,7 @@
  * em28xx_write_ac97()
  * write a 16 bit value to the specified AC97 address (LSB first!)
  */
-int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
+static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
 {
 	int ret;
 	u8 addr = reg & 0x7f;
@@ -268,16 +268,91 @@
 	return 0;
 }
 
-int em28xx_audio_analog_set(struct em28xx *dev)
+int em28xx_set_audio_source(struct em28xx *dev)
 {
-	char s[2] = { 0x00, 0x00 };
-	s[0] |= 0x1f - dev->volume;
-	s[1] |= 0x1f - dev->volume;
-	if (dev->mute)
-		s[1] |= 0x80;
-	return em28xx_write_ac97(dev, MASTER_AC97, s);
+	static char *enable  = "\x08\x08";
+	static char *disable = "\x08\x88";
+	char *video = enable, *line = disable;
+	int ret, no_ac97;
+	u8 input;
+
+	if (dev->is_em2800) {
+		if (dev->ctl_ainput)
+			input = EM2800_AUDIO_SRC_LINE;
+		else
+			input = EM2800_AUDIO_SRC_TUNER;
+
+		ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (dev->has_msp34xx)
+		input = EM28XX_AUDIO_SRC_TUNER;
+	else {
+		switch (dev->ctl_ainput) {
+		case EM28XX_AMUX_VIDEO:
+			input = EM28XX_AUDIO_SRC_TUNER;
+			no_ac97 = 1;
+			break;
+		case EM28XX_AMUX_LINE_IN:
+			input = EM28XX_AUDIO_SRC_LINE;
+			no_ac97 = 1;
+			break;
+		case EM28XX_AMUX_AC97_VIDEO:
+			input = EM28XX_AUDIO_SRC_LINE;
+			break;
+		case EM28XX_AMUX_AC97_LINE_IN:
+			input = EM28XX_AUDIO_SRC_LINE;
+			video = disable;
+			line  = enable;
+			break;
+		}
+	}
+
+	ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+	if (ret < 0)
+		return ret;
+
+	if (no_ac97)
+		return 0;
+
+	/* Sets AC97 mixer registers */
+
+	ret = em28xx_write_ac97(dev, VIDEO_AC97, video);
+	if (ret < 0)
+		return ret;
+
+	ret = em28xx_write_ac97(dev, LINE_IN_AC97, line);
+
+	return ret;
 }
 
+int em28xx_audio_analog_set(struct em28xx *dev)
+{
+	int ret;
+	char s[2] = { 0x00, 0x00 };
+
+	s[0] |= 0x1f - dev->volume;
+	s[1] |= 0x1f - dev->volume;
+
+	if (dev->mute)
+		s[1] |= 0x80;
+	ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+	if (ret < 0)
+		return ret;
+
+	ret = em28xx_write_reg_bits(dev, XCLK_REG,
+				    dev->mute ? 0x00 : 0x80, 0x80);
+	if (ret < 0)
+		return ret;
+
+	/* Selects the proper audio input */
+	ret = em28xx_set_audio_source(dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
 
 int em28xx_colorlevels_set_default(struct em28xx *dev)
 {
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index c2901f1..1a284cb 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -122,11 +122,13 @@
 /*	em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
 	em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
 
-	em28xx_audio_usb_mute(dev, 1);
 	dev->mute = 1;		/* maybe not the right place... */
 	dev->volume = 0x1f;
+
+	/* Init XCLK_REG, audio muted */
+	dev->em28xx_write_regs(dev, XCLK_REG, "\x87", 1);
+
 	em28xx_audio_analog_set(dev);
-	em28xx_audio_analog_setup(dev);
 	em28xx_outfmt_set_yuv422(dev);
 	em28xx_colorlevels_set_default(dev);
 	em28xx_compression_disable(dev);
@@ -168,7 +170,6 @@
 
 static void video_mux(struct em28xx *dev, int index)
 {
-	int ainput;
 	struct v4l2_routing route;
 
 	route.input = INPUT(index)->vmux;
@@ -185,18 +186,9 @@
 		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
 		/* Note: this is msp3400 specific */
 		em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
-		ainput = EM28XX_AUDIO_SRC_TUNER;
-		em28xx_audio_source(dev, ainput);
-	} else {
-		switch (dev->ctl_ainput) {
-			case 0:
-				ainput = EM28XX_AUDIO_SRC_TUNER;
-				break;
-			default:
-				ainput = EM28XX_AUDIO_SRC_LINE;
-		}
-		em28xx_audio_source(dev, ainput);
 	}
+
+	em28xx_set_audio_source(dev);
 }
 
 /* Usage lock check functions */
@@ -292,7 +284,6 @@
 	case V4L2_CID_AUDIO_MUTE:
 		if (ctrl->value != dev->mute) {
 			dev->mute = ctrl->value;
-			em28xx_audio_usb_mute(dev, ctrl->value);
 			return em28xx_audio_analog_set(dev);
 		}
 		return 0;
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 93007cc..abde13e 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -151,10 +151,17 @@
 	EM28XX_RADIO,
 };
 
+enum em28xx_amux {
+	EM28XX_AMUX_VIDEO,
+	EM28XX_AMUX_LINE_IN,
+	EM28XX_AMUX_AC97_VIDEO,
+	EM28XX_AMUX_AC97_LINE_IN,
+};
+
 struct em28xx_input {
 	enum enum28xx_itype type;
 	unsigned int vmux;
-	unsigned int amux;
+	enum em28xx_amux amux;
 };
 
 #define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
@@ -321,8 +328,9 @@
 int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
 int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
 			  u8 bitmask);
-int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val);
+int em28xx_set_audio_source(struct em28xx *dev);
 int em28xx_audio_analog_set(struct em28xx *dev);
+
 int em28xx_colorlevels_set_default(struct em28xx *dev);
 int em28xx_capture_start(struct em28xx *dev, int start);
 int em28xx_outfmt_set_yuv422(struct em28xx *dev);
@@ -394,6 +402,7 @@
 
 /* em202 registers */
 #define MASTER_AC97	0x02
+#define LINE_IN_AC97    0x10
 #define VIDEO_AC97	0x14
 
 /* register settings */
@@ -418,28 +427,6 @@
 	printk(KERN_WARNING "%s: "fmt,\
 			dev->name , ##arg); } while (0)
 
-inline static int em28xx_audio_source(struct em28xx *dev, int input)
-{
-	if(dev->is_em2800){
-		u8 tmp = EM2800_AUDIO_SRC_TUNER;
-		if(input == EM28XX_AUDIO_SRC_LINE)
-			tmp = EM2800_AUDIO_SRC_LINE;
-		em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &tmp, 1);
-	}
-	return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
-}
-
-inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute)
-{
-	return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80);
-}
-
-inline static int em28xx_audio_analog_setup(struct em28xx *dev)
-{
-	/* unmute video mixer with default volume level */
-	return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08");
-}
-
 inline static int em28xx_compression_disable(struct em28xx *dev)
 {
 	/* side effect of disabling scaler and mixer */