V4L/DVB (9747): em28xx: Properly handles XCLK and I2C speed

The previous patches removed XCLK and I2C magic. Now, we finally know
what those registers do. Also, only a very few cards need different
setups for those.

Instead of keeping the setups for those values inside the per-device
hack magic switch, move the uncommon values to the board-specific
struct, and have a common setup for all other boards.

So, almost 100 lines of hacking magic were removed.

A co-lateral effect of this patch is that it also fixes a bug at em28xx-core, where xclk
were set, without taking any care about not overriding a previous xclk setup.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 83f352a..729c76c 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -55,6 +55,7 @@
 	[EM2750_BOARD_UNKNOWN] = {
 		.name          = "Unknown EM2750/EM2751 webcam grabber",
 		.vchannels     = 1,
+		.xclk          = EM28XX_XCLK_FREQUENCY_48MHZ,
 		.input         = { {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = 0,
@@ -78,15 +79,15 @@
 		} },
 	},
 	[EM2820_BOARD_UNKNOWN] = {
-		.name         = "Unknown EM2750/28xx video grabber",
-		.is_em2800    = 0,
-		.tuner_type   = TUNER_ABSENT,
+		.name          = "Unknown EM2750/28xx video grabber",
+		.tuner_type    = TUNER_ABSENT,
 	},
 	[EM2750_BOARD_DLCW_130] = {
 		/* Beijing Huaqi Information Digital Technology Co., Ltd */
 		.name          = "Huaqi DLCW-130",
 		.valid         = EM28XX_BOARD_NOT_VALIDATED,
 		.vchannels     = 1,
+		.xclk          = EM28XX_XCLK_FREQUENCY_48MHZ,
 		.input         = { {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = 0,
@@ -514,6 +515,10 @@
 		.name         = "Pinnacle PCTV DVB-T",
 		.valid        = EM28XX_BOARD_NOT_VALIDATED,
 		.tuner_type   = TUNER_ABSENT, /* MT2060 */
+
+		/* djh - I have serious doubts this is right... */
+		.xclk         = EM28XX_XCLK_IR_RC5_MODE |
+				EM28XX_XCLK_FREQUENCY_10MHZ,
 	},
 	[EM2870_BOARD_COMPRO_VIDEOMATE] = {
 		.name         = "Compro, VideoMate U3",
@@ -547,7 +552,7 @@
 		.tda9887_conf = TDA9887_PRESENT,
 		.tuner_type   = TUNER_XC2028,
 		.mts_firmware = 1,
-		.has_dvb        = 1,
+		.has_dvb      = 1,
 		.decoder      = EM28XX_TVP5150,
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -589,7 +594,6 @@
 		.vchannels      = 3,
 		.tuner_type     = TUNER_XC2028,
 		.mts_firmware   = 1,
-		.has_12mhz_i2s  = 1,
 		.has_dvb        = 1,
 		.ir_codes       = ir_codes_hauppauge_new,
 		.decoder        = EM28XX_TVP5150,
@@ -612,7 +616,6 @@
 		.vchannels      = 3,
 		.tuner_type     = TUNER_XC2028,
 		.mts_firmware   = 1,
-		.has_12mhz_i2s  = 1,
 		.has_dvb        = 1,
 		.ir_codes       = ir_codes_pinnacle_pctv_hd,
 		.decoder        = EM28XX_TVP5150,
@@ -635,7 +638,6 @@
 		.vchannels      = 3,
 		.tuner_type     = TUNER_XC2028,
 		.mts_firmware   = 1,
-		.has_12mhz_i2s  = 1,
 		.has_dvb        = 1,
 		.ir_codes       = ir_codes_ati_tv_wonder_hd_600,
 		.decoder        = EM28XX_TVP5150,
@@ -1091,9 +1093,12 @@
 		.name         = "Pinnacle PCTV HD Mini",
 		.vchannels    = 0,
 		.tuner_type   = TUNER_ABSENT,
-		.has_dvb        = 1,
-		.ir_codes       = ir_codes_pinnacle_pctv_hd,
+		.has_dvb      = 1,
+		.ir_codes     = ir_codes_pinnacle_pctv_hd,
 		.decoder      = EM28XX_NODECODER,
+		.i2c_speed    = EM28XX_I2C_CLK_WAIT_ENABLE |
+				EM2874_I2C_SECONDARY_BUS_SELECT |
+				EM28XX_I2C_FREQ_400_KHZ,
 #ifdef DJH_DEBUG
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -1326,7 +1331,8 @@
 	dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
 	dev->decoder = em28xx_boards[dev->model].decoder;
 	dev->video_inputs = em28xx_boards[dev->model].vchannels;
-	dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
+	dev->xclk = em28xx_boards[dev->model].xclk;
+	dev->i2c_speed = em28xx_boards[dev->model].i2c_speed;
 	dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
 	dev->has_dvb = em28xx_boards[dev->model].has_dvb;
 	dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button;
@@ -1385,6 +1391,21 @@
 
 	em28xx_set_model(dev);
 
+	/* Those are the default values for the majority of boards
+	   Use those values if not specified otherwise at boards entry
+	 */
+	if (!dev->xclk)
+		dev->xclk = EM28XX_XCLK_IR_RC5_MODE |
+			    EM28XX_XCLK_FREQUENCY_12MHZ;
+
+	if (!dev->i2c_speed)
+		dev->i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+				 EM28XX_I2C_FREQ_100_KHZ;
+
+	em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->xclk & 0x7f);
+	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->i2c_speed);
+	msleep(50);
+
 	/* request some modules */
 	switch (dev->model) {
 	case EM2880_BOARD_TERRATEC_PRODIGY_XS:
@@ -1396,14 +1417,6 @@
 	case EM2882_BOARD_PINNACLE_HYBRID_PRO:
 	case EM2883_BOARD_KWORLD_HYBRID_A316:
 	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
-		msleep(50);
-
 		/* Sets GPO/GPIO sequences for this device */
 		dev->analog_gpio      = hauppauge_wintv_hvr_900_analog;
 		dev->digital_gpio     = hauppauge_wintv_hvr_900_digital;
@@ -1412,16 +1425,6 @@
 		break;
 
 	case EM2882_BOARD_TERRATEC_HYBRID_XS:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
-		msleep(50);
-
-		/* should be added ir_codes here */
-
 		/* Sets GPO/GPIO sequences for this device */
 		dev->analog_gpio      = hauppauge_wintv_hvr_900_analog;
 		dev->digital_gpio     = hauppauge_wintv_hvr_900_digital;
@@ -1436,14 +1439,6 @@
 	case EM2880_BOARD_KWORLD_DVB_310U:
 	case EM2870_BOARD_KWORLD_350U:
 	case EM2881_BOARD_DNT_DA2_HYBRID:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
-		msleep(50);
-
 		/* NOTE: EM2881_DNT_DA2_HYBRID spend 140 msleep for digital
 			 and analog commands. If this commands doesn't work,
 			 add this timer. */
@@ -1457,14 +1452,6 @@
 
 	case EM2880_BOARD_MSI_DIGIVOX_AD:
 	case EM2880_BOARD_MSI_DIGIVOX_AD_II:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
-		msleep(50);
-
 		/* Sets GPO/GPIO sequences for this device */
 		dev->analog_gpio      = em2880_msi_digivox_ad_analog;
 		dev->digital_gpio     = em2880_msi_digivox_ad_digital;
@@ -1472,19 +1459,7 @@
 		dev->tun_digital_gpio = default_callback;
 		break;
 
-	case EM2750_BOARD_UNKNOWN:
-	case EM2750_BOARD_DLCW_130:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_FREQUENCY_48MHZ);
-		break;
-
 	case EM2861_BOARD_PLEXTOR_PX_TV100U:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
 		/* FIXME guess */
 		/* Turn on analog audio output */
 		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
@@ -1492,13 +1467,6 @@
 
 	case EM2861_BOARD_KWORLD_PVRTV_300U:
 	case EM2880_BOARD_KWORLD_DVB_305U:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
-		msleep(10);
 		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x6d);
 		msleep(10);
 		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x7d);
@@ -1506,25 +1474,11 @@
 		break;
 
 	case EM2870_BOARD_KWORLD_355U:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
-		msleep(50);
-
 		/* Sets GPO/GPIO sequences for this device */
 		dev->digital_gpio     = em2870_kworld_355u_digital;
 		break;
 
 	case EM2870_BOARD_COMPRO_VIDEOMATE:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
 		/* TODO: someone can do some cleanup here...
 			 not everything's needed */
 		em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
@@ -1542,12 +1496,6 @@
 		break;
 
 	case EM2870_BOARD_TERRATEC_XS_MT2060:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
 		/* this device needs some gpio writes to get the DVB-T
 		   demod work */
 		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
@@ -1559,10 +1507,6 @@
 		break;
 
 	case EM2870_BOARD_PINNACLE_PCTV_DVB:
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
-
 		/* this device needs some gpio writes to get the
 		   DVB-T demod work */
 		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
@@ -1571,53 +1515,15 @@
 		mdelay(70);
 		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
 		mdelay(70);
-		/* switch em2880 rc protocol */
-		/* djh - I have serious doubts this is right... */
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_10MHZ);
-		/* should be added ir_codes here */
 		break;
 
 	case EM2820_BOARD_GADMEI_UTV310:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
-		/* Turn on analog audio output */
-		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
-		break;
-
-	case EM2860_BOARD_GADMEI_UTV330:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
-		/* should be added ir_codes here */
-		break;
-
 	case EM2820_BOARD_MSI_VOX_USB_2:
-		em28xx_write_reg(dev, EM28XX_R0F_XCLK,
-				 EM28XX_XCLK_IR_RC5_MODE |
-				 EM28XX_XCLK_FREQUENCY_12MHZ);
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM28XX_I2C_FREQ_100_KHZ);
-		/* enables audio for that device */
+		/* enables audio for that devices */
 		em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
 		break;
 
 	case EM2874_BOARD_PINNACLE_PCTV_80E:
-		/* Set 400 KHz clock and select secondary i2c bus */
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
-				 EM28XX_I2C_CLK_WAIT_ENABLE |
-				 EM2874_I2C_SECONDARY_BUS_SELECT |
-				 EM28XX_I2C_FREQ_400_KHZ);
-
 		dev->digital_gpio = em2874_pinnacle_80e_digital;
 		break;
 	}
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 413428a..53c7252 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -399,7 +399,7 @@
 int em28xx_audio_analog_set(struct em28xx *dev)
 {
 	int ret, i;
-	u8 xclk = 0x07;
+	u8 xclk;
 
 	if (!dev->audio_mode.has_audio)
 		return 0;
@@ -417,13 +417,11 @@
 		}
 	}
 
-	if (dev->has_12mhz_i2s)
-		xclk |= 0x20;
-
+	xclk = dev->xclk & 0x7f;
 	if (!dev->mute)
 		xclk |= 0x80;
 
-	ret = em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, xclk, 0xa7);
+	ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
 	if (ret < 0)
 		return ret;
 	msleep(10);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 4d50d60..3bf23d3 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -338,12 +338,13 @@
 	unsigned int is_em2800:1;
 	unsigned int has_msp34xx:1;
 	unsigned int mts_firmware:1;
-	unsigned int has_12mhz_i2s:1;
 	unsigned int max_range_640_480:1;
 	unsigned int has_dvb:1;
 	unsigned int has_snapshot_button:1;
 	unsigned int valid:1;
 
+	unsigned char xclk, i2c_speed;
+
 	enum em28xx_decoder decoder;
 
 	struct em28xx_input       input[MAX_EM28XX_INPUT];
@@ -422,12 +423,13 @@
 	unsigned int stream_on:1;	/* Locks streams */
 	unsigned int has_audio_class:1;
 	unsigned int has_alsa_audio:1;
-	unsigned int has_12mhz_i2s:1;
 	unsigned int max_range_640_480:1;
 	unsigned int has_dvb:1;
 	unsigned int has_snapshot_button:1;
 	unsigned int valid:1;		/* report for validated boards */
 
+	unsigned char xclk, i2c_speed;
+
 	struct em28xx_IR *ir;
 
 	/* Some older em28xx chips needs a waiting time after writing */