Commit cc26b076 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

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: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 7c9fc9d5
......@@ -203,43 +203,42 @@ static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
{
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.
*/
/*
* 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 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);
/* 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);
/* 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;
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
return 0;
}
case CX18_AV_INIT_NORMAL:
default:
if (!state->is_initialized) {
/* initialize on first use */
state->is_initialized = 1;
cx18_av_initialize(cx);
}
break;
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);
if (!state->is_initialized) {
/* initialize on first use */
state->is_initialized = 1;
cx18_av_initialize(cx);
}
return 0;
}
......@@ -1185,6 +1184,7 @@ static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
.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,
......
......@@ -328,11 +328,6 @@ static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd)
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);
......
......@@ -810,7 +810,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
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 @@ int cx18_init_on_first_open(struct cx18 *cx)
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;
......
......@@ -316,7 +316,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
"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);
}
......
......@@ -741,7 +741,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
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;
}
......
......@@ -1182,7 +1182,7 @@ static void log_audio_status(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
/* 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 @@ static void log_audio_status(struct i2c_client *client)
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 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = {
.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,
......
......@@ -1234,7 +1234,7 @@ 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);
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;
......
......@@ -2185,7 +2185,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
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;
......
......@@ -89,7 +89,9 @@ struct v4l2_crystal_freq {
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 @@ struct v4l2_subdev_core_ops {
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 @@ struct v4l2_subdev_audio_ops {
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 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment