V4L/DVB (11300): cx88: convert to v4l2_subdev.

Convert cx88 to use v4l2_subdev since the old i2c autoprobing mechanism
will be removed.

Added code to explicitly load tvaudio where needed. Also fix the rtc-isl1208
support: since that driver no longer supports autoprobing it has to be
loaded using the new i2c API.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 484df54..44eacfb 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -915,7 +915,7 @@
 	snprintf(name, sizeof(name), "%s/2", core->name);
 	printk("%s/2: ============  START LOG STATUS  ============\n",
 		core->name);
-	cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
+	call_all(core, core, log_status);
 	cx2341x_log_status(&dev->params, name);
 	printk("%s/2: =============  END LOG STATUS  =============\n",
 		core->name);
@@ -970,7 +970,7 @@
 
 	f->type = V4L2_TUNER_ANALOG_TV;
 	f->frequency = core->freq;
-	cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+	call_all(core, tuner, g_frequency, f);
 
 	return 0;
 }
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 348f6ef..c226fff 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -732,6 +732,8 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
+		/* Some variants use a tda9874 and so need the tvaudio module. */
+		.audio_chip     = V4L2_IDENT_TVAUDIO,
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
@@ -2985,7 +2987,7 @@
 		tea5767_cfg.tuner = TUNER_TEA5767;
 		tea5767_cfg.priv  = &ctl;
 
-		cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
+		call_all(core, tuner, s_config, &tea5767_cfg);
 		break;
 	}
 	case  CX88_BOARD_TEVII_S420:
@@ -3010,7 +3012,7 @@
 		tun_setup.type           = core->board.radio_type;
 		tun_setup.addr           = core->board.radio_addr;
 		tun_setup.tuner_callback = cx88_tuner_callback;
-		cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
+		call_all(core, tuner, s_type_addr, &tun_setup);
 		mode_mask &= ~T_RADIO;
 	}
 
@@ -3020,7 +3022,7 @@
 		tun_setup.addr           = core->board.tuner_addr;
 		tun_setup.tuner_callback = cx88_tuner_callback;
 
-		cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
+		call_all(core, tuner, s_type_addr, &tun_setup);
 	}
 
 	if (core->board.tda9887_conf) {
@@ -3029,7 +3031,7 @@
 		tda9887_cfg.tuner = TUNER_TDA9887;
 		tda9887_cfg.priv  = &core->board.tda9887_conf;
 
-		cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tda9887_cfg);
+		call_all(core, tuner, s_config, &tda9887_cfg);
 	}
 
 	if (core->board.tuner_type == TUNER_XC2028) {
@@ -3045,9 +3047,9 @@
 		xc2028_cfg.priv  = &ctl;
 		info_printk(core, "Asking xc2028/3028 to load firmware %s\n",
 			    ctl.fname);
-		cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg);
+		call_all(core, tuner, s_config, &xc2028_cfg);
 	}
-	cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
+	call_all(core, core, s_standby, 0);
 }
 
 /* ------------------------------------------------------------------ */
@@ -3202,8 +3204,30 @@
 	cx88_i2c_init(core, pci);
 
 	/* load tuner module, if needed */
-	if (TUNER_ABSENT != core->board.tuner_type)
-		request_module("tuner");
+	if (TUNER_ABSENT != core->board.tuner_type) {
+		int has_demod = (core->board.tda9887_conf & TDA9887_PRESENT);
+
+		/* I don't trust the radio_type as is stored in the card
+		   definitions, so we just probe for it.
+		   The radio_type is sometimes missing, or set to UNSET but
+		   later code configures a tea5767.
+		 */
+		v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner", "tuner",
+				v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+		if (has_demod)
+			v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner",
+				"tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+		if (core->board.tuner_addr == ADDR_UNSET) {
+			enum v4l2_i2c_tuner_type type =
+				has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+
+			v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner",
+				"tuner", v4l2_i2c_tuner_addrs(type));
+		} else {
+			v4l2_i2c_new_subdev(&core->i2c_adap,
+				"tuner", "tuner", core->board.tuner_addr);
+		}
+	}
 
 	cx88_card_setup(core);
 	cx88_ir_init(core, pci);
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 17c7dad..f2fb9f3 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -991,7 +991,7 @@
 	set_tvaudio(core);
 
 	// tell i2c chips
-	cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);
+	call_all(core, tuner, s_std, norm);
 
 	// done
 	return 0;
@@ -1059,8 +1059,11 @@
 
 	mutex_lock(&devlist);
 	cx88_ir_fini(core);
-	if (0 == core->i2c_rc)
+	if (0 == core->i2c_rc) {
+		if (core->i2c_rtc)
+			i2c_unregister_device(core->i2c_rtc);
 		i2c_del_adapter(&core->i2c_adap);
+	}
 	list_del(&core->devlist);
 	iounmap(core->lmmio);
 	cx88_devcount--;
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 08346fa..4ff4d9f 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -1168,7 +1168,7 @@
 		fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
 
 	/* Put the analog decoder in standby to keep it quiet */
-	cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
+	call_all(core, core, s_standby, 0);
 
 	/* register everything */
 	return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 4a17a75..996b4ed 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -97,39 +97,6 @@
 
 /* ----------------------------------------------------------------------- */
 
-static int attach_inform(struct i2c_client *client)
-{
-	struct v4l2_device *v4l2_dev = i2c_get_adapdata(client->adapter);
-	struct cx88_core *core = to_core(v4l2_dev);
-
-	dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
-		client->driver->driver.name, client->addr, client->name);
-	return 0;
-}
-
-static int detach_inform(struct i2c_client *client)
-{
-	struct v4l2_device *v4l2_dev = i2c_get_adapdata(client->adapter);
-	struct cx88_core *core = to_core(v4l2_dev);
-
-	dprintk(1, "i2c detach [client=%s]\n", client->name);
-	return 0;
-}
-
-void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
-{
-	if (0 != core->i2c_rc)
-		return;
-
-	if (core->gate_ctrl)
-		core->gate_ctrl(core, 1);
-
-	i2c_clients_command(&core->i2c_adap, cmd, arg);
-
-	if (core->gate_ctrl)
-		core->gate_ctrl(core, 0);
-}
-
 static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
 	.setsda  = cx8800_bit_setsda,
 	.setscl  = cx8800_bit_setscl,
@@ -175,17 +142,11 @@
 	memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
 	       sizeof(core->i2c_algo));
 
-	if (core->board.tuner_type != TUNER_ABSENT)
-		core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
-	if (core->board.mpeg & CX88_MPEG_DVB)
-		core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
 
 	core->i2c_adap.dev.parent = &pci->dev;
 	strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
 	core->i2c_adap.owner = THIS_MODULE;
 	core->i2c_adap.id = I2C_HW_B_CX2388x;
-	core->i2c_adap.client_register = attach_inform;
-	core->i2c_adap.client_unregister = detach_inform;
 	core->i2c_algo.udelay = i2c_udelay;
 	core->i2c_algo.data = core;
 	i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev);
@@ -224,8 +185,6 @@
 
 /* ----------------------------------------------------------------------- */
 
-EXPORT_SYMBOL(cx88_call_i2c_clients);
-
 /*
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 5b0fbc6..434237a 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -431,8 +431,7 @@
 			struct v4l2_routing route;
 
 			route.input = INPUT(input).audioroute;
-			cx88_call_i2c_clients(core,
-				VIDIOC_INT_S_AUDIO_ROUTING, &route);
+			call_all(core, audio, s_routing, &route);
 		}
 		/* cx2388's C-ADC is connected to the tuner only.
 		   When used with S-Video, that ADC is busy dealing with
@@ -827,8 +826,7 @@
 				struct v4l2_routing route;
 
 				route.input = core->board.radio.audioroute;
-				cx88_call_i2c_clients(core,
-					VIDIOC_INT_S_AUDIO_ROUTING, &route);
+				call_all(core, audio, s_routing, &route);
 			}
 			/* "I2S ADC mode" */
 			core->tvaudio = WW_I2SADC;
