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>
This commit is contained in:
committed by
Mauro Carvalho Chehab
parent
7c9fc9d50f
commit
cc26b076cf
@@ -202,44 +202,43 @@ static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
|
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_av_state *state = to_cx18_av_state(sd);
|
||||||
struct cx18 *cx = v4l2_get_subdevdata(sd);
|
struct cx18 *cx = v4l2_get_subdevdata(sd);
|
||||||
|
|
||||||
switch (val) {
|
if (!state->is_initialized) {
|
||||||
case CX18_AV_INIT_PLLS:
|
/* initialize on first use */
|
||||||
/*
|
state->is_initialized = 1;
|
||||||
* The crystal freq used in calculations in this driver will be
|
cx18_av_initialize(cx);
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
return 0;
|
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,
|
.g_chip_ident = cx18_av_g_chip_ident,
|
||||||
.log_status = cx18_av_log_status,
|
.log_status = cx18_av_log_status,
|
||||||
.init = cx18_av_init,
|
.init = cx18_av_init,
|
||||||
|
.load_fw = cx18_av_load_fw,
|
||||||
.reset = cx18_av_reset,
|
.reset = cx18_av_reset,
|
||||||
.queryctrl = cx18_av_queryctrl,
|
.queryctrl = cx18_av_queryctrl,
|
||||||
.g_ctrl = cx18_av_g_ctrl,
|
.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);
|
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 */
|
/* cx18_av-core.c */
|
||||||
int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
|
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");
|
CX18_ERR("Could not register A/V decoder subdevice\n");
|
||||||
goto free_map;
|
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 */
|
/* Initialize GPIO Reset Controller to do chip resets during i2c init */
|
||||||
if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) {
|
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);
|
cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG);
|
||||||
|
|
||||||
/* Init the A/V decoder, if it hasn't been already */
|
/* 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.tuner = 0;
|
||||||
vf.type = V4L2_TUNER_ANALOG_TV;
|
vf.type = V4L2_TUNER_ANALOG_TV;
|
||||||
|
@@ -316,7 +316,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
|
|||||||
"cx25840", "cx25840", 0x88 >> 1);
|
"cx25840", "cx25840", 0x88 >> 1);
|
||||||
if (dev->sd_cx25840 == NULL)
|
if (dev->sd_cx25840 == NULL)
|
||||||
cx231xx_info("cx25840 subdev registration failure\n");
|
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:
|
case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
|
||||||
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->i2c_bus[2].i2c_adap,
|
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->i2c_bus[2].i2c_adap,
|
||||||
"cx25840", "cx25840", 0x88 >> 1);
|
"cx25840", "cx25840", 0x88 >> 1);
|
||||||
v4l2_subdev_call(dev->sd_cx25840, core, init, 0);
|
v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
|
||||||
break;
|
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
|
Without this the audio standard detection will fail and you will
|
||||||
only get mono.
|
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)
|
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
|
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. */
|
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 cx25840_state *state = to_state(sd);
|
||||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||||
|
|
||||||
if (!state->is_initialized) {
|
if (!state->is_initialized) {
|
||||||
/* initialize on first use */
|
/* initialize and load firmware */
|
||||||
state->is_initialized = 1;
|
state->is_initialized = 1;
|
||||||
if (state->is_cx25836)
|
if (state->is_cx25836)
|
||||||
cx25836_initialize(client);
|
cx25836_initialize(client);
|
||||||
@@ -1473,7 +1473,7 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = {
|
|||||||
.s_ctrl = cx25840_s_ctrl,
|
.s_ctrl = cx25840_s_ctrl,
|
||||||
.queryctrl = cx25840_queryctrl,
|
.queryctrl = cx25840_queryctrl,
|
||||||
.reset = cx25840_reset,
|
.reset = cx25840_reset,
|
||||||
.init = cx25840_init,
|
.load_fw = cx25840_load_fw,
|
||||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
.g_register = cx25840_g_register,
|
.g_register = cx25840_g_register,
|
||||||
.s_register = cx25840_s_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) {
|
if (itv->card->hw_all & IVTV_HW_CX25840) {
|
||||||
struct v4l2_control ctrl;
|
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 */
|
/* CX25840_CID_ENABLE_PVR150_WORKAROUND */
|
||||||
ctrl.id = V4L2_CID_PRIVATE_BASE;
|
ctrl.id = V4L2_CID_PRIVATE_BASE;
|
||||||
ctrl.value = itv->pvr150_workaround;
|
ctrl.value = itv->pvr150_workaround;
|
||||||
|
@@ -2185,7 +2185,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
|
|||||||
pvr2_hdw_load_modules(hdw);
|
pvr2_hdw_load_modules(hdw);
|
||||||
if (!pvr2_hdw_dev_ok(hdw)) return;
|
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++) {
|
for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
|
||||||
cptr = hdw->controls + 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
|
values. Do not use for new drivers and should be removed in existing
|
||||||
drivers.
|
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
|
reset. Passing 0 will always reset the whole chip. Do not use for new
|
||||||
drivers without discussing this first on the linux-media mailinglist.
|
drivers without discussing this first on the linux-media mailinglist.
|
||||||
There should be no reason normally to reset a device.
|
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 (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
|
||||||
int (*log_status)(struct v4l2_subdev *sd);
|
int (*log_status)(struct v4l2_subdev *sd);
|
||||||
int (*init)(struct v4l2_subdev *sd, u32 val);
|
int (*init)(struct v4l2_subdev *sd, u32 val);
|
||||||
|
int (*load_fw)(struct v4l2_subdev *sd);
|
||||||
int (*reset)(struct v4l2_subdev *sd, u32 val);
|
int (*reset)(struct v4l2_subdev *sd, u32 val);
|
||||||
int (*s_gpio)(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);
|
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
|
v4l2_sliced_vbi_data struct. If no valid VBI data was found, then the
|
||||||
type field is set to 0 on return.
|
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
|
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
|
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
|
is disabled. If no valid VBI data was found, then the type field is
|
||||||
set to 0 on return.
|
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
|
Not all video decoders support this. If no data is available because
|
||||||
the readback register contains invalid or erroneous data -EIO is
|
the readback register contains invalid or erroneous data -EIO is
|
||||||
returned. Note that you must fill in the 'id' member and the 'field'
|
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
|
member (to determine whether CC data from the first or second field
|
||||||
should be obtained).
|
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.
|
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
|
clocks. An extra flags field allows device specific configuration
|
||||||
regarding clock frequency dividers, etc. If not used, then set flags
|
regarding clock frequency dividers, etc. If not used, then set flags
|
||||||
to 0. If the frequency is not supported, then -EINVAL is returned.
|
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.
|
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.
|
devices.
|
||||||
*/
|
*/
|
||||||
struct v4l2_subdev_video_ops {
|
struct v4l2_subdev_video_ops {
|
||||||
|
Reference in New Issue
Block a user