V4L/DVB (6765): ivtv: convert to bus-based i2c API

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index 715285e..26322e9 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -40,6 +40,27 @@
 #define MSP_MONO   MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
 				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
 
+/* usual i2c tuner addresses to probe */
+static struct ivtv_card_tuner_i2c ivtv_i2c_std = {
+	.radio = { I2C_CLIENT_END },
+	.demod = { 0x43, I2C_CLIENT_END },
+	.tv    = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
+/* as above, but with possible radio tuner */
+static struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
+	.radio = { 0x60, I2C_CLIENT_END },
+	.demod = { 0x43, I2C_CLIENT_END },
+	.tv    = { 0x61, I2C_CLIENT_END },
+};
+
+/* using the tda8290+75a combo */
+static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = {
+	.radio = { I2C_CLIENT_END },
+	.demod = { I2C_CLIENT_END },
+	.tv    = { 0x4b, I2C_CLIENT_END },
+};
+
 /********************** card configuration *******************************/
 
 /* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
@@ -73,6 +94,7 @@
 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
 	},
 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -127,6 +149,7 @@
 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
 	},
 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+	.i2c = &ivtv_i2c_std,
 };
 
 /* PVR-350 V1 boards have a different audio tuner input and use a
@@ -158,6 +181,7 @@
 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
 	},
 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -193,6 +217,7 @@
 			 CX25840_AUDIO_SERIAL, WM8775_AIN4 },
 	/* apparently needed for the IR blaster */
 	.gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 },
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -235,6 +260,7 @@
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC },
 	},
 	.pci_list = ivtv_pci_m179,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -276,6 +302,7 @@
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_mpg600,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -316,6 +343,7 @@
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_mpg160,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -351,6 +379,7 @@
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_pg600,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -394,6 +423,7 @@
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
 	.pci_list = ivtv_pci_avc2410,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -464,6 +494,7 @@
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_tg5000tv,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -494,6 +525,7 @@
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_va2000,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -538,6 +570,7 @@
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
 	.pci_list = ivtv_pci_cx23416gyc,
+	.i2c = &ivtv_i2c_std,
 };
 
 static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
@@ -568,6 +601,7 @@
 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
+	.i2c = &ivtv_i2c_std,
 };
 
 static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
@@ -597,6 +631,7 @@
 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -636,6 +671,7 @@
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
 	},
 	.pci_list = ivtv_pci_gv_mvprx,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -672,6 +708,7 @@
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
 	},
 	.pci_list = ivtv_pci_gv_mvprx2e,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -706,6 +743,7 @@
 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 	},
 	.pci_list = ivtv_pci_gotview_pci_dvd,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -744,6 +782,7 @@
 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 	},
 	.pci_list = ivtv_pci_gotview_pci_dvd2,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -779,6 +818,7 @@
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 },
 	},
 	.pci_list = ivtv_pci_yuan_mpc622,
+	.i2c = &ivtv_i2c_tda8290,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -820,6 +860,7 @@
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_dctmvtvp1,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -852,6 +893,7 @@
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 	},
 	.pci_list = ivtv_pci_pg600v2,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -883,6 +925,7 @@
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 	},
 	.pci_list = ivtv_pci_club3d,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -914,6 +957,7 @@
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 	},
 	.pci_list = ivtv_pci_avertv_mce116,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -952,6 +996,7 @@
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N },
 	},
 	.pci_list = ivtv_pci_aver_pvr150,
+	.i2c = &ivtv_i2c_radio,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -979,6 +1024,7 @@
 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 0 },
 	},
 	.gpio_init = { .direction = 0x4000, .initial_value = 0x4000 },
+	/* Does not have a tuner */
 	.pci_list = ivtv_pci_aver_ezmaker,
 };
 
@@ -1018,6 +1064,7 @@
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
 	.pci_list = ivtv_pci_asus_falcon2,
