V4L/DVB (11369): v4l2-subdev: add load_fw and use that instead of abusing core->init.

The init callback was used in several places to load firmware. Make a separate
load_fw callback for that. This makes the code a lot more understandable.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index f4dd9d7..0c58e55 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -203,43 +203,42 @@
 
 static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
 {
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+	/*
+	 * The crystal freq used in calculations in this driver will be
+	 * 28.636360 MHz.
+	 * Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
+	 */
+
+	/*
+	 * VDCLK  Integer = 0x0f, Post Divider = 0x04
+	 * AIMCLK Integer = 0x0e, Post Divider = 0x16
+	 */
+	cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
+
+	/* VDCLK Fraction = 0x2be2fe */
+	/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
+	cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
+
+	/* AIMCLK Fraction = 0x05227ad */
+	/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
+	cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
+
+	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+	cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+	return 0;
+}
+
+static int cx18_av_load_fw(struct v4l2_subdev *sd)
+{
 	struct cx18_av_state *state = to_cx18_av_state(sd);
 	struct cx18 *cx = v4l2_get_subdevdata(sd);
 
-	switch (val) {
-	case CX18_AV_INIT_PLLS:
-		/*
-		 * The crystal freq used in calculations in this driver will be
-		 * 28.636360 MHz.
-		 * Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
-		 */
-
-		/*
-		 * VDCLK  Integer = 0x0f, Post Divider = 0x04
-		 * AIMCLK Integer = 0x0e, Post Divider = 0x16
-		 */
-		cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
-
-		/* VDCLK Fraction = 0x2be2fe */
-		/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
-		cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
-
-		/* AIMCLK Fraction = 0x05227ad */
-		/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
-		cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
-
-		/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
-		cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
-		break;
-
-	case CX18_AV_INIT_NORMAL:
-	default:
-		if (!state->is_initialized) {
-			/* initialize on first use */
-			state->is_initialized = 1;
-			cx18_av_initialize(cx);
-		}
-		break;
+	if (!state->is_initialized) {
+		/* initialize on first use */
+		state->is_initialized = 1;
+		cx18_av_initialize(cx);
 	}
 	return 0;
 }
@@ -1185,6 +1184,7 @@
 	.g_chip_ident = cx18_av_g_chip_ident,
 	.log_status = cx18_av_log_status,
 	.init = cx18_av_init,
+	.load_fw = cx18_av_load_fw,
 	.reset = cx18_av_reset,
 	.queryctrl = cx18_av_queryctrl,
 	.g_ctrl = cx18_av_g_ctrl,
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index c458120..9b84a0c 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -328,11 +328,6 @@
 	return container_of(sd, struct cx18_av_state, sd);
 }
 
-enum cx18_av_subdev_init_arg {
-	CX18_AV_INIT_NORMAL = 0,
-	CX18_AV_INIT_PLLS = 1,
-};
-
 /* ----------------------------------------------------------------------- */
 /* cx18_av-core.c 							   */
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 210c68a..49b1c3d 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -810,7 +810,7 @@
 		CX18_ERR("Could not register A/V decoder subdevice\n");
 		goto free_map;
 	}
-	cx18_call_hw(cx, CX18_HW_418_AV, core, init, (u32) CX18_AV_INIT_PLLS);
+	cx18_call_hw(cx, CX18_HW_418_AV, core, init, 0);
 
 	/* Initialize GPIO Reset Controller to do chip resets during i2c init */
 	if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
@@ -1028,7 +1028,7 @@
 	cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
 
 	/* Init the A/V decoder, if it hasn't been already */
-	v4l2_subdev_call(cx->sd_av, core, init, (u32) CX18_AV_INIT_NORMAL);
+	v4l2_subdev_call(cx->sd_av, core, load_fw);
 
 	vf.tuner = 0;
 	vf.type = V4L2_TUNER_ANALOG_TV;
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c
index 79833c2..b63719f 100644
--- a/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -316,7 +316,7 @@
 					"cx25840", "cx25840", 0x88 >> 1);
 		if (dev->sd_cx25840 == NULL)
 			cx231xx_info("cx25840 subdev registration failure\n");
-		cx25840_call(dev, core, init, 0);
+		cx25840_call(dev, core, load_fw);
 
 	}
 
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index 5e4b7e7..fe85255 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -741,7 +741,7 @@
 	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
 		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->i2c_bus[2].i2c_adap,
 				"cx25840", "cx25840", 0x88 >> 1);
-		v4l2_subdev_call(dev->sd_cx25840, core, init, 0);
+		v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
 		break;
 	}
 
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index f8ed3c0..5126681 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -1182,7 +1182,7 @@
 
 /* ----------------------------------------------------------------------- */
 