@@ -839,7 +837,7 @@
 			cx88_set_tvaudio(core);
 			cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
 		}
-		cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
+		call_all(core, tuner, s_radio);
 	}
 	unlock_kernel();
 
@@ -933,7 +931,7 @@
 	kfree(fh);
 
 	if(atomic_dec_and_test(&dev->core->users))
-		cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+		call_all(dev->core, core, s_standby, 0);
 
 	return 0;
 }
@@ -1395,7 +1393,7 @@
 	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
 	f->frequency = core->freq;
 
-	cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+	call_all(core, tuner, g_frequency, f);
 
 	return 0;
 }
@@ -1411,7 +1409,7 @@
 	mutex_lock(&core->lock);
 	core->freq = f->frequency;
 	cx88_newstation(core);
-	cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
+	call_all(core, tuner, s_frequency, f);
 
 	/* When changing channels it is required to reset TVAUDIO */
 	msleep (10);
@@ -1493,7 +1491,7 @@
 	strcpy(t->name, "Radio");
 	t->type = V4L2_TUNER_RADIO;
 
-	cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
+	call_all(core, tuner, g_tuner, t);
 	return 0;
 }
 
@@ -1527,7 +1525,7 @@
 	if (0 != t->index)
 		return -EINVAL;
 
-	cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
+	call_all(core, tuner, s_tuner, t);
 
 	return 0;
 }
@@ -1884,12 +1882,30 @@
 	/* load and configure helper modules */
 
 	if (core->board.audio_chip == V4L2_IDENT_WM8775)
-		request_module("wm8775");
+		v4l2_i2c_new_subdev(&core->i2c_adap,
+				"wm8775", "wm8775", 0x36 >> 1);
+
+	if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
+		/* This probes for a tda9874 as is used on some
+		   Pixelview Ultra boards. */
+		static const unsigned short i2c_addr[] = {
+			0xb0 >> 1, I2C_CLIENT_END
+		};
+
+		v4l2_i2c_new_probed_subdev(&core->i2c_adap,
+				"tvaudio", "tvaudio", i2c_addr);
+	}
 
 	switch (core->boardnr) {
 	case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
-	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: {
+		static struct i2c_board_info rtc_info = {
+			I2C_BOARD_INFO("isl1208", 0x6f)
+		};
+
 		request_module("rtc-isl1208");
+		core->i2c_rtc = i2c_new_device(&core->i2c_adap, &rtc_info);
+	}
 		/* break intentionally omitted */
 	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
 		request_module("ir-kbd-i2c");
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 890018c..9a43fdf 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -328,6 +328,7 @@
 
 	/* config info -- analog */
 	struct v4l2_device 	   v4l2_dev;
+	struct i2c_client 	   *i2c_rtc;
 	unsigned int               boardnr;
 	struct cx88_board	   board;
 
@@ -371,6 +372,17 @@
 	return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
 }
 
+#define call_all(core, o, f, args...) 				\
+	do {							\
+		if (!core->i2c_rc) {				\
+			if (core->gate_ctrl)			\
+				core->gate_ctrl(core, 1);	\
+			v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \
+			if (core->gate_ctrl)			\
+				core->gate_ctrl(core, 0);	\
+		}						\
+	} while (0)
+
 struct cx8800_dev;
 struct cx8802_dev;
 
@@ -616,8 +628,6 @@
 /* cx88-i2c.c                                                  */
 
 extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
-extern void cx88_call_i2c_clients(struct cx88_core *core,
-				  unsigned int cmd, void *arg);
 
 
 /* ----------------------------------------------------------- */