summary refs log tree commit diff
path: root/drivers/media/video/ivtv
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/ivtv')
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c16
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.c16
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c214
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h52
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c44
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.c324
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.h3
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c314
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.h13
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c73
-rw-r--r--drivers/media/video/ivtv/ivtv-routing.c12
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c15
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.c17
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c91
14 files changed, 516 insertions, 688 deletions
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index 4e05f91a9100..2883c8780760 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -877,20 +877,28 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = {
 static const struct ivtv_card ivtv_card_pg600v2 = {
 	.type = IVTV_CARD_PG600V2,
 	.name = "Yuan PG600-2, GotView PCI DVD Lite",
-	.comment = "only Composite and S-Video inputs are supported, not the tuner\n",
 	.v4l2_capabilities = IVTV_CAP_ENCODER,
 	.hw_video = IVTV_HW_CX25840,
 	.hw_audio = IVTV_HW_CX25840,
 	.hw_audio_ctrl = IVTV_HW_CX25840,
-	.hw_all = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	/* XC2028 support apparently works for the Yuan, it's still
+	   uncertain whether it also works with the GotView. */
 	.video_inputs = {
-		{ IVTV_CARD_INPUT_SVIDEO1,    0,
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
 		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
-		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
 	},
 	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
 	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
+	.xceive_pin = 12,
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
 	.pci_list = ivtv_pci_pg600v2,
 	.i2c = &ivtv_i2c_std,
 };
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index 48e103be7183..62aa06f5d168 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -63,7 +63,7 @@ int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
 	case V4L2_CID_HUE:
 	case V4L2_CID_SATURATION:
 	case V4L2_CID_CONTRAST:
-		if (itv->video_dec_func(itv, VIDIOC_QUERYCTRL, qctrl))
+		if (v4l2_subdev_call(itv->sd_video, core, queryctrl, qctrl))
 			qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
 		return 0;
 
@@ -73,7 +73,7 @@ int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
 	case V4L2_CID_AUDIO_BASS:
 	case V4L2_CID_AUDIO_TREBLE:
 	case V4L2_CID_AUDIO_LOUDNESS:
-		if (ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl))
+		if (v4l2_subdev_call(itv->sd_audio, core, queryctrl, qctrl))
 			qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
 		return 0;
 
@@ -122,7 +122,7 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
 	case V4L2_CID_HUE:
 	case V4L2_CID_SATURATION:
 	case V4L2_CID_CONTRAST:
-		return itv->video_dec_func(itv, VIDIOC_S_CTRL, vctrl);
+		return v4l2_subdev_call(itv->sd_video, core, s_ctrl, vctrl);
 
 	case V4L2_CID_AUDIO_VOLUME:
 	case V4L2_CID_AUDIO_MUTE:
@@ -130,7 +130,7 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
 	case V4L2_CID_AUDIO_BASS:
 	case V4L2_CID_AUDIO_TREBLE:
 	case V4L2_CID_AUDIO_LOUDNESS:
-		return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
+		return v4l2_subdev_call(itv->sd_audio, core, s_ctrl, vctrl);
 
 	default:
 		IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
@@ -147,7 +147,7 @@ static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
 	case V4L2_CID_HUE:
 	case V4L2_CID_SATURATION:
 	case V4L2_CID_CONTRAST:
-		return itv->video_dec_func(itv, VIDIOC_G_CTRL, vctrl);
+		return v4l2_subdev_call(itv->sd_video, core, g_ctrl, vctrl);
 
 	case V4L2_CID_AUDIO_VOLUME:
 	case V4L2_CID_AUDIO_MUTE:
@@ -155,7 +155,7 @@ static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
 	case V4L2_CID_AUDIO_BASS:
 	case V4L2_CID_AUDIO_TREBLE:
 	case V4L2_CID_AUDIO_LOUDNESS:
-		return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
+		return v4l2_subdev_call(itv->sd_audio, core, g_ctrl, vctrl);
 	default:
 		IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
 		return -EINVAL;
@@ -268,7 +268,7 @@ int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
 			fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 			fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1);
 			fmt.fmt.pix.height = itv->params.height;
-			itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt);
+			v4l2_subdev_call(itv->sd_video, video, s_fmt, &fmt);
 		}
 		err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p);
 		if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt)
@@ -279,7 +279,7 @@ int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
 		/* The audio clock of the digitizer must match the codec sample
 		   rate otherwise you get some very strange effects. */
 		if (idx < sizeof(freqs))
-			ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
+			ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]);
 		return err;
 	}
 	return -EINVAL;
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index b69cc1d55e5b..08b762951759 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -60,9 +60,6 @@
 #include <media/v4l2-chip-ident.h>
 #include "tuner-xc2028.h"
 
-/* var to keep track of the number of array elements in use */
-int ivtv_cards_active;
-
 /* If you have already X v4l cards, then set this to X. This way
    the device numbers stay matched. Example: you have a WinTV card
    without radio and a PVR-350 with. Normally this would give a
@@ -70,12 +67,6 @@ int ivtv_cards_active;
    setting this to 1 you ensure that radio0 is now also radio1. */
 int ivtv_first_minor;
 
-/* Master variable for all ivtv info */
-struct ivtv *ivtv_cards[IVTV_MAX_CARDS];
-
-/* Protects ivtv_cards_active */
-DEFINE_SPINLOCK(ivtv_cards_lock);
-
 /* add your revision and whatnot here */
 static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
 	{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15,
@@ -87,6 +78,9 @@ static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl);
 
+/* ivtv instance counter */
+static atomic_t ivtv_instance = ATOMIC_INIT(0);
+
 /* Parameter declarations */
 static int cardtype[IVTV_MAX_CARDS];
 static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
@@ -599,9 +593,9 @@ static void ivtv_process_options(struct ivtv *itv)
 	itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024;
 	itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024;
 	itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers;
-	itv->options.cardtype = cardtype[itv->num];
-	itv->options.tuner = tuner[itv->num];
-	itv->options.radio = radio[itv->num];
+	itv->options.cardtype = cardtype[itv->instance];
+	itv->options.tuner = tuner[itv->instance];
+	itv->options.radio = radio[itv->instance];
 	itv->options.newi2c = newi2c;
 	if (tunertype < -1 || tunertype > 1) {
 		IVTV_WARN("Invalid tunertype argument, will autodetect instead\n");
@@ -688,7 +682,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
 	spin_lock_init(&itv->lock);
 	spin_lock_init(&itv->dma_reg_lock);
 
-	itv->irq_work_queues = create_singlethread_workqueue(itv->name);
+	itv->irq_work_queues = create_singlethread_workqueue(itv->device.name);
 	if (itv->irq_work_queues == NULL) {
 		IVTV_ERR("Could not create ivtv workqueue\n");
 		return -1;
@@ -770,12 +764,6 @@ static void __devinit ivtv_init_struct2(struct ivtv *itv)
 		i = 0;
 	itv->active_input = i;
 	itv->audio_input = itv->card->video_inputs[i].audio_index;
-	if (itv->card->hw_all & IVTV_HW_CX25840)
-		itv->video_dec_func = ivtv_cx25840;
-	else if (itv->card->hw_all & IVTV_HW_SAA717X)
-		itv->video_dec_func = ivtv_saa717x;
-	else
-		itv->video_dec_func = ivtv_saa7115;
 }
 
 static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
@@ -788,21 +776,21 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
 	IVTV_DEBUG_INFO("Enabling pci device\n");
 
 	if (pci_enable_device(dev)) {
-		IVTV_ERR("Can't enable device %d!\n", itv->num);
+		IVTV_ERR("Can't enable device!\n");
 		return -EIO;
 	}
 	if (pci_set_dma_mask(dev, 0xffffffff)) {
-		IVTV_ERR("No suitable DMA available on card %d.\n", itv->num);
+		IVTV_ERR("No suitable DMA available.\n");
 		return -EIO;
 	}
 	if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) {
-		IVTV_ERR("Cannot request encoder memory region on card %d.\n", itv->num);
+		IVTV_ERR("Cannot request encoder memory region.\n");
 		return -EIO;
 	}
 
 	if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET,
 				IVTV_REG_SIZE, "ivtv registers")) {
-		IVTV_ERR("Cannot request register memory region on card %d.\n", itv->num);
+		IVTV_ERR("Cannot request register memory region.\n");
 		release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
 		return -EIO;
 	}
@@ -810,7 +798,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
 	if (itv->has_cx23415 &&
 	    !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET,
 				IVTV_DECODER_SIZE, "ivtv decoder")) {
-		IVTV_ERR("Cannot request decoder memory region on card %d.\n", itv->num);
+		IVTV_ERR("Cannot request decoder memory region.\n");
 		release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
 		release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
 		return -EIO;
@@ -853,69 +841,11 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
 	return 0;
 }
 
-#ifdef MODULE
-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);
-		return hw & ~id;
-	}
-	IVTV_DEBUG_INFO("Loaded module %s\n", name);
-	return hw;
-}
-#endif
-
 static void ivtv_load_and_init_modules(struct ivtv *itv)
 {
 	u32 hw = itv->card->hw_all;
 	unsigned i;
 
-#ifdef MODULE
-	/* load modules */
-#ifdef CONFIG_MEDIA_TUNER_MODULE
-	hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
-#endif
-#ifdef CONFIG_VIDEO_CX25840_MODULE
-	hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840);
-#endif
-#ifdef CONFIG_VIDEO_SAA711X_MODULE
-	hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X);
-#endif
-#ifdef CONFIG_VIDEO_SAA7127_MODULE
-	hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127);
-#endif
-#ifdef CONFIG_VIDEO_SAA717X_MODULE
-	hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X);
-#endif
-#ifdef CONFIG_VIDEO_UPD64031A_MODULE
-	hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A);
-#endif
-#ifdef CONFIG_VIDEO_UPD64083_MODULE
-	hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X);
-#endif
-#ifdef CONFIG_VIDEO_MSP3400_MODULE
-	hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX);
-#endif
-#ifdef CONFIG_VIDEO_VP27SMPX_MODULE
-	hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX);
-#endif
-#ifdef CONFIG_VIDEO_WM8775_MODULE
-	hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775);
-#endif
-#ifdef CONFIG_VIDEO_WM8739_MODULE
-	hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739);
-#endif
-#ifdef CONFIG_VIDEO_CS53L32A_MODULE
-	hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A);
-#endif
-#ifdef CONFIG_VIDEO_M52790_MODULE
-	hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790);
-#endif
-#endif
-
 	/* check which i2c devices are actually found */
 	for (i = 0; i < 32; i++) {
 		u32 device = 1 << i;
@@ -927,11 +857,21 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
 			itv->hw_flags |= device;
 			continue;
 		}
-		ivtv_i2c_register(itv, i);
-		if (ivtv_i2c_hw_addr(itv, device) > 0)
+		if (ivtv_i2c_register(itv, i) == 0)
 			itv->hw_flags |= device;
 	}
 
+	if (itv->card->hw_all & IVTV_HW_CX25840)
+		itv->sd_video = ivtv_find_hw(itv, IVTV_HW_CX25840);
+	else if (itv->card->hw_all & IVTV_HW_SAA717X)
+		itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA717X);
+	else if (itv->card->hw_all & IVTV_HW_SAA7114)
+		itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7114);
+	else
+		itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7115);
+	itv->sd_audio = ivtv_find_hw(itv, itv->card->hw_audio_ctrl);
+	itv->sd_muxer = ivtv_find_hw(itv, itv->card->hw_muxer);
+
 	hw = itv->hw_flags;
 
 	if (itv->card->type == IVTV_CARD_CX23416GYC) {
@@ -949,7 +889,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
 		/* The crystal frequency of GVMVPRX is 24.576MHz */
 		crystal_freq.freq = SAA7115_FREQ_24_576_MHZ;
 		crystal_freq.flags = SAA7115_FREQ_FL_UCGC;
-		itv->video_dec_func(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+		v4l2_subdev_call(itv->sd_video, video, s_crystal_freq, &crystal_freq);
 	}
 
 	if (hw & IVTV_HW_CX25840) {
@@ -967,7 +907,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
 		/* determine the exact saa711x model */
 		itv->hw_flags &= ~IVTV_HW_SAA711X;
 
-		ivtv_saa7115(itv, VIDIOC_G_CHIP_IDENT, &v);
+		ivtv_call_hw(itv, IVTV_HW_SAA711X, core, g_chip_ident, &v);
 		if (v.ident == V4L2_IDENT_SAA7114) {
 			itv->hw_flags |= IVTV_HW_SAA7114;
 			/* VBI is not yet supported by the saa7114 driver. */
@@ -1001,28 +941,20 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 	int vbi_buf_size;
 	struct ivtv *itv;
 
-	spin_lock(&ivtv_cards_lock);
-
-	/* Make sure we've got a place for this card */
-	if (ivtv_cards_active == IVTV_MAX_CARDS) {
-		printk(KERN_ERR "ivtv:  Maximum number of cards detected (%d)\n",
-			      ivtv_cards_active);
-		spin_unlock(&ivtv_cards_lock);
-		return -ENOMEM;
-	}
-
 	itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
-	if (itv == NULL) {
-		spin_unlock(&ivtv_cards_lock);
+	if (itv == NULL)
 		return -ENOMEM;
-	}
-	ivtv_cards[ivtv_cards_active] = itv;
 	itv->dev = dev;
-	itv->num = ivtv_cards_active++;
-	snprintf(itv->name, sizeof(itv->name), "ivtv%d", itv->num);
-	IVTV_INFO("Initializing card #%d\n", itv->num);
+	itv->instance = atomic_inc_return(&ivtv_instance) - 1;
 
-	spin_unlock(&ivtv_cards_lock);
+	retval = v4l2_device_register(&dev->dev, &itv->device);
+	if (retval)
+		return retval;
+	/* "ivtv + PCI ID" is a bit of a mouthful, so use
+	   "ivtv + instance" instead. */
+	snprintf(itv->device.name, sizeof(itv->device.name),
+			"ivtv%d", itv->instance);
+	IVTV_INFO("Initializing card %d\n", itv->instance);
 
 	ivtv_process_options(itv);
 	if (itv->options.cardtype == -1) {
@@ -1043,8 +975,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 		else if (retval == -ENXIO)
 			goto free_mem;
 	}
-	/* save itv in the pci struct for later use */
-	pci_set_drvdata(dev, itv);
 
 	/* map io memory */
 	IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
@@ -1086,7 +1016,9 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 		goto free_io;
 	}
 
-	ivtv_gpio_init(itv);
+	retval = ivtv_gpio_init(itv);
+	if (retval)
+		goto free_io;
 
 	/* active i2c  */
 	IVTV_DEBUG_INFO("activating i2c...\n");
@@ -1095,8 +1027,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 		goto free_io;
 	}
 
-	IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
-
 	if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
 		/* Based on the model number the cardtype may be changed.
 		   The PCI IDs are not always reliable. */
@@ -1191,7 +1121,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 		setup.mode_mask = T_ANALOG_TV;  /* matches TV tuners */
 		setup.tuner_callback = (setup.type == TUNER_XC2028) ?
 			ivtv_reset_tuner_gpio : NULL;
-		ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup);
+		ivtv_call_all(itv, tuner, s_type_addr, &setup);
 		if (setup.type == TUNER_XC2028) {
 			static struct xc2028_ctrl ctrl = {
 				.fname = XC2028_DEFAULT_FIRMWARE,
@@ -1201,7 +1131,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 				.tuner = itv->options.tuner,
 				.priv = &ctrl,
 			};
-			ivtv_call_i2c_clients(itv, TUNER_SET_CONFIG, &cfg);
+			ivtv_call_all(itv, tuner, s_config, &cfg);
 		}
 	}
 
@@ -1210,11 +1140,11 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 	itv->tuner_std = itv->std;
 
 	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
-		ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std);
+		ivtv_call_all(itv, video, s_std_output, itv->std);
 		/* Turn off the output signal. The mpeg decoder is not yet
 		   active so without this you would get a green image until the
 		   mpeg decoder becomes active. */
-		ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
 	}
 
 	/* clear interrupt mask, effectively disabling interrupts */
@@ -1222,7 +1152,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 
 	/* Register IRQ */
 	retval = request_irq(itv->dev->irq, ivtv_irq_handler,
-			     IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv);
+	     IRQF_SHARED | IRQF_DISABLED, itv->device.name, (void *)itv);
 	if (retval) {
 		IVTV_ERR("Failed to register irq %d\n", retval);
 		goto free_i2c;
@@ -1238,7 +1168,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 		IVTV_ERR("Error %d registering devices\n", retval);
 		goto free_streams;
 	}
-	IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
+	IVTV_INFO("Initialized card: %s\n", itv->card_name);
 	return 0;
 
 free_streams:
@@ -1261,10 +1191,8 @@ err:
 		retval = -ENODEV;
 	IVTV_ERR("Error %d on initialization\n", retval);
 
-	spin_lock(&ivtv_cards_lock);
-	kfree(ivtv_cards[ivtv_cards_active]);
-	ivtv_cards[ivtv_cards_active] = NULL;
-	spin_unlock(&ivtv_cards_lock);
+	v4l2_device_unregister(&itv->device);
+	kfree(itv);
 	return retval;
 }
 
@@ -1304,10 +1232,11 @@ int ivtv_init_on_first_open(struct ivtv *itv)
 	if (itv->card->hw_all & IVTV_HW_CX25840) {
 		struct v4l2_control ctrl;
 
+		v4l2_subdev_call(itv->sd_video, core, init, 0);
 		/* CX25840_CID_ENABLE_PVR150_WORKAROUND */
 		ctrl.id = V4L2_CID_PRIVATE_BASE;
 		ctrl.value = itv->pvr150_workaround;
-		itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl);
+		v4l2_subdev_call(itv->sd_video, core, s_ctrl, &ctrl);
 	}
 
 	vf.tuner = 0;
@@ -1337,7 +1266,7 @@ int ivtv_init_on_first_open(struct ivtv *itv)
 		/* Turn on the TV-out: ivtv_init_mpeg_decoder() initializes
 		   the mpeg decoder so now the saa7127 receives a proper
 		   signal. */
-		ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
 		ivtv_init_mpeg_decoder(itv);
 	}
 	ivtv_s_std(NULL, &fh, &itv->tuner_std);
@@ -1362,9 +1291,11 @@ int ivtv_init_on_first_open(struct ivtv *itv)
 
 static void ivtv_remove(struct pci_dev *pci_dev)
 {
-	struct ivtv *itv = pci_get_drvdata(pci_dev);
+	struct v4l2_device *dev = dev_get_drvdata(&pci_dev->dev);
+	struct ivtv *itv = to_ivtv(dev);
+	int i;
 
-	IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num);
+	IVTV_DEBUG_INFO("Removing card\n");
 
 	if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) {
 		/* Stop all captures */
@@ -1377,7 +1308,7 @@ static void ivtv_remove(struct pci_dev *pci_dev)
 
 		/* Turn off the TV-out */
 		if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
-			ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
+			ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
 		if (atomic_read(&itv->decoding) > 0) {
 			int type;
 
@@ -1402,6 +1333,8 @@ static void ivtv_remove(struct pci_dev *pci_dev)
 	ivtv_streams_cleanup(itv, 1);
 	ivtv_udma_free(itv);
 
+	v4l2_device_unregister(&itv->device);
+
 	exit_ivtv_i2c(itv);
 
 	free_irq(itv->dev->irq, (void *)itv);
@@ -1413,8 +1346,11 @@ static void ivtv_remove(struct pci_dev *pci_dev)
 		release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
 
 	pci_disable_device(itv->dev);
+	for (i = 0; i < IVTV_VBI_FRAMES; i++)
+		kfree(itv->vbi.sliced_mpeg_data[i]);
 
-	IVTV_INFO("Removed %s, card #%d\n", itv->card_name, itv->num);
+	printk(KERN_INFO "ivtv: Removed %s\n", itv->card_name);
+	kfree(itv);
 }
 
 /* define a pci_driver for card detection */
@@ -1427,54 +1363,36 @@ static struct pci_driver ivtv_pci_driver = {
 
 static int module_start(void)
 {
-	printk(KERN_INFO "ivtv:  Start initialization, version %s\n", IVTV_VERSION);
-
-	memset(ivtv_cards, 0, sizeof(ivtv_cards));
+	printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION);
 
 	/* Validate parameters */
 	if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
-		printk(KERN_ERR "ivtv:  Exiting, ivtv_first_minor must be between 0 and %d\n",
+		printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n",
 		     IVTV_MAX_CARDS - 1);
 		return -1;
 	}
 
 	if (ivtv_debug < 0 || ivtv_debug > 2047) {
 		ivtv_debug = 0;
-		printk(KERN_INFO "ivtv:  Debug value must be >= 0 and <= 2047\n");
+		printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n");
 	}
 
 	if (pci_register_driver(&ivtv_pci_driver)) {
-		printk(KERN_ERR "ivtv:  Error detecting PCI card\n");
+		printk(KERN_ERR "ivtv: Error detecting PCI card\n");
 		return -ENODEV;
 	}
-	printk(KERN_INFO "ivtv:  End initialization\n");
+	printk(KERN_INFO "ivtv: End initialization\n");
 	return 0;
 }
 
 static void module_cleanup(void)
 {
-	int i, j;
-
 	pci_unregister_driver(&ivtv_pci_driver);
-
-	spin_lock(&ivtv_cards_lock);
-	for (i = 0; i < ivtv_cards_active; i++) {
-		if (ivtv_cards[i] == NULL)
-			continue;
-		for (j = 0; j < IVTV_VBI_FRAMES; j++) {
-			kfree(ivtv_cards[i]->vbi.sliced_mpeg_data[j]);
-		}
-		kfree(ivtv_cards[i]);
-	}
-	spin_unlock(&ivtv_cards_lock);
 }
 
 /* Note: These symbols are exported because they are used by the ivtvfb
    framebuffer module and an infrared module for the IR-blaster. */
 EXPORT_SYMBOL(ivtv_set_irq_mask);
-EXPORT_SYMBOL(ivtv_cards_active);
-EXPORT_SYMBOL(ivtv_cards);
-EXPORT_SYMBOL(ivtv_cards_lock);
 EXPORT_SYMBOL(ivtv_api);
 EXPORT_SYMBOL(ivtv_vapi);
 EXPORT_SYMBOL(ivtv_vapi_result);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 3733b2afec5f..ce8d9b74357e 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -61,6 +61,7 @@
 #include <linux/dvb/audio.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
 #include <media/tuner.h>
 #include <media/cx2341x.h>
 
@@ -113,9 +114,6 @@
 #define IVTV_REG_VPU 			(0x9058)
 #define IVTV_REG_APU 			(0xA064)
 
-/* i2c stuff */
-#define I2C_CLIENTS_MAX 16
-
 /* debugging */
 extern int ivtv_debug;
 
@@ -132,12 +130,10 @@ extern int ivtv_debug;
 /* Flag to turn on high volume debugging */
 #define IVTV_DBGFLG_HIGHVOL (1 << 10)
 
-/* NOTE: extra space before comma in 'itv->num , ## args' is required for
-   gcc-2.95, otherwise it won't compile. */
 #define IVTV_DEBUG(x, type, fmt, args...) \
 	do { \
 		if ((x) & ivtv_debug) \
-			printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
+			v4l2_info(&itv->device, " " type ": " fmt , ##args);	\
 	} while (0)
 #define IVTV_DEBUG_WARN(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_WARN,  "warn",  fmt , ## args)
 #define IVTV_DEBUG_INFO(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_INFO,  "info",  fmt , ## args)
@@ -152,8 +148,8 @@ extern int ivtv_debug;
 
 #define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
 	do { \
-		if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
-			printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
+		if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) 	\
+			v4l2_info(&itv->device, " " type ": " fmt , ##args);	\
 	} while (0)
 #define IVTV_DEBUG_HI_WARN(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN,  "warn",  fmt , ## args)
 #define IVTV_DEBUG_HI_INFO(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO,  "info",  fmt , ## args)
@@ -167,9 +163,9 @@ extern int ivtv_debug;
 #define IVTV_DEBUG_HI_YUV(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV,   "yuv",   fmt , ## args)
 
 /* Standard kernel messages */
-#define IVTV_ERR(fmt, args...)      printk(KERN_ERR  "ivtv%d: " fmt, itv->num , ## args)
-#define IVTV_WARN(fmt, args...)     printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args)
-#define IVTV_INFO(fmt, args...)     printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args)
+#define IVTV_ERR(fmt, args...)      v4l2_err(&itv->device, fmt , ## args)
+#define IVTV_WARN(fmt, args...)     v4l2_warn(&itv->device, fmt , ## args)
+#define IVTV_INFO(fmt, args...)     v4l2_info(&itv->device, fmt , ## args)
 
 /* output modes (cx23415 only) */
 #define OUT_NONE        0
@@ -596,8 +592,6 @@ struct ivtv_card;
 /* Struct to hold info about ivtv cards */
 struct ivtv {
 	/* General fixed card data */
-	int num;			/* board number, -1 during init! */
-	char name[8];			/* board name for printk and interrupts (e.g. 'ivtv0') */
 	struct pci_dev *dev;		/* PCI device */
 	const struct ivtv_card *card;	/* card information */
 	const char *card_name;          /* full name of the card */
@@ -609,14 +603,18 @@ struct ivtv {
 	u32 v4l2_cap;			/* V4L2 capabilities of card */
 	u32 hw_flags; 			/* hardware description of the board */
 	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 *);
+	struct v4l2_subdev *sd_video;	/* controlling video decoder subdev */
+	struct v4l2_subdev *sd_audio;	/* controlling audio subdev */
+	struct v4l2_subdev *sd_muxer;	/* controlling audio muxer subdev */
 	u32 base_addr;                  /* PCI resource base address */
 	volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */
 	volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */
 	volatile void __iomem *reg_mem; /* pointer to mapped registers */
 	struct ivtv_options options; 	/* user options */
 
+	struct v4l2_device device;
+	struct v4l2_subdev sd_gpio;	/* GPIO sub-device */
+	u16 instance;
 
 	/* High-level state info */
 	unsigned long i_flags;          /* global ivtv flags */
@@ -676,7 +674,6 @@ struct ivtv {
 	struct i2c_adapter i2c_adap;
 	struct i2c_algo_bit_data i2c_algo;
 	struct i2c_client i2c_client;
-	struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];/* pointers to all I2C clients */
 	int i2c_state;                  /* i2c bit state */
 	struct mutex i2c_bus_lock;      /* lock i2c bus */
 
@@ -722,11 +719,13 @@ struct ivtv {
 	struct osd_info *osd_info;      /* ivtvfb private OSD info */
 };
 
+static inline struct ivtv *to_ivtv(struct v4l2_device *dev)
+{
+	return container_of(dev, struct ivtv, device);
+}
+
 /* Globals */
-extern struct ivtv *ivtv_cards[];
-extern int ivtv_cards_active;
 extern int ivtv_first_minor;
-extern spinlock_t ivtv_cards_lock;
 
 /*==============Prototypes==================*/
 
@@ -786,4 +785,19 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
 #define write_dec_sync(val, addr) \
 	do { write_dec(val, addr); read_dec(addr); } while (0)
 
+/* Call the specified callback for all subdevs matching hw (if 0, then
+   match them all). Ignore any errors. */
+#define ivtv_call_hw(itv, hw, o, f, args...) 				\
+	__v4l2_device_call_subdevs(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+
+#define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args)
+
+/* Call the specified callback for all subdevs matching hw (if 0, then
+   match them all). If the callback returns an error other than 0 or
+   -ENOIOCTLCMD, then return with that error code. */
+#define ivtv_call_hw_err(itv, hw, o, f, args...)  		\
+	__v4l2_device_call_subdevs_until_err(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+
+#define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args)
+
 #endif
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 1c404e454a36..5eb587592e9d 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -155,7 +155,7 @@ static void ivtv_dualwatch(struct ivtv *itv)
 
 	new_stereo_mode = itv->params.audio_properties & stereo_mask;
 	memset(&vt, 0, sizeof(vt));
-	ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, &vt);
+	ivtv_call_all(itv, tuner, g_tuner, &vt);
 	if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
 		new_stereo_mode = dual;
 
@@ -857,7 +857,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
 		/* Mark that the radio is no longer in use */
 		clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
 		/* Switch tuner to TV */
-		ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
+		ivtv_call_all(itv, tuner, s_std, itv->std);
 		/* Select correct audio input (i.e. TV tuner or Line in) */
 		ivtv_audio_set_io(itv);
 		if (itv->hw_flags & IVTV_HW_SAA711X)
@@ -865,7 +865,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
 			struct v4l2_crystal_freq crystal_freq;
 			crystal_freq.freq = SAA7115_FREQ_32_11_MHZ;
 			crystal_freq.flags = 0;
-			ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+			ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, &crystal_freq);
 		}
 		if (atomic_read(&itv->capturing) > 0) {
 			/* Undo video mute */
@@ -952,15 +952,14 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
 		/* We have the radio */
 		ivtv_mute(itv);
 		/* Switch tuner to radio */
-		ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);
+		ivtv_call_all(itv, tuner, s_radio);
 		/* Select the correct audio input (i.e. radio tuner) */
 		ivtv_audio_set_io(itv);
-		if (itv->hw_flags & IVTV_HW_SAA711X)
-		{
+		if (itv->hw_flags & IVTV_HW_SAA711X) {
 			struct v4l2_crystal_freq crystal_freq;
 			crystal_freq.freq = SAA7115_FREQ_32_11_MHZ;
 			crystal_freq.flags = SAA7115_FREQ_FL_APLL;
-			ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+			ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, &crystal_freq);
 		}
 		/* Done! Unmute and continue. */
 		ivtv_unmute(itv);
@@ -981,37 +980,18 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
 
 int ivtv_v4l2_open(struct inode *inode, struct file *filp)
 {
-	int res, x, y = 0;
+	int res;
 	struct ivtv *itv = NULL;
 	struct ivtv_stream *s = NULL;
-	int minor = iminor(inode);
-
-	/* Find which card this open was on */
-	spin_lock(&ivtv_cards_lock);
-	for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
-		if (ivtv_cards[x] == NULL)
-			continue;
-		/* find out which stream this open was on */
-		for (y = 0; y < IVTV_MAX_STREAMS; y++) {
-			s = &ivtv_cards[x]->streams[y];
-			if (s->v4l2dev && s->v4l2dev->minor == minor) {
-				itv = ivtv_cards[x];
-				break;
-			}
-		}
-	}
-	spin_unlock(&ivtv_cards_lock);
+	struct video_device *vdev = video_devdata(filp);
 
-	if (itv == NULL) {
-		/* Couldn't find a device registered
-		   on that minor, shouldn't happen! */
-		printk(KERN_WARNING "No ivtv device found on minor %d\n", minor);
-		return -ENXIO;
-	}
+	s = video_get_drvdata(vdev);
+	itv = s->itv;
 
 	mutex_lock(&itv->serialize_lock);
 	if (ivtv_init_on_first_open(itv)) {
-		IVTV_ERR("Failed to initialize on minor %d\n", minor);
+		IVTV_ERR("Failed to initialize on minor %d\n",
+				s->v4l2dev->minor);
 		mutex_unlock(&itv->serialize_lock);
 		return -ENXIO;
 	}
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index 74a44844ccaf..dc2850e87a7e 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -144,22 +144,9 @@ int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value)
 	return 0;
 }
 
-void ivtv_gpio_init(struct ivtv *itv)
+static inline struct ivtv *sd_to_ivtv(struct v4l2_subdev *sd)
 {
-	u16 pin = 0;
-
-	if (itv->card->xceive_pin)
-		pin = 1 << itv->card->xceive_pin;
-
-	if ((itv->card->gpio_init.direction | pin) == 0)
-		return;
-
-	IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
-		   read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT));
-
-	/* init output data then direction */
-	write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
-	write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
+	return container_of(sd, struct ivtv, sd_gpio);
 }
 
 static struct v4l2_queryctrl gpio_ctrl_mute = {
@@ -173,134 +160,231 @@ static struct v4l2_queryctrl gpio_ctrl_mute = {
 	.flags         = 0,
 };
 
-int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg)
+static int subdev_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
 {
-	struct v4l2_tuner *tuner = arg;
-	struct v4l2_control *ctrl = arg;
-	struct v4l2_routing *route = arg;
+	struct ivtv *itv = sd_to_ivtv(sd);
 	u16 mask, data;
 
-	switch (command) {
-	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-		mask = itv->card->gpio_audio_freq.mask;
-		switch (*(u32 *)arg) {
-		case 32000:
-			data = itv->card->gpio_audio_freq.f32000;
-			break;
-		case 44100:
-			data = itv->card->gpio_audio_freq.f44100;
-			break;
-		case 48000:
-		default:
-			data = itv->card->gpio_audio_freq.f48000;
-			break;
-		}
+	mask = itv->card->gpio_audio_freq.mask;
+	switch (freq) {
+	case 32000:
+		data = itv->card->gpio_audio_freq.f32000;
+		break;
+	case 44100:
+		data = itv->card->gpio_audio_freq.f44100;
+		break;
+	case 48000:
+	default:
+		data = itv->card->gpio_audio_freq.f48000;
 		break;
+	}
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
 
-	case VIDIOC_G_TUNER:
-		mask = itv->card->gpio_audio_detect.mask;
-		if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask))
-			tuner->rxsubchans = V4L2_TUNER_MODE_STEREO |
-			       V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
-		else
-			tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
-		return 0;
+static int subdev_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask;
+
+	mask = itv->card->gpio_audio_detect.mask;
+	if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask))
+		vt->rxsubchans = V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	else
+		vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+	return 0;
+}
 
-	case VIDIOC_S_TUNER:
-		mask = itv->card->gpio_audio_mode.mask;
-		switch (tuner->audmode) {
-		case V4L2_TUNER_MODE_LANG1:
-			data = itv->card->gpio_audio_mode.lang1;
-			break;
-		case V4L2_TUNER_MODE_LANG2:
-			data = itv->card->gpio_audio_mode.lang2;
-			break;
-		case V4L2_TUNER_MODE_MONO:
-			data = itv->card->gpio_audio_mode.mono;
-			break;
-		case V4L2_TUNER_MODE_STEREO:
-		case V4L2_TUNER_MODE_LANG1_LANG2:
-		default:
-			data = itv->card->gpio_audio_mode.stereo;
-			break;
-		}
-		break;
+static int subdev_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
 
-	case AUDC_SET_RADIO:
-		mask = itv->card->gpio_audio_input.mask;
-		data = itv->card->gpio_audio_input.radio;
+	mask = itv->card->gpio_audio_mode.mask;
+	switch (vt->audmode) {
+	case V4L2_TUNER_MODE_LANG1:
+		data = itv->card->gpio_audio_mode.lang1;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		data = itv->card->gpio_audio_mode.lang2;
+		break;
+	case V4L2_TUNER_MODE_MONO:
+		data = itv->card->gpio_audio_mode.mono;
 		break;
+	case V4L2_TUNER_MODE_STEREO:
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+	default:
+		data = itv->card->gpio_audio_mode.stereo;
+		break;
+	}
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
+
+static int subdev_s_radio(struct v4l2_subdev *sd)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
+
+	mask = itv->card->gpio_audio_input.mask;
+	data = itv->card->gpio_audio_input.radio;
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
 
-	case VIDIOC_S_STD:
-		mask = itv->card->gpio_audio_input.mask;
+static int subdev_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
+
+	mask = itv->card->gpio_audio_input.mask;
+	data = itv->card->gpio_audio_input.tuner;
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
+
+static int subdev_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
+
+	if (route->input > 2)
+		return -EINVAL;
+	mask = itv->card->gpio_audio_input.mask;
+	switch (route->input) {
+	case 0:
 		data = itv->card->gpio_audio_input.tuner;
 		break;
-
-	case VIDIOC_INT_S_AUDIO_ROUTING:
-		if (route->input > 2)
-			return -EINVAL;
-		mask = itv->card->gpio_audio_input.mask;
-		switch (route->input) {
-			case 0:
-				data = itv->card->gpio_audio_input.tuner;
-				break;
-			case 1:
-				data = itv->card->gpio_audio_input.linein;
-				break;
-			case 2:
-			default:
-				data = itv->card->gpio_audio_input.radio;
-				break;
-		}
+	case 1:
+		data = itv->card->gpio_audio_input.linein;
+		break;
+	case 2:
+	default:
+		data = itv->card->gpio_audio_input.radio;
 		break;
+	}
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
 
-	case VIDIOC_G_CTRL:
-		if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-			return -EINVAL;
-		mask = itv->card->gpio_audio_mute.mask;
-		data = itv->card->gpio_audio_mute.mute;
-		ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data;
-		return 0;
+static int subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
 
-	case VIDIOC_S_CTRL:
-		if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-			return -EINVAL;
-		mask = itv->card->gpio_audio_mute.mask;
-		data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0;
-		break;
+	if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+		return -EINVAL;
+	mask = itv->card->gpio_audio_mute.mask;
+	data = itv->card->gpio_audio_mute.mute;
+	ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data;
+	return 0;
+}
 
-	case VIDIOC_QUERYCTRL:
-	{
-		struct v4l2_queryctrl *qc = arg;
+static int subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
 
-		if (qc->id != V4L2_CID_AUDIO_MUTE)
-			return -EINVAL;
-		*qc = gpio_ctrl_mute;
-		return 0;
-	}
+	if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+		return -EINVAL;
+	mask = itv->card->gpio_audio_mute.mask;
+	data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0;
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
+
+static int subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+	if (qc->id != V4L2_CID_AUDIO_MUTE)
+		return -EINVAL;
+	*qc = gpio_ctrl_mute;
+	return 0;
+}
+
+static int subdev_log_status(struct v4l2_subdev *sd)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
 
-	case VIDIOC_LOG_STATUS:
-		IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n",
+	IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n",
 			read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT),
 			read_reg(IVTV_REG_GPIO_IN));
-		return 0;
+	return 0;
+}
 
-	case VIDIOC_INT_S_VIDEO_ROUTING:
-		if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */
-			return -EINVAL;
-		mask = itv->card->gpio_video_input.mask;
-		if  (route->input == 0)
-			data = itv->card->gpio_video_input.tuner;
-		else if  (route->input == 1)
-			data = itv->card->gpio_video_input.composite;
-		else
-			data = itv->card->gpio_video_input.svideo;
-		break;
+static int subdev_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+	struct ivtv *itv = sd_to_ivtv(sd);
+	u16 mask, data;
 
-	default:
+	if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */
 		return -EINVAL;
-	}
+	mask = itv->card->gpio_video_input.mask;
+	if  (route->input == 0)
+		data = itv->card->gpio_video_input.tuner;
+	else if  (route->input == 1)
+		data = itv->card->gpio_video_input.composite;
+	else
+		data = itv->card->gpio_video_input.svideo;
 	if (mask)
 		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
 	return 0;
 }
+
+static const struct v4l2_subdev_core_ops subdev_core_ops = {
+	.log_status = subdev_log_status,
+	.g_ctrl = subdev_g_ctrl,
+	.s_ctrl = subdev_s_ctrl,
+	.queryctrl = subdev_queryctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = {
+	.s_std = subdev_s_std,
+	.s_radio = subdev_s_radio,
+	.g_tuner = subdev_g_tuner,
+	.s_tuner = subdev_s_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops subdev_audio_ops = {
+	.s_clock_freq = subdev_s_clock_freq,
+	.s_routing = subdev_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops subdev_video_ops = {
+	.s_routing = subdev_s_video_routing,
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+	.core = &subdev_core_ops,
+	.tuner = &subdev_tuner_ops,
+	.audio = &subdev_audio_ops,
+	.video = &subdev_video_ops,
+};
+
+int ivtv_gpio_init(struct ivtv *itv)
+{
+	u16 pin = 0;
+
+	if (itv->card->xceive_pin)
+		pin = 1 << itv->card->xceive_pin;
+
+	if ((itv->card->gpio_init.direction | pin) == 0)
+		return 0;
+
+	IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
+		   read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT));
+
+	/* init output data then direction */
+	write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
+	write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
+	v4l2_subdev_init(&itv->sd_gpio, &subdev_ops);
+	snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->device.name);
+	itv->sd_gpio.grp_id = IVTV_HW_GPIO;
+	return v4l2_device_register_subdev(&itv->device, &itv->sd_gpio);
+}
diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h
index 48b6291613a2..0b5d19c8ecb4 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.h
+++ b/drivers/media/video/ivtv/ivtv-gpio.h
@@ -22,9 +22,8 @@
 #define IVTV_GPIO_H
 
 /* GPIO stuff */
-void ivtv_gpio_init(struct ivtv *itv);
+int ivtv_gpio_init(struct ivtv *itv);
 void ivtv_reset_ir_gpio(struct ivtv *itv);
 int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value);
-int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg);
 
 #endif
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 41dbbe9621a1..ca1d9557945e 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -90,26 +90,6 @@
 #define IVTV_M52790_I2C_ADDR      	0x48
 
 /* This array should match the IVTV_HW_ defines */
-static const u8 hw_driverids[] = {
-	I2C_DRIVERID_CX25840,
-	I2C_DRIVERID_SAA711X,
-	I2C_DRIVERID_SAA7127,
-	I2C_DRIVERID_MSP3400,
-	I2C_DRIVERID_TUNER,
-	I2C_DRIVERID_WM8775,
-	I2C_DRIVERID_CS53L32A,
-	I2C_DRIVERID_TVEEPROM,
-	I2C_DRIVERID_SAA711X,
-	I2C_DRIVERID_UPD64031A,
-	I2C_DRIVERID_UPD64083,
-	I2C_DRIVERID_SAA717X,
-	I2C_DRIVERID_WM8739,
-	I2C_DRIVERID_VP27SMPX,
-	I2C_DRIVERID_M52790,
-	0 		/* IVTV_HW_GPIO dummy driver ID */
-};
-
-/* This array should match the IVTV_HW_ defines */
 static const u8 hw_addrs[] = {
 	IVTV_CX25840_I2C_ADDR,
 	IVTV_SAA7115_I2C_ADDR,
@@ -130,6 +110,26 @@ static const u8 hw_addrs[] = {
 };
 
 /* This array should match the IVTV_HW_ defines */
+static const char *hw_modules[] = {
+	"cx25840",
+	"saa7115",
+	"saa7127",
+	"msp3400",
+	"tuner",
+	"wm8775",
+	"cs53l32a",
+	NULL,
+	"saa7115",
+	"upd64031a",
+	"upd64083",
+	"saa717x",
+	"wm8739",
+	"vp27smpx",
+	"m52790",
+	NULL
+};
+
+/* This array should match the IVTV_HW_ defines */
 static const char * const hw_devicenames[] = {
 	"cx25840",
 	"saa7115",
@@ -151,80 +151,58 @@ static const char * const hw_devicenames[] = {
 
 int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
 {
-	struct i2c_board_info info;
-	struct i2c_client *c;
-	u8 id;
-	int i;
+	struct v4l2_subdev *sd;
+	struct i2c_adapter *adap = &itv->i2c_adap;
+	const char *mod = hw_modules[idx];
+	const char *type = hw_devicenames[idx];
+	u32 hw = 1 << idx;
 
-	IVTV_DEBUG_I2C("i2c client register\n");
-	if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
+	if (idx >= ARRAY_SIZE(hw_addrs))
 		return -1;
-	id = hw_driverids[idx];
-	memset(&info, 0, sizeof(info));
-	strlcpy(info.type, hw_devicenames[idx], sizeof(info.type));
-	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");
-		return -ENOMEM;
+	if (hw == IVTV_HW_TUNER) {
+		/* special tuner handling */
+		sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+				itv->card_i2c->radio);
+		if (sd)
+			sd->grp_id = 1 << idx;
+		sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+				itv->card_i2c->demod);
+		if (sd)
+			sd->grp_id = 1 << idx;
+		sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+				itv->card_i2c->tv);
+		if (sd)
+			sd->grp_id = 1 << idx;
+		return sd ? 0 : -1;
 	}
+	if (!hw_addrs[idx])
+		return -1;
+	if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) {
+		unsigned short addrs[2] = { hw_addrs[idx], I2C_CLIENT_END };
 
-	if (id != I2C_DRIVERID_TUNER) {
-		if (id == I2C_DRIVERID_UPD64031A ||
-		    id == I2C_DRIVERID_UPD64083) {
-			unsigned short addrs[2] = { info.addr, I2C_CLIENT_END };
-
-			c = i2c_new_probed_device(&itv->i2c_adap, &info, addrs);
-		} else
-			c = i2c_new_device(&itv->i2c_adap, &info);
-		if (c && c->driver == NULL)
-			i2c_unregister_device(c);
-		else if (c)
-			itv->i2c_clients[i] = c;
-		return itv->i2c_clients[i] ? 0 : -ENODEV;
+		sd = v4l2_i2c_new_probed_subdev(adap, mod, type, addrs);
+	} else {
+		sd = v4l2_i2c_new_subdev(adap, mod, type, hw_addrs[idx]);
 	}
-
-	/* 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;
+	if (sd)
+		sd->grp_id = 1 << idx;
+	return sd ? 0 : -1;
 }
 
-static int detach_inform(struct i2c_client *client)
+struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw)
 {
-	int i;
-	struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter);
+	struct v4l2_subdev *result = NULL;
+	struct v4l2_subdev *sd;
 
-	IVTV_DEBUG_I2C("i2c client detach\n");
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (itv->i2c_clients[i] == client) {
-			itv->i2c_clients[i] = NULL;
+	spin_lock(&itv->device.lock);
+	v4l2_device_for_each_subdev(sd, &itv->device) {
+		if (sd->grp_id == hw) {
+			result = sd;
 			break;
 		}
 	}
-	IVTV_DEBUG_I2C("i2c detach [client=%s,%s]\n",
-		   client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
-
-	return 0;
+	spin_unlock(&itv->device.lock);
+	return result;
 }
 
 /* Set the serial clock line to the desired state */
@@ -494,7 +472,8 @@ static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data,
    intervening stop condition */
 static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
 {
-	struct ivtv *itv = i2c_get_adapdata(i2c_adap);
+	struct v4l2_device *drv = i2c_get_adapdata(i2c_adap);
+	struct ivtv *itv = to_ivtv(drv);
 	int retval;
 	int i;
 
@@ -530,8 +509,6 @@ static struct i2c_adapter ivtv_i2c_adap_hw_template = {
 	.id = I2C_HW_B_CX2341X,
 	.algo = &ivtv_algo,
 	.algo_data = NULL,			/* filled from template */
-	.client_register = attach_inform,
-	.client_unregister = detach_inform,
 	.owner = THIS_MODULE,
 };
 
@@ -583,8 +560,6 @@ static struct i2c_adapter ivtv_i2c_adap_template = {
 	.id = I2C_HW_B_CX2341X,
 	.algo = NULL,                   /* set by i2c-algo-bit */
 	.algo_data = NULL,              /* filled from template */
-	.client_register = attach_inform,
-	.client_unregister = detach_inform,
 	.owner = THIS_MODULE,
 };
 
@@ -601,160 +576,6 @@ static struct i2c_client ivtv_i2c_client_template = {
 	.name = "ivtv internal",
 };
 
-int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg)
-{
-	struct i2c_client *client;
-	int retval;
-	int i;
-
-	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 || client->driver == NULL ||
-		    client->driver->command == NULL)
-			continue;
-		if (addr == client->addr) {
-			retval = client->driver->command(client, cmd, arg);
-			return retval;
-		}
-	}
-	if (cmd != VIDIOC_G_CHIP_IDENT)
-		IVTV_ERR("i2c addr 0x%02x not found for command 0x%x\n", addr, cmd);
-	return -ENODEV;
-}
-
-/* Find the i2c device based on the driver ID and return
-   its i2c address or -ENODEV if no matching device was found. */
-static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id)
-{
-	struct i2c_client *client;
-	int retval = -ENODEV;
-	int i;
-
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		client = itv->i2c_clients[i];
-		if (client == NULL || client->driver == NULL)
-			continue;
-		if (id == client->driver->id) {
-			retval = client->addr;
-			break;
-		}
-	}
-	return retval;
-}
-
-/* Find the i2c device name matching the DRIVERID */
-static const char *ivtv_i2c_id_name(u32 id)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
-		if (hw_driverids[i] == id)
-			return hw_devicenames[i];
-	return "unknown device";
-}
-
-/* Find the i2c device name matching the IVTV_HW_ flag */
-static const char *ivtv_i2c_hw_name(u32 hw)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
-		if (1 << i == hw)
-			return hw_devicenames[i];
-	return "unknown device";
-}
-
-/* Find the i2c device matching the IVTV_HW_ flag and return
-   its i2c address or -ENODEV if no matching device was found. */
-int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
-		if (1 << i == hw)
-			return ivtv_i2c_id_addr(itv, hw_driverids[i]);
-	return -ENODEV;
-}
-
-/* Calls i2c device based on IVTV_HW_ flag. If hw == 0, then do nothing.
-   If hw == IVTV_HW_GPIO then call the gpio handler. */
-int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg)
-{
-	int addr;
-
-	if (hw == IVTV_HW_GPIO)
-		return ivtv_gpio(itv, cmd, arg);
-	if (hw == 0)
-		return 0;
-
-	addr = ivtv_i2c_hw_addr(itv, hw);
-	if (addr < 0) {
-		IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x\n",
-			       hw, ivtv_i2c_hw_name(hw), cmd);
-		return addr;
-	}
-	return ivtv_call_i2c_client(itv, addr, cmd, arg);
-}
-
-/* Calls i2c device based on I2C driver ID. */
-int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg)
-{
-	int addr;
-
-	addr = ivtv_i2c_id_addr(itv, id);
-	if (addr < 0) {
-		if (cmd != VIDIOC_G_CHIP_IDENT)
-			IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x\n",
-				id, ivtv_i2c_id_name(id), cmd);
-		return addr;
-	}
-	return ivtv_call_i2c_client(itv, addr, cmd, arg);
-}
-
-int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-	return ivtv_call_i2c_client(itv, IVTV_CX25840_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-	return ivtv_call_i2c_client(itv, IVTV_SAA7115_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-	return ivtv_call_i2c_client(itv, IVTV_SAA7127_I2C_ADDR, cmd, arg);
-}
-EXPORT_SYMBOL(ivtv_saa7127);
-
-int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-	return ivtv_call_i2c_client(itv, IVTV_SAA717x_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-	return ivtv_call_i2c_client(itv, IVTV_UPD64031A_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-	return ivtv_call_i2c_client(itv, IVTV_UPD64083_I2C_ADDR, cmd, arg);
-}
-
-/* broadcast cmd for all I2C clients and for the gpio subsystem */
-void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-	if (itv->i2c_adap.algo == NULL) {
-		IVTV_ERR("Adapter is not set");
-		return;
-	}
-	i2c_clients_command(&itv->i2c_adap, cmd, arg);
-	if (itv->hw_flags & IVTV_HW_GPIO)
-		ivtv_gpio(itv, cmd, arg);
-}
-
 /* init + register i2c algo-bit adapter */
 int init_ivtv_i2c(struct ivtv *itv)
 {
@@ -763,10 +584,9 @@ int init_ivtv_i2c(struct ivtv *itv)
 	/* 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_devicenames) != ARRAY_SIZE(hw_addrs) ||
-	    IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
-	    hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+	if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
+	    ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_modules) ||
+	    IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1))) {
 		IVTV_ERR("Mismatched I2C hardware arrays\n");
 		return -ENODEV;
 	}
@@ -783,8 +603,8 @@ int init_ivtv_i2c(struct ivtv *itv)
 	itv->i2c_adap.algo_data = &itv->i2c_algo;
 
 	sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
-		itv->num);
-	i2c_set_adapdata(&itv->i2c_adap, itv);
+		itv->instance);
+	i2c_set_adapdata(&itv->i2c_adap, &itv->device);
 
 	memcpy(&itv->i2c_client, &ivtv_i2c_client_template,
 	       sizeof(struct i2c_client));
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h
index 022978cf533d..396928a06a54 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.h
+++ b/drivers/media/video/ivtv/ivtv-i2c.h
@@ -21,19 +21,8 @@
 #ifndef IVTV_I2C_H
 #define IVTV_I2C_H
 
-int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg);
-
-int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw);
-int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg);
-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);
+struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw);
 
 /* init + register i2c algo-bit adapter */
 int init_ivtv_i2c(struct ivtv *itv);
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 4bae38d21ef6..cd990a4b81a9 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -393,7 +393,7 @@ static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo
 		return 0;
 	}
 
-	itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
+	v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
 	vbifmt->service_set = ivtv_get_service_set(vbifmt);
 	return 0;
 }
@@ -581,7 +581,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
 	p->height = h;
 	if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
 		fmt->fmt.pix.width /= 2;
-	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+	v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
 	return ivtv_g_fmt_vid_cap(file, fh, fmt);
 }
 
@@ -593,7 +593,7 @@ static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f
 		return -EBUSY;
 	itv->vbi.sliced_in->service_set = 0;
 	itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
-	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+	v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
 	return ivtv_g_fmt_vbi_cap(file, fh, fmt);
 }
 
@@ -611,7 +611,7 @@ static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo
 	if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
 		return -EBUSY;
 	itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
-	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+	v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
 	memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
 	return 0;
 }
@@ -685,18 +685,17 @@ static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_chip_ident
 			chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
 		return 0;
 	}
