commit: http://blackfin.uclinux.org/git/?p=linux-kernel;a=commitdiff;h=587ec157d80fbf5d73465aab81db24305c1d005c branch: http://blackfin.uclinux.org/git/?p=linux-kernel;a=shortlog;h=refs/heads/trunk
Signed-off-by: Scott Jiang <[email protected]> --- drivers/media/video/adv7842.c | 217 ++++++++++++++++++++++++++++++++++------ include/media/adv7842.h | 53 ++++++---- 2 files changed, 217 insertions(+), 53 deletions(-) diff --git a/drivers/media/video/adv7842.c b/drivers/media/video/adv7842.c index 524f15a..03e4899 100644 --- a/drivers/media/video/adv7842.c +++ b/drivers/media/video/adv7842.c @@ -120,6 +120,9 @@ struct adv7842_state { struct v4l2_ctrl_handler hdl; enum adv7842_prim_mode prim_mode; enum adv7842_vid_std_select vid_std_select; + struct adv7842_platform_data *pdata; + struct adv7842_output_format *opf; + v4l2_std_id std; /* current standard in SDP mode */ u32 preset; u8 edid[256]; wait_queue_head_t cec_wqh; @@ -1348,6 +1351,22 @@ static void sdp_csc_coeff(struct v4l2_subdev *sd, static void select_input(struct v4l2_subdev *sd, enum adv7842_prim_mode prim_mode, enum adv7842_vid_std_select vid_std_select) { + struct adv7842_state *state = to_state(sd); + struct adv7842_output_format *opf = state->opf; + + /* output video format */ + io_write_and_or(sd, 0x02, 0xf8, + opf->op_656_range << 2 | + opf->rgb_out << 1 | + opf->alt_data_sat << 0); + io_write(sd, 0x03, opf->op_format_sel); + io_write_and_or(sd, 0x04, 0x1f, opf->op_ch_sel << 5); + io_write_and_or(sd, 0x05, 0xf0, opf->blank_data << 3 | + opf->insert_av_codes << 2 | + opf->replicate_av_codes << 1 | + opf->invert_cbcr << 0); + io_write_and_or(sd, 0x30, ~(1 << 4), opf->output_bus_lsb_to_msb << 4); + switch (prim_mode) { case ADV7842_PRIM_MODE_SDP: @@ -1380,7 +1399,10 @@ static void select_input(struct v4l2_subdev *sd, enum adv7842_prim_mode prim_mod sdp_io_write(sd, 0x7b, 0x8f); /* Timing Adjustment */ sdp_io_write(sd, 0x60, 0x01); /* SDRAM reset */ sdp_io_write(sd, 0x97, 0x00); /* Hsync width Adjustment */ - sdp_io_write(sd, 0xb2, 0x60); /* Disable AV codes */ + if (opf->insert_av_codes) + sdp_io_write(sd, 0xb2, 0x6c); + else + sdp_io_write(sd, 0xb2, 0x60); /* Disable AV codes */ /* SDP recommended settings */ sdp_write(sd, 0x00, 0x7F); /* Autodetect PAL NTSC SECAM */ @@ -1389,20 +1411,23 @@ static void select_input(struct v4l2_subdev *sd, enum adv7842_prim_mode prim_mod sdp_write(sd, 0x04, 0x0B); /* Manual Luma setting */ sdp_write(sd, 0x05, 0xC3); /* Manual Chroma setting 0x3FE */ sdp_write(sd, 0x06, 0xFE); /* Manual Chroma setting */ - sdp_write(sd, 0x12, 0x0C); /* Frame TBC,3D comb enabled */ + sdp_write(sd, 0x12, 0x05); /* Frame TBC,3D comb enabled */ sdp_write(sd, 0xA7, 0x00); /* ADI Recommended Write */ - sdp_write_and_or(sd, 0x12, 0xf7, 0x08); /* deinterlacer enabled */ + if (opf->i2p_convert) + sdp_write_and_or(sd, 0x12, 0xf7, 0x08); /* deinterlacer enabled */ sdp_write(sd, 0xdd, 0x08); /* free run auto */ - /* Manual CSC mode, convert to RGB - http://ez.analog.com/message/30063 - */ - sdp_csc_coeff(sd, true, 2, - 0x03a7, 0x1e91, 0x1de2, 0x7d00, - 0x03a7, 0x0761, 0x0000, 0x7900, - 0x03a7, 0x0000, 0x0429, 0x7900); + if (opf->rgb_out) { + /* Manual CSC mode, convert to RGB + http://ez.analog.com/message/30063 + */ + sdp_csc_coeff(sd, true, 2, + 0x03a7, 0x1e91, 0x1de2, 0x7d00, + 0x03a7, 0x0761, 0x0000, 0x7900, + 0x03a7, 0x0000, 0x0429, 0x7900); + } v4l2_info(sd, "%s: SDP todo\n", __func__); break; case ADV7842_PRIM_MODE_COMP: @@ -1537,6 +1562,14 @@ static int adv7842_s_routing(struct v4l2_subdev *sd, return -EINVAL; } + if (output < state->pdata->num_opf) { + state->opf = &state->pdata->opf[output]; + } else { + state->prim_mode = prev_prime_mode; + state->vid_std_select = prev_vid_std_select; + return -EINVAL; + } + if ((state->prim_mode != prev_prime_mode) || (state->vid_std_select != prev_vid_std_select)) { /* only re-init if primary mode changed */ @@ -1553,10 +1586,13 @@ static int adv7842_s_routing(struct v4l2_subdev *sd, static int adv7842_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { + struct adv7842_state *state = to_state(sd); if (index) return -EINVAL; - /* Good enough for now */ - *code = V4L2_MBUS_FMT_FIXED; + if (state->prim_mode == ADV7842_PRIM_MODE_SDP) + *code = V4L2_MBUS_FMT_UYVY8_2X8; + else + *code = V4L2_MBUS_FMT_FIXED; return 0; } @@ -1567,16 +1603,32 @@ static int adv7842_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_dv_enum_preset info; int err; - if (state->preset == V4L2_DV_INVALID) - return -EINVAL; - err = v4l_fill_dv_preset_info(state->preset, &info); - fmt->width = info.width; - fmt->height = info.height; - fmt->code = V4L2_MBUS_FMT_FIXED; - fmt->field = V4L2_FIELD_NONE; - fmt->colorspace = (state->preset <= V4L2_DV_576P50) ? - V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; - return err; + if (state->prim_mode == ADV7842_PRIM_MODE_SDP) { + + fmt->code = V4L2_MBUS_FMT_UYVY8_2X8; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + if (state->std & V4L2_STD_525_60) { + fmt->field = V4L2_FIELD_SEQ_TB; + fmt->width = 720; + fmt->height = 480; + } else { + fmt->field = V4L2_FIELD_SEQ_BT; + fmt->width = 720; + fmt->height = 576; + } + return 0; + } else { + if (state->preset == V4L2_DV_INVALID) + return -EINVAL; + err = v4l_fill_dv_preset_info(state->preset, &info); + fmt->width = info.width; + fmt->height = info.height; + fmt->code = V4L2_MBUS_FMT_FIXED; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = (state->preset <= V4L2_DV_576P50) ? + V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; + return err; + } } static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) @@ -2305,6 +2357,96 @@ static int adv7842_log_status(struct v4l2_subdev *sd) return 0; } +static int adv7842_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + struct adv7842_state *state = to_state(sd); + + if (state->prim_mode != ADV7842_PRIM_MODE_SDP) + return -EINVAL; + + *std = state->std; + return 0; +} + +static int adv7842_s_std(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7842_state *state = to_state(sd); + u8 val; + + if (state->prim_mode != ADV7842_PRIM_MODE_SDP) + return -EINVAL; + + if (std == state->std) + return 0; + + if (std == V4L2_STD_NTSC_443) + val = 0x20; + else if (std == V4L2_STD_PAL_60) + val = 0x10; + else if (std == V4L2_STD_PAL_Nc) + val = 0x08; + else if (std == V4L2_STD_PAL_M) + val = 0x04; + else if (std & V4L2_STD_NTSC) + val = 0x02; + else if (std & V4L2_STD_PAL) + val = 0x01; + else if (std & V4L2_STD_SECAM) + val = 0x40; + else + return -EINVAL; + /* force the digital core into a specific video standard */ + sdp_write(sd, 0x0, val); + /* wait 100ms, otherwise color will be lost */ + msleep(100); + state->std = std; + return 0; +} + +static int adv7842_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + struct adv7842_state *state = to_state(sd); + u8 val; + + if (state->prim_mode != ADV7842_PRIM_MODE_SDP) + return -EINVAL; + + /* enable autodetection block */ + sdp_write(sd, 0x0, 0x7f); + /* wait autodetection switch */ + mdelay(10); + /* get autodetection result */ + val = sdp_read(sd, 0x52) & 0xf; + switch (val) { + case 0x0: + *std = V4L2_STD_NTSC; + break; + case 0x2: + *std = V4L2_STD_NTSC_443; + break; + case 0x4: + *std = V4L2_STD_PAL_M; + break; + case 0x6: + *std = V4L2_STD_PAL_60; + break; + case 0xc: + *std = V4L2_STD_PAL_Nc; + break; + case 0xe: + *std = V4L2_STD_PAL; + break; + case 0xf: + *std = V4L2_STD_SECAM; + break; + default: + *std = V4L2_STD_UNKNOWN; + break; + } + /* after autodetection, write back user set std */ + return adv7842_s_std(sd, state->std); +} + /* ----------------------------------------------------------------------- */ static const struct v4l2_ctrl_ops adv7842_ctrl_ops = { @@ -2322,6 +2464,8 @@ static const struct v4l2_subdev_core_ops adv7842_core_ops = { .querymenu = v4l2_subdev_querymenu, .ioctl = adv7842_ioctl, .g_chip_ident = adv7842_g_chip_ident, + .g_std = adv7842_g_std, + .s_std = adv7842_s_std, .interrupt_service_routine = adv7842_isr, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = adv7842_g_register, @@ -2331,6 +2475,7 @@ static const struct v4l2_subdev_core_ops adv7842_core_ops = { static const struct v4l2_subdev_video_ops adv7842_video_ops = { .s_routing = adv7842_s_routing, + .querystd = adv7842_querystd, .g_input_status = adv7842_g_input_status, .enum_dv_presets = adv7842_enum_dv_presets, .s_dv_preset = adv7842_s_dv_preset, @@ -2411,16 +2556,7 @@ static int adv7842_core_init(struct v4l2_subdev *sd, const struct adv7842_platfo /* video format */ io_write(sd, 0x02, pdata->inp_color_space << 4 | - pdata->alt_gamma << 3 | - pdata->op_656_range << 2 | - pdata->rgb_out << 1 | - pdata->alt_data_sat << 0); - io_write(sd, 0x03, pdata->op_format_sel); - io_write_and_or(sd, 0x04, 0x1f, pdata->op_ch_sel << 5); - io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 | - pdata->insert_av_codes << 2 | - pdata->replicate_av_codes << 1 | - pdata->invert_cbcr << 0); + pdata->alt_gamma << 3); /* TODO from platform data */ cp_write(sd, 0x69, 0x14); /* Enable CP CSC */ @@ -2433,7 +2569,6 @@ static int adv7842_core_init(struct v4l2_subdev *sd, const struct adv7842_platfo afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ - io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4); select_input(sd, pdata->prim_mode, pdata->vid_std_select); @@ -2518,6 +2653,8 @@ static int adv7842_probe(struct i2c_client *client, state->preset = V4L2_DV_1080P60; state->connector_hdmi = pdata->connector_hdmi; state->prim_mode = pdata->prim_mode; + state->pdata = pdata; + state->opf = &pdata->opf[0]; hdl = &state->hdl; v4l2_ctrl_handler_init(hdl, 5); @@ -2588,6 +2725,16 @@ static int adv7842_probe(struct i2c_client *client, v4l2_err(sd, "failed to create all i2c clients\n"); goto err_i2c; } + if (pdata->i2c_ex) { + struct i2c_client *i2c_ex; + i2c_ex = i2c_new_dummy(client->adapter, pdata->i2c_ex); + /* enable 24-bit mode and sport */ + adv_smbus_write_byte_data(i2c_ex, 0x14, 0xfa); + adv_smbus_write_byte_data(i2c_ex, 0x15, 0xff); + adv_smbus_write_byte_data(i2c_ex, 0x0, 0x0); + adv_smbus_write_byte_data(i2c_ex, 0x1, 0x0); + i2c_unregister_device(i2c_ex); + } /* work queues */ state->work_queues = create_singlethread_workqueue(client->name); @@ -2608,6 +2755,10 @@ static int adv7842_probe(struct i2c_client *client, err = adv7842_core_init(sd, pdata); if (err) goto err_entity; + if (state->prim_mode == ADV7842_PRIM_MODE_SDP) { + state->std = V4L2_STD_UNKNOWN; + adv7842_s_std(sd, V4L2_STD_PAL); + } v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); return 0; diff --git a/include/media/adv7842.h b/include/media/adv7842.h index 0490cd9..7461745 100644 --- a/include/media/adv7842.h +++ b/include/media/adv7842.h @@ -100,8 +100,38 @@ enum adv7842_op_format_sel { ADV7842_OP_FORMAT_SEL_SDR_ITU656_24_MODE2 = 0x8a, }; +/* output format, may change with input */ +struct adv7842_output_format { + /* Bus rotation and reordering */ + enum adv7842_op_ch_sel op_ch_sel; + + /* Select output format */ + enum adv7842_op_format_sel op_format_sel; + + /* IO register 0x02 */ + unsigned op_656_range:1; + unsigned rgb_out:1; + unsigned alt_data_sat:1; + + /* IO register 0x05 */ + unsigned blank_data:1; + unsigned insert_av_codes:1; + unsigned replicate_av_codes:1; + unsigned invert_cbcr:1; + + /* IO register 0x30 */ + unsigned output_bus_lsb_to_msb:1; + + /* SDP register 0x12 */ + unsigned i2p_convert:1; +}; + /* Platform dependent definition */ struct adv7842_platform_data { + /* output format for corresponding inputs */ + struct adv7842_output_format *opf; + int num_opf; + /* connector - HDMI or DVI? */ unsigned connector_hdmi:1; @@ -114,8 +144,7 @@ struct adv7842_platform_data { /* Analog input muxing mode */ enum adv7842_ain_sel ain_sel; - /* Bus rotation and reordering */ - enum adv7842_op_ch_sel op_ch_sel; + unsigned alt_gamma:1; /* Primary mode */ enum adv7842_prim_mode prim_mode; @@ -126,24 +155,6 @@ struct adv7842_platform_data { /* Input Color Space */ enum adv7842_inp_color_space inp_color_space; - /* Select output format */ - enum adv7842_op_format_sel op_format_sel; - - /* IO register 0x02 */ - unsigned alt_gamma:1; - unsigned op_656_range:1; - unsigned rgb_out:1; - unsigned alt_data_sat:1; - - /* IO register 0x05 */ - unsigned blank_data:1; - unsigned insert_av_codes:1; - unsigned replicate_av_codes:1; - unsigned invert_cbcr:1; - - /* IO register 0x30 */ - unsigned output_bus_lsb_to_msb:1; - /* Free run */ unsigned hdmi_free_run_mode; @@ -159,6 +170,8 @@ struct adv7842_platform_data { u8 i2c_infoframe; u8 i2c_cec; u8 i2c_avlink; + /* I/O expander on ADI adv7842 ez-extender board */ + u8 i2c_ex; }; /* notify events */
_______________________________________________ Linux-kernel-commits mailing list [email protected] https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits
