diff options
Diffstat (limited to 'drivers/media/i2c/adv7604.c')
-rw-r--r-- | drivers/media/i2c/adv7604.c | 67 |
1 files changed, 40 insertions, 27 deletions
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 4abff32dc852..4003831de712 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -167,6 +167,7 @@ struct adv76xx_state { struct adv76xx_platform_data pdata; struct gpio_desc *hpd_gpio[4]; + struct gpio_desc *reset_gpio; struct v4l2_subdev sd; struct media_pad pads[ADV76XX_PAD_MAX]; @@ -187,16 +188,15 @@ struct adv76xx_state { u16 spa_port_a[2]; struct v4l2_fract aspect_ratio; u32 rgb_quantization_range; + struct delayed_work delayed_work_enable_hotplug; + bool restart_stdi_once; + /* CEC */ struct cec_adapter *cec_adap; u8 cec_addr[ADV76XX_MAX_ADDRS]; u8 cec_valid_addrs; bool cec_enabled_adap; - struct workqueue_struct *work_queues; - struct delayed_work delayed_work_enable_hotplug; - bool restart_stdi_once; - /* i2c clients */ struct i2c_client *i2c_clients[ADV76XX_PAGE_MAX]; @@ -1102,6 +1102,10 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) struct adv76xx_state *state = to_state(sd); bool rgb_output = io_read(sd, 0x02) & 0x02; bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; + u8 y = HDMI_COLORSPACE_RGB; + + if (hdmi_signal && (io_read(sd, 0x60) & 1)) + y = infoframe_read(sd, 0x01) >> 5; v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n", __func__, state->rgb_quantization_range, @@ -1109,6 +1113,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) adv76xx_set_gain(sd, true, 0x0, 0x0, 0x0); adv76xx_set_offset(sd, true, 0x0, 0x0, 0x0); + io_write_clr_set(sd, 0x02, 0x04, rgb_output ? 0 : 4); switch (state->rgb_quantization_range) { case V4L2_DV_RGB_RANGE_AUTO: @@ -1158,6 +1163,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) break; } + if (y != HDMI_COLORSPACE_RGB) + break; + /* RGB limited range (16-235) */ io_write_clr_set(sd, 0x02, 0xf0, 0x00); @@ -1169,6 +1177,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) break; } + if (y != HDMI_COLORSPACE_RGB) + break; + /* RGB full range (0-255) */ io_write_clr_set(sd, 0x02, 0xf0, 0x10); @@ -1865,6 +1876,7 @@ static void adv76xx_setup_format(struct adv76xx_state *state) io_write_clr_set(sd, 0x04, 0xe0, adv76xx_op_ch_sel(state)); io_write_clr_set(sd, 0x05, 0x01, state->format->swap_cb_cr ? ADV76XX_OP_SWAP_CB_CR : 0); + set_rgb_quantization_range(sd); } static int adv76xx_get_format(struct v4l2_subdev *sd, @@ -2360,8 +2372,7 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) cec_s_phys_addr(state->cec_adap, pa, false); /* enable hotplug after 100 ms */ - queue_delayed_work(state->work_queues, - &state->delayed_work_enable_hotplug, HZ / 10); + schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10); return 0; } @@ -2540,11 +2551,10 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) rgb_quantization_range_txt[state->rgb_quantization_range]); v4l2_info(sd, "Input color space: %s\n", input_color_space_txt[reg_io_0x02 >> 4]); - v4l2_info(sd, "Output color space: %s %s, saturator %s, alt-gamma %s\n", + v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n", (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", - (reg_io_0x02 & 0x04) ? "(16-235)" : "(0-255)", (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? - "enabled" : "disabled", + "(16-235)" : "(0-255)", (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); v4l2_info(sd, "Color space conversion: %s\n", csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]); @@ -2732,10 +2742,7 @@ static int adv76xx_core_init(struct v4l2_subdev *sd) cp_write(sd, 0xcf, 0x01); /* Power down macrovision */ /* video format */ - io_write_clr_set(sd, 0x02, 0x0f, - pdata->alt_gamma << 3 | - pdata->op_656_range << 2 | - pdata->alt_data_sat << 0); + io_write_clr_set(sd, 0x02, 0x0f, pdata->alt_gamma << 3); io_write_clr_set(sd, 0x05, 0x0e, pdata->blank_data << 3 | pdata->insert_av_codes << 2 | pdata->replicate_av_codes << 1); @@ -3085,10 +3092,8 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) state->pdata.inv_llc_pol = 1; - if (bus_cfg.bus_type == V4L2_MBUS_BT656) { + if (bus_cfg.bus_type == V4L2_MBUS_BT656) state->pdata.insert_av_codes = 1; - state->pdata.op_656_range = 1; - } /* Disable the interrupt for now as no DT-based board uses it. */ state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED; @@ -3111,7 +3116,6 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) state->pdata.disable_pwrdnb = 0; state->pdata.disable_cable_det_rst = 0; state->pdata.blank_data = 1; - state->pdata.alt_data_sat = 1; state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0; state->pdata.bus_order = ADV7604_BUS_ORDER_RGB; @@ -3260,6 +3264,19 @@ static int configure_regmaps(struct adv76xx_state *state) return 0; } +static void adv76xx_reset(struct adv76xx_state *state) +{ + if (state->reset_gpio) { + /* ADV76XX can be reset by a low reset pulse of minimum 5 ms. */ + gpiod_set_value_cansleep(state->reset_gpio, 0); + usleep_range(5000, 10000); + gpiod_set_value_cansleep(state->reset_gpio, 1); + /* It is recommended to wait 5 ms after the low pulse before */ + /* an I2C write is performed to the ADV76XX. */ + usleep_range(5000, 10000); + } +} + static int adv76xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -3323,6 +3340,12 @@ static int adv76xx_probe(struct i2c_client *client, if (state->hpd_gpio[i]) v4l_info(client, "Handling HPD %u GPIO\n", i); } + state->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(state->reset_gpio)) + return PTR_ERR(state->reset_gpio); + + adv76xx_reset(state); state->timings = cea640x480; state->format = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); @@ -3447,14 +3470,6 @@ static int adv76xx_probe(struct i2c_client *client, } } - /* work queues */ - state->work_queues = create_singlethread_workqueue(client->name); - if (!state->work_queues) { - v4l2_err(sd, "Could not create work queue\n"); - err = -ENOMEM; - goto err_i2c; - } - INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, adv76xx_delayed_work_enable_hotplug); @@ -3502,7 +3517,6 @@ err_entity: media_entity_cleanup(&sd->entity); err_work_queues: cancel_delayed_work(&state->delayed_work_enable_hotplug); - destroy_workqueue(state->work_queues); err_i2c: adv76xx_unregister_clients(state); err_hdl: @@ -3525,7 +3539,6 @@ static int adv76xx_remove(struct i2c_client *client) io_write(sd, 0x73, 0); cancel_delayed_work(&state->delayed_work_enable_hotplug); - destroy_workqueue(state->work_queues); v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); adv76xx_unregister_clients(to_state(sd)); |