-	if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-		return ivtv_i2c_id(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
-	if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
-		return ivtv_call_i2c_client(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
-	return -EINVAL;
+	if (chip->match_type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+	    chip->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+	/* TODO: is this correct? */
+	return ivtv_call_all_err(itv, core, g_chip_ident, chip);
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
 {
 	struct v4l2_register *regs = arg;
-	unsigned long flags;
 	volatile u8 __iomem *reg_start;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -711,12 +710,10 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
 	else
 		return -EINVAL;
 
-	spin_lock_irqsave(&ivtv_cards_lock, flags);
 	if (cmd == VIDIOC_DBG_G_REGISTER)
 		regs->val = readl(regs->reg + reg_start);
 	else
 		writel(regs->val, regs->reg + reg_start);
-	spin_unlock_irqrestore(&ivtv_cards_lock, flags);
 	return 0;
 }
 
@@ -726,9 +723,10 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_register *re
 
 	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
 		return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg);
-	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-		return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
-	return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
+	/* TODO: subdev errors should not be ignored, this should become a
+	   subdev helper function. */
+	ivtv_call_all(itv, core, g_register, reg);
+	return 0;
 }
 
 static int ivtv_s_register(struct file *file, void *fh, struct v4l2_register *reg)
@@ -737,9 +735,10 @@ static int ivtv_s_register(struct file *file, void *fh, struct v4l2_register *re
 
 	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
 		return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg);
-	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-		return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
-	return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
+	/* TODO: subdev errors should not be ignored, this should become a
+	   subdev helper function. */
+	ivtv_call_all(itv, core, s_register, reg);
+	return 0;
 }
 #endif
 
@@ -884,12 +883,6 @@ static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 
 	streamtype = id->type;
 
-	if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
-		printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
-		/* Should be replaced */
-		/* v4l_printk_ioctl(VIDIOC_S_CROP); */
-	}
-
 	if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
 	    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
 		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
@@ -1050,7 +1043,7 @@ static int ivtv_s_output(struct file *file, void *fh, unsigned int outp)
 	itv->active_output = outp;
 	route.input = SAA7127_INPUT_TYPE_NORMAL;
 	route.output = itv->card->video_outputs[outp].video_output;
-	ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing, &route);
 
 	return 0;
 }
@@ -1062,7 +1055,7 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *
 	if (vf->tuner != 0)
 		return -EINVAL;
 
-	ivtv_call_i2c_clients(itv, VIDIOC_G_FREQUENCY, vf);
+	ivtv_call_all(itv, tuner, g_frequency, vf);
 	return 0;
 }
 
@@ -1075,7 +1068,7 @@ int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
 
 	ivtv_mute(itv);
 	IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
-	ivtv_call_i2c_clients(itv, VIDIOC_S_FREQUENCY, vf);
+	ivtv_call_all(itv, tuner, s_frequency, vf);
 	ivtv_unmute(itv);
 	return 0;
 }
@@ -1123,14 +1116,14 @@ int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
 	IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
 
 	/* Tuner */
-	ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
+	ivtv_call_all(itv, tuner, s_std, itv->std);
 
 	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
 		/* set display standard */
 		itv->std_out = *std;
 		itv->is_out_60hz = itv->is_60hz;
 		itv->is_out_50hz = itv->is_50hz;
-		ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out);
+		ivtv_call_all(itv, video, s_std_output, itv->std_out);
 		ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
 		itv->main_rect.left = itv->main_rect.top = 0;
 		itv->main_rect.width = 720;
@@ -1154,7 +1147,7 @@ static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 	if (vt->index != 0)
 		return -EINVAL;
 
-	ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt);
+	ivtv_call_all(itv, tuner, s_tuner, vt);
 
 	return 0;
 }
@@ -1166,7 +1159,7 @@ static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 	if (vt->index != 0)
 		return -EINVAL;
 
-	ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
+	ivtv_call_all(itv, tuner, g_tuner, vt);
 
 	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
 		strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
@@ -1444,14 +1437,15 @@ static int ivtv_log_status(struct file *file, void *fh)
 	struct v4l2_audio audin;
 	int i;
 
-	IVTV_INFO("=================  START STATUS CARD #%d  =================\n", itv->num);
+	IVTV_INFO("=================  START STATUS CARD #%d  =================\n",
+		       itv->instance);
 	IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
 	if (itv->hw_flags & IVTV_HW_TVEEPROM) {
 		struct tveeprom tv;
 
 		ivtv_read_eeprom(itv, &tv);
 	}
-	ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
+	ivtv_call_all(itv, core, log_status);
 	ivtv_get_input(itv, itv->active_input, &vidin);
 	ivtv_get_audio_input(itv, itv->audio_input, &audin);
 	IVTV_INFO("Video Input:  %s\n", vidin.name);
@@ -1518,7 +1512,7 @@ static int ivtv_log_status(struct file *file, void *fh)
 	}
 	IVTV_INFO("Tuner:  %s\n",
 		test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
-	cx2341x_log_status(&itv->params, itv->name);
+	cx2341x_log_status(&itv->params, itv->device.name);
 	IVTV_INFO("Status flags:    0x%08lx\n", itv->i_flags);
 	for (i = 0; i < IVTV_MAX_STREAMS; i++) {
 		struct ivtv_stream *s = &itv->streams[i];
@@ -1530,8 +1524,11 @@ static int ivtv_log_status(struct file *file, void *fh)
 				(s->buffers * s->buf_size) / 1024, s->buffers);
 	}
 
-	IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
-	IVTV_INFO("==================  END STATUS CARD #%d  ==================\n", itv->num);
+	IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n",
+			(long long)itv->mpg_data_received,
+			(long long)itv->vbi_data_inserted);
+	IVTV_INFO("==================  END STATUS CARD #%d  ==================\n",
+			itv->instance);
 
 	return 0;
 }
@@ -1736,7 +1733,7 @@ static int ivtv_default(struct file *file, void *fh, int cmd, void *arg)
 	case VIDIOC_INT_S_AUDIO_ROUTING: {
 		struct v4l2_routing *route = arg;
 
-		ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
+		ivtv_call_hw(itv, itv->card->hw_audio, audio, s_routing, route);
 		break;
 	}
 
@@ -1746,7 +1743,7 @@ static int ivtv_default(struct file *file, void *fh, int cmd, void *arg)
 		if ((val == 0 && itv->options.newi2c) || (val & 0x01))
 			ivtv_reset_ir_gpio(itv);
 		if (val & 0x02)
-			itv->video_dec_func(itv, cmd, NULL);
+			v4l2_subdev_call(itv->sd_video, core, reset, 0);
 		break;
 	}
 
diff --git a/drivers/media/video/ivtv/ivtv-routing.c b/drivers/media/video/ivtv/ivtv-routing.c
index 05564919b57f..3fd302294497 100644
--- a/drivers/media/video/ivtv/ivtv-routing.c
+++ b/drivers/media/video/ivtv/ivtv-routing.c
@@ -47,13 +47,13 @@ void ivtv_audio_set_io(struct ivtv *itv)
 	route.output = 0;
 	if (itv->card->hw_muxer & IVTV_HW_M52790)
 		route.output = M52790_OUT_STEREO;
-	ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+	v4l2_subdev_call(itv->sd_muxer, audio, s_routing, &route);
 
 	route.input = in->audio_input;
 	route.output = 0;
 	if (itv->card->hw_audio & IVTV_HW_MSP34XX)
 		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
-	ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+	ivtv_call_hw(itv, itv->card->hw_audio, audio, s_routing, &route);
 }
 
 /* Selects the video input and output according to the current
@@ -66,7 +66,7 @@ void ivtv_video_set_io(struct ivtv *itv)
 
 	route.input = itv->card->video_inputs[inp].video_input;
 	route.output = 0;
-	itv->video_dec_func(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+	v4l2_subdev_call(itv->sd_video, video, s_routing, &route);
 
 	type = itv->card->video_inputs[inp].video_type;
 
@@ -79,7 +79,7 @@ void ivtv_video_set_io(struct ivtv *itv)
 	}
 
 	if (itv->card->hw_video & IVTV_HW_GPIO)
-		ivtv_gpio(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+		ivtv_call_hw(itv, IVTV_HW_GPIO, video, s_routing, &route);
 
 	if (itv->card->hw_video & IVTV_HW_UPD64031A) {
 		if (type == IVTV_CARD_INPUT_VID_TUNER ||
@@ -92,7 +92,7 @@ void ivtv_video_set_io(struct ivtv *itv)
 		}
 		route.input |= itv->card->gr_config;
 
-		ivtv_upd64031a(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+		ivtv_call_hw(itv, IVTV_HW_UPD64031A, video, s_routing, &route);
 	}
 
 	if (itv->card->hw_video & IVTV_HW_UPD6408X) {
@@ -110,6 +110,6 @@ void ivtv_video_set_io(struct ivtv *itv)
 		    route.input |= UPD64083_EXT_Y_ADC;
 		  }
 		}
-		ivtv_upd64083(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+		ivtv_call_hw(itv, IVTV_HW_UPD6408X, video, s_routing, &route);
 	}
 }
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 9b7aa79eb267..f77d764707b2 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -172,7 +172,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
 {
 	struct ivtv_stream *s = &itv->streams[type];
 	int num_offset = ivtv_stream_info[type].num_offset;
-	int num = itv->num + ivtv_first_minor + num_offset;
+	int num = itv->instance + ivtv_first_minor + num_offset;
 
 	/* These four fields are always initialized. If v4l2dev == NULL, then
 	   this stream is not in use. In that case no other fields but these
@@ -205,11 +205,11 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
 		return -ENOMEM;
 	}
 
-	snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s",
-			itv->num, s->name);
+	snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "%s %s",
+			itv->device.name, s->name);
 
 	s->v4l2dev->num = num;
-	s->v4l2dev->parent = &itv->dev->dev;
+	s->v4l2dev->v4l2_dev = &itv->device;
 	s->v4l2dev->fops = ivtv_stream_info[type].fops;
 	s->v4l2dev->release = video_device_release;
 	s->v4l2dev->tvnorms = V4L2_STD_ALL;
@@ -260,6 +260,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
 		if (s_mpg->v4l2dev)
 			num = s_mpg->v4l2dev->num + ivtv_stream_info[type].num_offset;
 	}
+	video_set_drvdata(s->v4l2dev, s);
 
 	/* Register device. First try the desired minor, then any free one. */
 	if (video_register_device(s->v4l2dev, vfl_type, num)) {
@@ -343,7 +344,7 @@ static void ivtv_vbi_setup(struct ivtv *itv)
 	ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
 
 	/* setup VBI registers */
-	itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
+	v4l2_subdev_call(itv->sd_video, video, s_fmt, &itv->vbi.in);
 
 	/* determine number of lines and total number of VBI bytes.
 	   A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
@@ -577,10 +578,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
 		clear_bit(IVTV_F_I_EOS, &itv->i_flags);
 
 		/* Initialize Digitizer for Capture */
-		itv->video_dec_func(itv, VIDIOC_STREAMOFF, NULL);
+		v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
 		ivtv_msleep_timeout(300, 1);
 		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-		itv->video_dec_func(itv, VIDIOC_STREAMON, NULL);
+		v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
 	}
 
 	/* begin_capture */
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index 4a37a7d2e69d..5c5d1c462fef 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -21,6 +21,7 @@
 #include "ivtv-i2c.h"
 #include "ivtv-ioctl.h"
 #include "ivtv-queue.h"
+#include "ivtv-cards.h"
 #include "ivtv-vbi.h"
 
 static void ivtv_set_vps(struct ivtv *itv, int enabled)
@@ -37,7 +38,7 @@ static void ivtv_set_vps(struct ivtv *itv, int enabled)
 	data.data[9] = itv->vbi.vps_payload.data[2];
 	data.data[10] = itv->vbi.vps_payload.data[3];
 	data.data[11] = itv->vbi.vps_payload.data[4];
-	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
 }
 
 static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
@@ -51,12 +52,12 @@ static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
 	data.line = (mode & 1) ? 21 : 0;
 	data.data[0] = cc->odd[0];
 	data.data[1] = cc->odd[1];
-	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
 	data.field = 1;
 	data.line = (mode & 2) ? 21 : 0;
 	data.data[0] = cc->even[0];
 	data.data[1] = cc->even[1];
-	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
 }
 
 static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
@@ -79,7 +80,7 @@ static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
 	data.line = enabled ? 23 : 0;
 	data.data[0] = mode & 0xff;
 	data.data[1] = (mode >> 8) & 0xff;
-	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+	ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
 }
 
 static int odd_parity(u8 c)
@@ -313,7 +314,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8
 			continue;
 		}
 		vbi.p = p + 4;
-		itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
+		v4l2_subdev_call(itv->sd_video, video, decode_vbi_line, &vbi);
 		if (vbi.type && !(lines & (1 << vbi.line))) {
 			lines |= 1 << vbi.line;
 			itv->vbi.sliced_data[line].id = vbi.type;
@@ -437,7 +438,7 @@ void ivtv_vbi_work_handler(struct ivtv *itv)
 			data.id = V4L2_SLICED_WSS_625;
 			data.field = 0;
 
-			if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+			if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
 				ivtv_set_wss(itv, 1, data.data[0] & 0xf);
 				vi->wss_missing_cnt = 0;
 			} else if (vi->wss_missing_cnt == 4) {
@@ -451,13 +452,13 @@ void ivtv_vbi_work_handler(struct ivtv *itv)
 
 			data.id = V4L2_SLICED_CAPTION_525;
 			data.field = 0;
-			if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+			if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
 				mode |= 1;
 				cc.odd[0] = data.data[0];
 				cc.odd[1] = data.data[1];
 			}
 			data.field = 1;
-			if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+			if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
 				mode |= 2;
 				cc.even[0] = data.data[0];
 				cc.even[1] = data.data[1];
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 921e281876f8..36abd2aef6f1 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -48,6 +48,7 @@
 #endif
 
 #include "ivtv-driver.h"
+#include "ivtv-cards.h"
 #include "ivtv-i2c.h"
 #include "ivtv-udma.h"
 #include "ivtv-mailbox.h"
@@ -121,15 +122,15 @@ MODULE_LICENSE("GPL");
 #define IVTVFB_DEBUG(x, type, fmt, args...) \
 	do { \
 		if ((x) & ivtvfb_debug) \
-			printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \
+			printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->instance , ## args); \
 	} while (0)
 #define IVTVFB_DEBUG_WARN(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
 #define IVTVFB_DEBUG_INFO(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
 
 /* Standard kernel messages */
-#define IVTVFB_ERR(fmt, args...)   printk(KERN_ERR  "ivtvfb%d: " fmt, itv->num , ## args)
-#define IVTVFB_WARN(fmt, args...)  printk(KERN_WARNING  "ivtvfb%d: " fmt, itv->num , ## args)
-#define IVTVFB_INFO(fmt, args...)  printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args)
+#define IVTVFB_ERR(fmt, args...)   printk(KERN_ERR  "ivtvfb%d: " fmt, itv->instance , ## args)
+#define IVTVFB_WARN(fmt, args...)  printk(KERN_WARNING  "ivtvfb%d: " fmt, itv->instance , ## args)
+#define IVTVFB_INFO(fmt, args...)  printk(KERN_INFO "ivtvfb%d: " fmt, itv->instance , ## args)
 
 /* --------------------------------------------------------------------- */
 
@@ -895,16 +896,16 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)
 	switch (blank_mode) {
 	case FB_BLANK_UNBLANK:
 		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
-		ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
 		break;
 	case FB_BLANK_NORMAL:
 	case FB_BLANK_HSYNC_SUSPEND:
 	case FB_BLANK_VSYNC_SUSPEND:
 		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
-		ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
 		break;
 	case FB_BLANK_POWERDOWN:
-		ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
 		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
 		break;
 	}
@@ -1188,10 +1189,45 @@ static int ivtvfb_init_card(struct ivtv *itv)
 
 }
 
+static int __init ivtvfb_callback_init(struct device *dev, void *p)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+	struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
+
+	if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+		if (ivtvfb_init_card(itv) == 0) {
+			IVTVFB_INFO("Framebuffer registered on %s\n",
+					itv->device.name);
+			(*(int *)p)++;
+		}
+	}
+	return 0;
+}
+
+static int ivtvfb_callback_cleanup(struct device *dev, void *p)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+	struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
+
+	if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+		if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
+			IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
+				       itv->instance);
+			return 0;
+		}
+		IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
+		ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
+		ivtvfb_release_buffers(itv);
+		itv->osd_video_pbase = 0;
+	}
+	return 0;
+}
+
 static int __init ivtvfb_init(void)
 {
-	struct ivtv *itv;
-	int i, registered = 0;
+	struct device_driver *drv;
+	int registered = 0;
+	int err;
 
 	if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
 		printk(KERN_ERR "ivtvfb:  ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
@@ -1199,20 +1235,11 @@ static int __init ivtvfb_init(void)
 		return -EINVAL;
 	}
 
-	/* Locate & initialise all cards supporting an OSD. */
-	for (i = 0; i < ivtv_cards_active; i++) {
-		if (ivtvfb_card_id != -1 && i != ivtvfb_card_id)
-			continue;
-		itv = ivtv_cards[i];
-		if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
-			if (ivtvfb_init_card(itv) == 0) {
-				IVTVFB_INFO("Framebuffer registered on ivtv card id %d\n", i);
-				registered++;
-			}
-		}
-	}
+	drv = driver_find("ivtv", &pci_bus_type);
+	err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
+	put_driver(drv);
 	if (!registered) {
-		printk(KERN_ERR "ivtvfb:  no cards found");
+		printk(KERN_ERR "ivtvfb:  no cards found\n");
 		return -ENODEV;
 	}
 	return 0;
@@ -1220,24 +1247,14 @@ static int __init ivtvfb_init(void)
 
 static void ivtvfb_cleanup(void)
 {
-	struct ivtv *itv;
-	int i;
+	struct device_driver *drv;
+	int err;
 
 	printk(KERN_INFO "ivtvfb:  Unloading framebuffer module\n");
 
-	for (i = 0; i < ivtv_cards_active; i++) {
-		itv = ivtv_cards[i];
-		if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
-			if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
-				IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n", i);
-				return;
-			}
-			IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i);
-			ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
-			ivtvfb_release_buffers(itv);
-			itv->osd_video_pbase = 0;
-		}
-	}
+	drv = driver_find("ivtv", &pci_bus_type);
+	err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
+	put_driver(drv);
 }
 
 module_init(ivtvfb_init);