-/* This init operation must be called to load the driver's firmware.
+/* This load_fw operation must be called to load the driver's firmware.
    Without this the audio standard detection will fail and you will
    only get mono.
 
@@ -1192,13 +1192,13 @@
    postponing it is that loading this firmware takes a long time (seconds)
    due to the slow i2c bus speed. So it will speed up the boot process if
    you can avoid loading the fw as long as the video device isn't used.  */
-static int cx25840_init(struct v4l2_subdev *sd, u32 val)
+static int cx25840_load_fw(struct v4l2_subdev *sd)
 {
 	struct cx25840_state *state = to_state(sd);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
 	if (!state->is_initialized) {
-		/* initialize on first use */
+		/* initialize and load firmware */
 		state->is_initialized = 1;
 		if (state->is_cx25836)
 			cx25836_initialize(client);
@@ -1473,7 +1473,7 @@
 	.s_ctrl = cx25840_s_ctrl,
 	.queryctrl = cx25840_queryctrl,
 	.reset = cx25840_reset,
-	.init = cx25840_init,
+	.load_fw = cx25840_load_fw,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	.g_register = cx25840_g_register,
 	.s_register = cx25840_s_register,
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index eca8bf9..07d5ffe 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1234,7 +1234,7 @@
 	if (itv->card->hw_all & IVTV_HW_CX25840) {
 		struct v4l2_control ctrl;
 
-		v4l2_subdev_call(itv->sd_video, core, init, 0);
+		v4l2_subdev_call(itv->sd_video, core, load_fw);
 		/* CX25840_CID_ENABLE_PVR150_WORKAROUND */
 		ctrl.id = V4L2_CID_PRIVATE_BASE;
 		ctrl.value = itv->pvr150_workaround;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index eff9211..59a0259 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2185,7 +2185,7 @@
 	pvr2_hdw_load_modules(hdw);
 	if (!pvr2_hdw_dev_ok(hdw)) return;
 
-	v4l2_device_call_all(&hdw->v4l2_dev, 0, core, init, 0);
+	v4l2_device_call_all(&hdw->v4l2_dev, 0, core, load_fw);
 
 	for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
 		cptr = hdw->controls + idx;
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index c84ff88..38b89cf 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -89,7 +89,9 @@
 	values. Do not use for new drivers and should be removed in existing
 	drivers.
 
-  reset: generic reset command. The argument selects which subsystems to
+   load_fw: load firmware.
+
+   reset: generic reset command. The argument selects which subsystems to
 	reset. Passing 0 will always reset the whole chip. Do not use for new
 	drivers without discussing this first on the linux-media mailinglist.
 	There should be no reason normally to reset a device.
@@ -101,6 +103,7 @@
 	int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
 	int (*log_status)(struct v4l2_subdev *sd);
 	int (*init)(struct v4l2_subdev *sd, u32 val);
+	int (*load_fw)(struct v4l2_subdev *sd);
 	int (*reset)(struct v4l2_subdev *sd, u32 val);
 	int (*s_gpio)(struct v4l2_subdev *sd, u32 val);
 	int (*queryctrl)(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc);
@@ -175,31 +178,31 @@
 	v4l2_sliced_vbi_data struct. If no valid VBI data was found, then the
 	type field is set to 0 on return.
 
-  s_vbi_data: used to generate VBI signals on a video signal.
+   s_vbi_data: used to generate VBI signals on a video signal.
 	v4l2_sliced_vbi_data is filled with the data packets that should be
 	output. Note that if you set the line field to 0, then that VBI signal
 	is disabled. If no valid VBI data was found, then the type field is
 	set to 0 on return.
 
-  g_vbi_data: used to obtain the sliced VBI packet from a readback register.
+   g_vbi_data: used to obtain the sliced VBI packet from a readback register.
 	Not all video decoders support this. If no data is available because
 	the readback register contains invalid or erroneous data -EIO is
 	returned. Note that you must fill in the 'id' member and the 'field'
 	member (to determine whether CC data from the first or second field
 	should be obtained).
 
-  s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by
+   s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by
 	video input devices.
 
-  s_crystal_freq: sets the frequency of the crystal used to generate the
+   s_crystal_freq: sets the frequency of the crystal used to generate the
 	clocks. An extra flags field allows device specific configuration
 	regarding clock frequency dividers, etc. If not used, then set flags
 	to 0. If the frequency is not supported, then -EINVAL is returned.
 
-  g_input_status: get input status. Same as the status field in the v4l2_input
+   g_input_status: get input status. Same as the status field in the v4l2_input
 	struct.
 
-  s_routing: see s_routing in audio_ops, except this version is for video
+   s_routing: see s_routing in audio_ops, except this version is for video
 	devices.
  */
 struct v4l2_subdev_video_ops {