/** * struct tvp514x_std_info - Structure to store standard information * @width: Line width in pixels * @height:Number of active lines * @video_std: Value to write in REG_VIDEO_STD register * @standard: v4l2 standard structure information
*/ struct tvp514x_std_info { unsignedlong width; unsignedlong height;
u8 video_std; struct v4l2_standard standard;
};
staticint tvp514x_s_stream(struct v4l2_subdev *sd, int enable); /** * struct tvp514x_decoder - TVP5146/47 decoder object * @sd: Subdevice Slave handle * @hdl: embedded &struct v4l2_ctrl_handler * @tvp514x_regs: copy of hw's regs with preset values. * @pdata: Board specific * @ver: Chip version * @streaming: TVP5146/47 decoder streaming - enabled or disabled. * @pix: Current pixel format * @num_fmts: Number of formats * @fmt_list: Format list * @current_std: Current standard * @num_stds: Number of standards * @std_list: Standards list * @input: Input routing at chip level * @output: Output routing at chip level * @pad: subdev media pad associated with the decoder * @format: media bus frame format * @int_seq: driver's register init sequence
*/ struct tvp514x_decoder { struct v4l2_subdev sd; struct v4l2_ctrl_handler hdl; struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)]; conststruct tvp514x_platform_data *pdata;
int ver; int streaming;
struct v4l2_pix_format pix; int num_fmts; conststruct v4l2_fmtdesc *fmt_list;
enum tvp514x_std current_std; int num_stds; conststruct tvp514x_std_info *std_list; /* Input and Output Routing parameters */
u32 input;
u32 output;
/* mc related members */ struct media_pad pad; struct v4l2_mbus_framefmt format;
/* * List of image formats supported by TVP5146/47 decoder * Currently we are using 8 bit mode only, but can be * extended to 10/20 bit mode.
*/ staticconststruct v4l2_fmtdesc tvp514x_fmt_list[] = {
{
.index = 0,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.flags = 0,
.description = "8-bit UYVY 4:2:2 Format",
.pixelformat = V4L2_PIX_FMT_UYVY,
},
};
/* * Supported standards - * * Currently supports two standards only, need to add support for rest of the * modes, like SECAM, etc...
*/ staticconststruct tvp514x_std_info tvp514x_std_list[] = { /* Standard: STD_NTSC_MJ */
[STD_NTSC_MJ] = {
.width = NTSC_NUM_ACTIVE_PIXELS,
.height = NTSC_NUM_ACTIVE_LINES,
.video_std = VIDEO_STD_NTSC_MJ_BIT,
.standard = {
.index = 0,
.id = V4L2_STD_NTSC,
.name = "NTSC",
.frameperiod = {1001, 30000},
.framelines = 525
}, /* Standard: STD_PAL_BDGHIN */
},
[STD_PAL_BDGHIN] = {
.width = PAL_NUM_ACTIVE_PIXELS,
.height = PAL_NUM_ACTIVE_LINES,
.video_std = VIDEO_STD_PAL_BDGHIN_BIT,
.standard = {
.index = 1,
.id = V4L2_STD_PAL,
.name = "PAL",
.frameperiod = {1, 25},
.framelines = 625
},
}, /* Standard: need to add for additional standard */
};
/** * tvp514x_read_reg() - Read a value from a register in an TVP5146/47. * @sd: ptr to v4l2_subdev struct * @reg: TVP5146/47 register address * * Returns value read if successful, or non-zero (-1) otherwise.
*/ staticint tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg)
{ int err, retry = 0; struct i2c_client *client = v4l2_get_subdevdata(sd);
val = tvp514x_read_reg(sd, reg);
v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val);
}
/** * tvp514x_write_reg() - Write a value to a register in TVP5146/47 * @sd: ptr to v4l2_subdev struct * @reg: TVP5146/47 register address * @val: value to be written to the register * * Write a value to a register in an TVP5146/47 decoder device. * Returns zero if successful, or non-zero otherwise.
*/ staticint tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val)
{ int err, retry = 0; struct i2c_client *client = v4l2_get_subdevdata(sd);
/** * tvp514x_write_regs() : Initializes a list of TVP5146/47 registers * @sd: ptr to v4l2_subdev struct * @reglist: list of TVP5146/47 registers and values * * Initializes a list of TVP5146/47 registers:- * if token is TOK_TERM, then entire write operation terminates * if token is TOK_DELAY, then a delay of 'val' msec is introduced * if token is TOK_SKIP, then the register write is skipped * if token is TOK_WRITE, then the register write is performed * Returns zero if successful, or non-zero otherwise.
*/ staticint tvp514x_write_regs(struct v4l2_subdev *sd, conststruct tvp514x_reg reglist[])
{ int err; conststruct tvp514x_reg *next = reglist;
for (; next->token != TOK_TERM; next++) { if (next->token == TOK_DELAY) {
msleep(next->val); continue;
}
/** * tvp514x_query_current_std() : Query the current standard detected by TVP5146/47 * @sd: ptr to v4l2_subdev struct * * Returns the current standard detected by TVP5146/47, STD_INVALID if there is no * standard detected.
*/ staticenum tvp514x_std tvp514x_query_current_std(struct v4l2_subdev *sd)
{
u8 std, std_status;
std = tvp514x_read_reg(sd, REG_VIDEO_STD); if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) /* use the standard status register */
std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS); else /* use the standard register itself */
std_status = std;
switch (std_status & VIDEO_STD_MASK) { case VIDEO_STD_NTSC_MJ_BIT: return STD_NTSC_MJ;
case VIDEO_STD_PAL_BDGHIN_BIT: return STD_PAL_BDGHIN;
/** * tvp514x_configure() - Configure the TVP5146/47 registers * @sd: ptr to v4l2_subdev struct * @decoder: ptr to tvp514x_decoder structure * * Returns zero if successful, or non-zero otherwise.
*/ staticint tvp514x_configure(struct v4l2_subdev *sd, struct tvp514x_decoder *decoder)
{ int err;
/* common register initialization */
err =
tvp514x_write_regs(sd, decoder->tvp514x_regs); if (err) return err;
if (debug)
tvp514x_reg_dump(sd);
return 0;
}
/** * tvp514x_detect() - Detect if an tvp514x is present, and if so which revision. * @sd: pointer to standard V4L2 sub-device structure * @decoder: pointer to tvp514x_decoder structure * * A device is considered to be detected if the chip ID (LSB and MSB) * registers match the expected values. * Any value of the rom version register is accepted. * Returns ENODEV error number if no device is detected, or zero * if a device is detected.
*/ staticint tvp514x_detect(struct v4l2_subdev *sd, struct tvp514x_decoder *decoder)
{
u8 chip_id_msb, chip_id_lsb, rom_ver; struct i2c_client *client = v4l2_get_subdevdata(sd);
v4l2_dbg(1, debug, sd, "chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n",
chip_id_msb, chip_id_lsb, rom_ver); if ((chip_id_msb != TVP514X_CHIP_ID_MSB)
|| ((chip_id_lsb != TVP5146_CHIP_ID_LSB)
&& (chip_id_lsb != TVP5147_CHIP_ID_LSB))) { /* We didn't read the values we expected, so this must not be * an TVP5146/47.
*/
v4l2_err(sd, "chip id mismatch msb:0x%x lsb:0x%x\n",
chip_id_msb, chip_id_lsb); return -ENODEV;
}
decoder->ver = rom_ver;
v4l2_info(sd, "%s (Version - 0x%.2x) found at 0x%x (%s)\n",
client->name, decoder->ver,
client->addr << 1, client->adapter->name); return 0;
}
/** * tvp514x_querystd() - V4L2 decoder interface handler for querystd * @sd: pointer to standard V4L2 sub-device structure * @std_id: standard V4L2 std_id ioctl enum * * Returns the current standard detected by TVP5146/47. If no active input is * detected then *std_id is set to 0 and the function returns 0.
*/ staticint tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
{ struct tvp514x_decoder *decoder = to_decoder(sd); enum tvp514x_std current_std; enum tvp514x_input input_sel;
u8 sync_lock_status, lock_mask;
if (std_id == NULL) return -EINVAL;
/* To query the standard the TVP514x must power on the ADCs. */ if (!decoder->streaming) {
tvp514x_s_stream(sd, 1);
msleep(LOCK_RETRY_DELAY);
}
/* query the current standard */
current_std = tvp514x_query_current_std(sd); if (current_std == STD_INVALID) {
*std_id = V4L2_STD_UNKNOWN; return 0;
}
input_sel = decoder->input;
switch (input_sel) { case INPUT_CVBS_VI1A: case INPUT_CVBS_VI1B: case INPUT_CVBS_VI1C: case INPUT_CVBS_VI2A: case INPUT_CVBS_VI2B: case INPUT_CVBS_VI2C: case INPUT_CVBS_VI3A: case INPUT_CVBS_VI3B: case INPUT_CVBS_VI3C: case INPUT_CVBS_VI4A:
lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
STATUS_HORZ_SYNC_LOCK_BIT |
STATUS_VIRT_SYNC_LOCK_BIT; break;
case INPUT_SVIDEO_VI2A_VI1A: case INPUT_SVIDEO_VI2B_VI1B: case INPUT_SVIDEO_VI2C_VI1C: case INPUT_SVIDEO_VI2A_VI3A: case INPUT_SVIDEO_VI2B_VI3B: case INPUT_SVIDEO_VI2C_VI3C: case INPUT_SVIDEO_VI4A_VI1A: case INPUT_SVIDEO_VI4A_VI1B: case INPUT_SVIDEO_VI4A_VI1C: case INPUT_SVIDEO_VI4A_VI3A: case INPUT_SVIDEO_VI4A_VI3B: case INPUT_SVIDEO_VI4A_VI3C:
lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
STATUS_VIRT_SYNC_LOCK_BIT; break; /*Need to add other interfaces*/ default: return -EINVAL;
} /* check whether signal is locked */
sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1); if (lock_mask != (sync_lock_status & lock_mask)) {
*std_id = V4L2_STD_UNKNOWN; return 0; /* No input detected */
}
v4l2_dbg(1, debug, sd, "Standard set to: %s\n",
decoder->std_list[i].standard.name); return 0;
}
/** * tvp514x_s_routing() - V4L2 decoder interface handler for s_routing * @sd: pointer to standard V4L2 sub-device structure * @input: input selector for routing the signal * @output: output selector for routing the signal * @config: config value. Not used * * If index is valid, selects the requested input. Otherwise, returns -EINVAL if * the input is not supported or there is no active signal present in the * selected input.
*/ staticint tvp514x_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{ struct tvp514x_decoder *decoder = to_decoder(sd); int err; enum tvp514x_input input_sel; enum tvp514x_output output_sel;
if ((input >= INPUT_INVALID) ||
(output >= OUTPUT_INVALID)) /* Index out of bound */ return -EINVAL;
input_sel = input;
output_sel = output;
err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel); if (err) return err;
v4l2_dbg(1, debug, sd, "Input set to: %d\n", input_sel);
return 0;
}
/** * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl * @ctrl: pointer to v4l2_ctrl structure * * If the requested control is supported, sets the control's current * value in HW. Otherwise, returns -EINVAL if the control is not supported.
*/ staticint tvp514x_s_ctrl(struct v4l2_ctrl *ctrl)
{ struct v4l2_subdev *sd = to_sd(ctrl); struct tvp514x_decoder *decoder = to_decoder(sd); int err = -EINVAL, value;
value = ctrl->val;
switch (ctrl->id) { case V4L2_CID_BRIGHTNESS:
err = tvp514x_write_reg(sd, REG_BRIGHTNESS, value); if (!err)
decoder->tvp514x_regs[REG_BRIGHTNESS].val = value; break; case V4L2_CID_CONTRAST:
err = tvp514x_write_reg(sd, REG_CONTRAST, value); if (!err)
decoder->tvp514x_regs[REG_CONTRAST].val = value; break; case V4L2_CID_SATURATION:
err = tvp514x_write_reg(sd, REG_SATURATION, value); if (!err)
decoder->tvp514x_regs[REG_SATURATION].val = value; break; case V4L2_CID_HUE: if (value == 180)
value = 0x7F; elseif (value == -180)
value = 0x80;
err = tvp514x_write_reg(sd, REG_HUE, value); if (!err)
decoder->tvp514x_regs[REG_HUE].val = value; break; case V4L2_CID_AUTOGAIN:
err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value ? 0x0f : 0x0c); if (!err)
decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value; break;
}
/* * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 * subdev active state API.
*/ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL;
/* get the current standard */
current_std = decoder->current_std;
/* * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 * subdev active state API.
*/ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL;
timeperframe = &ival->interval;
/* get the current standard */
current_std = decoder->current_std;
/** * tvp514x_get_pad_format() - V4L2 decoder interface handler for get pad format * @sd: pointer to standard V4L2 sub-device structure * @sd_state: subdev state * @format: pointer to v4l2_subdev_format structure * * Retrieves pad format which is active or tried based on requirement
*/ staticint tvp514x_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format)
{ struct tvp514x_decoder *decoder = to_decoder(sd);
__u32 which = format->which;
/** * tvp514x_set_pad_format() - V4L2 decoder interface handler for set pad format * @sd: pointer to standard V4L2 sub-device structure * @sd_state: subdev state * @fmt: pointer to v4l2_subdev_format structure * * Set pad format for the output pad
*/ staticint tvp514x_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt)
{ struct tvp514x_decoder *decoder = to_decoder(sd);
if (pdata == NULL) {
dev_err(&client->dev, "No platform data\n"); return -EINVAL;
}
/* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO;
decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL); if (!decoder) return -ENOMEM;
/* Initialize the tvp514x_decoder with default configuration */
*decoder = tvp514x_dev; /* Copy default register configuration */
memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default, sizeof(tvp514x_reg_list_default));
decoder->int_seq = i2c_get_match_data(client);
/* Copy board specific information here */
decoder->pdata = pdata;
/** * Fetch platform specific data, and configure the * tvp514x_reg_list[] accordingly. Since this is one * time configuration, no need to preserve.
*/
decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |=
(decoder->pdata->clk_polarity << 1);
decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
((decoder->pdata->hs_polarity << 2) |
(decoder->pdata->vs_polarity << 3)); /* Set default standard to auto */
decoder->tvp514x_regs[REG_VIDEO_STD].val =
VIDEO_STD_AUTO_SWITCH_BIT;
/* Register with V4L2 layer as slave device */
sd = &decoder->sd;
v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.