+	.i2c = &ivtv_i2c_std,
 };
 
 static const struct ivtv_card *ivtv_card_list[] = {
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index b982fb0..191aafd 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -84,7 +84,7 @@
 #define IVTV_PCI_ID_GOTVIEW1		0xffac
 #define IVTV_PCI_ID_GOTVIEW2 		0xffad
 
-/* hardware flags */
+/* hardware flags, no gaps allowed, IVTV_HW_GPIO must always be last */
 #define IVTV_HW_CX25840   (1 << 0)
 #define IVTV_HW_SAA7115   (1 << 1)
 #define IVTV_HW_SAA7127   (1 << 2)
@@ -94,14 +94,13 @@
 #define IVTV_HW_CS53L32A  (1 << 6)
 #define IVTV_HW_TVEEPROM  (1 << 7)
 #define IVTV_HW_SAA7114   (1 << 8)
-#define IVTV_HW_TVAUDIO   (1 << 9)
-#define IVTV_HW_UPD64031A (1 << 10)
-#define IVTV_HW_UPD6408X  (1 << 11)
-#define IVTV_HW_SAA717X   (1 << 12)
-#define IVTV_HW_WM8739    (1 << 13)
-#define IVTV_HW_VP27SMPX  (1 << 14)
-#define IVTV_HW_M52790    (1 << 15)
-#define IVTV_HW_GPIO      (1 << 16)
+#define IVTV_HW_UPD64031A (1 << 9)
+#define IVTV_HW_UPD6408X  (1 << 10)
+#define IVTV_HW_SAA717X   (1 << 11)
+#define IVTV_HW_WM8739    (1 << 12)
+#define IVTV_HW_VP27SMPX  (1 << 13)
+#define IVTV_HW_M52790    (1 << 14)
+#define IVTV_HW_GPIO      (1 << 15)
 
 #define IVTV_HW_SAA711X   (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
 
@@ -235,6 +234,12 @@
 	int 	    tuner; 	/* tuner ID (from tuner.h) */
 };
 
+struct ivtv_card_tuner_i2c {
+	unsigned short radio[2];/* radio tuner i2c address to probe */
+	unsigned short demod[2];/* demodulator i2c address to probe */
+	unsigned short tv[4];	/* tv tuner i2c addresses to probe */
+};
+
 /* for card information/parameters */
 struct ivtv_card {
 	int type;
@@ -262,6 +267,7 @@
 	struct ivtv_gpio_audio_detect 	gpio_audio_detect;
 
 	struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS];
+	struct ivtv_card_tuner_i2c *i2c;
 
 	/* list of device and subsystem vendor/devices that
 	   correspond to this card type. */
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 4595c78..4994dc5 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -400,6 +400,7 @@
 
 	itv->v4l2_cap = itv->card->v4l2_capabilities;
 	itv->card_name = itv->card->name;
+	itv->card_i2c = itv->card->i2c;
 
 	/* If this is a PVR500 then it should be possible to detect whether it is the
 	   first or second unit by looking at the subsystem device ID: is bit 4 is
@@ -417,7 +418,14 @@
 	   This detection is needed since the eeprom reports incorrectly that a radio is
 	   present on the second unit. */
 	if (tv.model / 1000 == 23) {
+		static const struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
+			.radio = { 0x60, I2C_CLIENT_END },
+			.demod = { 0x43, I2C_CLIENT_END },
+			.tv = { 0x61, I2C_CLIENT_END },
+		};
+
 		itv->card_name = "WinTV PVR 500";
+		itv->card_i2c = &ivtv_i2c_radio;
 		if (pci_slot == 8 || pci_slot == 9) {
 			int is_first = (pci_slot & 1) == 0;
 
@@ -635,6 +643,7 @@
 	}
 	itv->v4l2_cap = itv->card->v4l2_capabilities;
 	itv->card_name = itv->card->name;
+	itv->card_i2c = itv->card->i2c;
 }
 
 /* Precondition: the ivtv structure has been memset to 0. Only
@@ -816,79 +825,66 @@
 	return 0;
 }
 
-static void ivtv_request_module(struct ivtv *itv, const char *name)
+static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
+		const char *name, u32 id)
 {
+	if ((hw & id) == 0)
+		return hw;
 	if (request_module(name) != 0) {
 		IVTV_ERR("Failed to load module %s\n", name);
-	} else {
-		IVTV_DEBUG_INFO("Loaded module %s\n", name);
+		return hw & ~id;
 	}
+	IVTV_DEBUG_INFO("Loaded module %s\n", name);
+	return hw;
 }
 
 static void ivtv_load_and_init_modules(struct ivtv *itv)
 {
 	u32 hw = itv->card->hw_all;
-	int i;
+	unsigned i;
 
 	/* load modules */
-#ifndef CONFIG_VIDEO_TUNER
-	if (hw & IVTV_HW_TUNER) {
-		if (itv->options.tuner == TUNER_XC2028) {
-			IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n");
-			itv->tunerid = 1;
-		}
-		else {
-			ivtv_request_module(itv, "tuner");
-		}
+	if ((hw & IVTV_HW_TUNER) && itv->options.tuner == TUNER_XC2028) {
+		IVTV_INFO("Xceive tuner not yet supported, only composite\n");
+		IVTV_INFO("and S-Video inputs will be available\n");
+		hw &= ~IVTV_HW_TUNER;
 	}
+#ifndef CONFIG_VIDEO_TUNER
+	hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
 #endif
 #ifndef CONFIG_VIDEO_CX25840
-	if (hw & IVTV_HW_CX25840)
-		ivtv_request_module(itv, "cx25840");
+	hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840);
 #endif
 #ifndef CONFIG_VIDEO_SAA711X
-	if (hw & IVTV_HW_SAA711X)
-		ivtv_request_module(itv, "saa7115");
+	hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X);
 #endif
 #ifndef CONFIG_VIDEO_SAA7127
-	if (hw & IVTV_HW_SAA7127)
-		ivtv_request_module(itv, "saa7127");
+	hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127);
 #endif
-	if (hw & IVTV_HW_SAA717X)
-		ivtv_request_module(itv, "saa717x");
+	hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X);
 #ifndef CONFIG_VIDEO_UPD64031A
-	if (hw & IVTV_HW_UPD64031A)
-		ivtv_request_module(itv, "upd64031a");
+	hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A);
 #endif
 #ifndef CONFIG_VIDEO_UPD64083
-	if (hw & IVTV_HW_UPD6408X)
-		ivtv_request_module(itv, "upd64083");
+	hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X);
 #endif
 #ifndef CONFIG_VIDEO_MSP3400
-	if (hw & IVTV_HW_MSP34XX)
-		ivtv_request_module(itv, "msp3400");
+	hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX);
 #endif
 #ifndef CONFIG_VIDEO_VP27SMPX
-	if (hw & IVTV_HW_VP27SMPX)
-		ivtv_request_module(itv, "vp27smpx");
+	hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX);
 #endif
-	if (hw & IVTV_HW_TVAUDIO)
-		ivtv_request_module(itv, "tvaudio");
 #ifndef CONFIG_VIDEO_WM8775
-	if (hw & IVTV_HW_WM8775)
-		ivtv_request_module(itv, "wm8775");
+	hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775);
 #endif
 #ifndef CONFIG_VIDEO_WM8739
-	if (hw & IVTV_HW_WM8739)
-		ivtv_request_module(itv, "wm8739");
+	hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739);
 #endif
 #ifndef CONFIG_VIDEO_CS53L32A
-	if (hw & IVTV_HW_CS53L32A)
-		ivtv_request_module(itv, "cs53l32a");
+	hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A);
 #endif
 #ifndef CONFIG_VIDEO_M52790
-	if (hw & IVTV_HW_M52790)
-		ivtv_request_module(itv, "m52790");
+	hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790);
 #endif
 
 	/* check which i2c devices are actually found */
@@ -897,11 +893,12 @@
 
 		if (!(device & hw))
 			continue;
-		if (device == IVTV_HW_GPIO) {
-			/* GPIO is always available */
-			itv->hw_flags |= IVTV_HW_GPIO;
+		if (device == IVTV_HW_GPIO || device == IVTV_HW_TVEEPROM) {
+			/* GPIO and TVEEPROM do not use i2c probing */
+			itv->hw_flags |= device;
 			continue;
 		}
+		ivtv_i2c_register(itv, i);
 		if (ivtv_i2c_hw_addr(itv, device) > 0)
 			itv->hw_flags |= device;
 	}
@@ -1075,9 +1072,6 @@
 	IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
 
 	if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
-#ifdef CONFIG_VIDEO_TVEEPROM_MODULE
-		ivtv_request_module(itv, "tveeprom");
-#endif
 		/* Based on the model number the cardtype may be changed.
 		   The PCI IDs are not always reliable. */
 		ivtv_process_eeprom(itv);
@@ -1150,7 +1144,7 @@
 	if (itv->options.radio > 0)
 		itv->v4l2_cap |= V4L2_CAP_RADIO;
 
-	if (itv->options.tuner > -1 && itv->tunerid == 0) {
+	if (itv->options.tuner > -1) {
 		struct tuner_setup setup;
 
 		setup.addr = ADDR_UNSET;
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 19a9b3b..8eeea3a 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -590,13 +590,13 @@
 	struct pci_dev *dev;		/* PCI device */
 	const struct ivtv_card *card;	/* card information */
 	const char *card_name;          /* full name of the card */
+	const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
 	u8 has_cx23415;			/* 1 if it is a cx23415 based card, 0 for cx23416 */
 	u8 pvr150_workaround;           /* 1 if the cx25840 needs to workaround a PVR150 bug */
 	u8 nof_inputs;			/* number of video inputs */
 	u8 nof_audio_inputs;		/* number of audio inputs */
 	u32 v4l2_cap;			/* V4L2 capabilities of card */
 	u32 hw_flags; 			/* hardware description of the board */
-	int tunerid;			/* userspace tuner ID for experimental Xceive tuner support */
 	v4l2_std_id tuner_std;		/* the norm of the card's tuner (fixed) */
 					/* controlling video decoder function */
 	int (*video_dec_func)(struct ivtv *, unsigned int, void *);
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 7f513ec..9acfde6 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -92,7 +92,8 @@
 #define IVTV_TEA5767_I2C_ADDR		0x60
 #define IVTV_UPD64031A_I2C_ADDR 	0x12
 #define IVTV_UPD64083_I2C_ADDR 		0x5c
-#define IVTV_TDA985X_I2C_ADDR      	0x5b
+#define IVTV_VP27SMPX_I2C_ADDR      	0x5b
+#define IVTV_M52790_I2C_ADDR      	0x48
 
 /* This array should match the IVTV_HW_ defines */
 static const u8 hw_driverids[] = {
@@ -105,7 +106,6 @@
 	I2C_DRIVERID_CS53L32A,
 	I2C_DRIVERID_TVEEPROM,
 	I2C_DRIVERID_SAA711X,
-	I2C_DRIVERID_TVAUDIO,
 	I2C_DRIVERID_UPD64031A,
 	I2C_DRIVERID_UPD64083,
 	I2C_DRIVERID_SAA717X,
@@ -116,8 +116,28 @@
 };
 
 /* This array should match the IVTV_HW_ defines */
+static const u8 hw_addrs[] = {
+	IVTV_CX25840_I2C_ADDR,
+	IVTV_SAA7115_I2C_ADDR,
+	IVTV_SAA7127_I2C_ADDR,
+	IVTV_MSP3400_I2C_ADDR,
+	0,
+	IVTV_WM8775_I2C_ADDR,
+	IVTV_CS53L32A_I2C_ADDR,
+	0,
+	IVTV_SAA7115_I2C_ADDR,
+	IVTV_UPD64031A_I2C_ADDR,
+	IVTV_UPD64083_I2C_ADDR,
+	IVTV_SAA717x_I2C_ADDR,
+	IVTV_WM8739_I2C_ADDR,
+	IVTV_VP27SMPX_I2C_ADDR,
+	IVTV_M52790_I2C_ADDR,
+	0 		/* IVTV_HW_GPIO dummy driver ID */
+};
+
+/* This array should match the IVTV_HW_ defines */
 static const char * const hw_drivernames[] = {
-	"cx2584x",
+	"cx25840",
 	"saa7115",
 	"saa7127",
 	"msp3400",
@@ -125,8 +145,7 @@
 	"wm8775",
 	"cs53l32a",
 	"tveeprom",
-	"saa7114",
-	"tvaudio",
+	"saa7115",
 	"upd64031a",
 	"upd64083",
 	"saa717x",
@@ -136,21 +155,57 @@
 	"gpio",
 };
 
-static int attach_inform(struct i2c_client *client)
+int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
 {
-	struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter);
+	struct i2c_board_info info;
+	struct i2c_client *c;
+	u8 id;
 	int i;
 
-	IVTV_DEBUG_I2C("i2c client attach\n");
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (itv->i2c_clients[i] == NULL) {
-			itv->i2c_clients[i] = client;
-			break;
-		}
-	}
+	IVTV_DEBUG_I2C("i2c client register\n");
+	if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
+		return -1;
+	id = hw_driverids[idx];
+	memset(&info, 0, sizeof(info));
+	strcpy(info.driver_name, hw_drivernames[idx]);
+	info.addr = hw_addrs[idx];
+	for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {}
+
 	if (i == I2C_CLIENTS_MAX) {
-		IVTV_ERR("Insufficient room for new I2C client\n");
+		IVTV_ERR("insufficient room for new I2C client!\n");
+		return -ENOMEM;
 	}
+
+	if (id != I2C_DRIVERID_TUNER) {
+		c = i2c_new_device(&itv->i2c_adap, &info);
+		if (c->driver == NULL)
+			i2c_unregister_device(c);
+		else
+			itv->i2c_clients[i] = c;
+		return itv->i2c_clients[i] ? 0 : -ENODEV;
+	}
+
+	/* special tuner handling */
+	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->radio);
+	if (c && c->driver == NULL)
+		i2c_unregister_device(c);
+	else if (c)
+		itv->i2c_clients[i++] = c;
+	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->demod);
+	if (c && c->driver == NULL)
+		i2c_unregister_device(c);
+	else if (c)
+		itv->i2c_clients[i++] = c;
+	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->tv);
+	if (c && c->driver == NULL)
+		i2c_unregister_device(c);
+	else if (c)
+		itv->i2c_clients[i++] = c;
+	return 0;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
 	return 0;
 }
 
@@ -478,9 +533,6 @@
 	.client_register = attach_inform,
 	.client_unregister = detach_inform,
 	.owner = THIS_MODULE,
-#ifdef I2C_ADAP_CLASS_TV_ANALOG
-	.class = I2C_ADAP_CLASS_TV_ANALOG,
-#endif
 };
 
 static void ivtv_setscl_old(void *data, int state)
@@ -534,9 +586,6 @@
 	.client_register = attach_inform,
 	.client_unregister = detach_inform,
 	.owner = THIS_MODULE,
-#ifdef I2C_ADAP_CLASS_TV_ANALOG
-	.class = I2C_ADAP_CLASS_TV_ANALOG,
-#endif
 };
 
 static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
@@ -561,12 +610,9 @@
 	IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
 	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
 		client = itv->i2c_clients[i];
-		if (client == NULL) {
+		if (client == NULL || client->driver == NULL ||
+		    client->driver->command == NULL)
 			continue;
-		}
-		if (client->driver->command == NULL) {
-			continue;
-		}
 		if (addr == client->addr) {
 			retval = client->driver->command(client, cmd, arg);
 			return retval;
@@ -587,7 +633,7 @@
 
 	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
 		client = itv->i2c_clients[i];
-		if (client == NULL)
+		if (client == NULL || client->driver == NULL)
 			continue;
 		if (id == client->driver->id) {
 			retval = client->addr;
@@ -713,6 +759,16 @@
 {
 	IVTV_DEBUG_I2C("i2c init\n");
 
+	/* Sanity checks for the I2C hardware arrays. They must be the
+	 * same size and GPIO must be the last entry.
+	 */
+	if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
+	    ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) ||
+	    IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
+	    hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+		IVTV_ERR("Mismatched I2C hardware arrays\n");
+		return -ENODEV;
+	}
 	if (itv->options.newi2c > 0) {
 		memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template,
 		       sizeof(struct i2c_adapter));
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h
index 987042c..022978c 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.h
+++ b/drivers/media/video/ivtv/ivtv-i2c.h
@@ -33,6 +33,7 @@
 int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg);
 int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg);
 void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg);
+int ivtv_i2c_register(struct ivtv *itv, unsigned idx);
 
 /* init + register i2c algo-bit adapter */
 int init_ivtv_i2c(struct ivtv *itv);