Lines Matching +full:sd +full:- +full:hs
1 // SPDX-License-Identifier: GPL-2.0
5 * Author: Dingxian Wen <shawn.wen@rock-chips.com>
20 #include <linux/rk-camera-module.h>
23 #include <linux/v4l2-dv-timings.h>
28 #include <media/v4l2-controls_rockchip.h>
29 #include <media/v4l2-ctrls.h>
30 #include <media/v4l2-device.h>
31 #include <media/v4l2-dv-timings.h>
32 #include <media/v4l2-event.h>
33 #include <media/v4l2-fwnode.h>
53 MODULE_PARM_DESC(debug, "debug level (0-2)");
79 struct v4l2_subdev sd; member
186 static void lt6911uxc_format_change(struct v4l2_subdev *sd);
187 static int lt6911uxc_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd);
188 static int lt6911uxc_s_dv_timings(struct v4l2_subdev *sd,
191 static inline struct lt6911uxc *to_state(struct v4l2_subdev *sd) in to_state() argument
193 return container_of(sd, struct lt6911uxc, sd); in to_state()
196 static int i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) in i2c_rd() argument
198 struct lt6911uxc *lt6911uxc = to_state(sd); in i2c_rd()
199 struct i2c_client *client = lt6911uxc->i2c_client; in i2c_rd()
207 msgs[0].addr = client->addr; in i2c_rd()
213 msgs[1].addr = client->addr; in i2c_rd()
219 msgs[2].addr = client->addr; in i2c_rd()
224 err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); in i2c_rd()
226 v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", in i2c_rd()
227 __func__, reg, client->addr); in i2c_rd()
228 return -EIO; in i2c_rd()
234 static int i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) in i2c_wr() argument
236 struct lt6911uxc *lt6911uxc = to_state(sd); in i2c_wr()
237 struct i2c_client *client = lt6911uxc->i2c_client; in i2c_wr()
246 n = I2C_MAX_XFER_SIZE - 1; in i2c_wr()
247 v4l2_warn(sd, "i2c wr reg=%04x: len=%d is too big!\n", reg, in i2c_wr()
256 msgs[0].addr = client->addr; in i2c_wr()
262 msgs[1].addr = client->addr; in i2c_wr()
267 err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); in i2c_wr()
269 v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n", in i2c_wr()
270 __func__, reg, client->addr); in i2c_wr()
271 return -EIO; in i2c_wr()
277 static int i2c_rd8(struct v4l2_subdev *sd, u16 reg, u8 *val_p) in i2c_rd8() argument
279 return i2c_rd(sd, reg, val_p, 1); in i2c_rd8()
282 static int i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) in i2c_wr8() argument
284 return i2c_wr(sd, reg, &val, 1); in i2c_wr8()
287 static void lt6911uxc_i2c_enable(struct v4l2_subdev *sd) in lt6911uxc_i2c_enable() argument
289 i2c_wr8(sd, I2C_EN_REG, I2C_ENABLE); in lt6911uxc_i2c_enable()
292 static void lt6911uxc_i2c_disable(struct v4l2_subdev *sd) in lt6911uxc_i2c_disable() argument
294 i2c_wr8(sd, I2C_EN_REG, I2C_DISABLE); in lt6911uxc_i2c_disable()
297 static inline bool tx_5v_power_present(struct v4l2_subdev *sd) in tx_5v_power_present() argument
301 struct lt6911uxc *lt6911uxc = to_state(sd); in tx_5v_power_present()
304 if (!lt6911uxc->plugin_det_gpio) in tx_5v_power_present()
309 val = gpiod_get_value(lt6911uxc->plugin_det_gpio); in tx_5v_power_present()
317 v4l2_dbg(1, debug, sd, "%s: %d\n", __func__, ret); in tx_5v_power_present()
322 static inline bool no_signal(struct v4l2_subdev *sd) in no_signal() argument
324 struct lt6911uxc *lt6911uxc = to_state(sd); in no_signal()
326 v4l2_dbg(1, debug, sd, "%s no signal:%d\n", __func__, in no_signal()
327 lt6911uxc->nosignal); in no_signal()
329 return lt6911uxc->nosignal; in no_signal()
332 static inline bool audio_present(struct v4l2_subdev *sd) in audio_present() argument
334 struct lt6911uxc *lt6911uxc = to_state(sd); in audio_present()
336 return lt6911uxc->is_audio_present; in audio_present()
339 static int get_audio_sampling_rate(struct v4l2_subdev *sd) in get_audio_sampling_rate() argument
341 struct lt6911uxc *lt6911uxc = to_state(sd); in get_audio_sampling_rate()
343 if (no_signal(sd)) in get_audio_sampling_rate()
346 return lt6911uxc->audio_sampling_rate; in get_audio_sampling_rate()
354 return DIV_ROUND_CLOSEST((unsigned int)t->pixelclock, in fps_calc()
358 static bool lt6911uxc_rcv_supported_res(struct v4l2_subdev *sd, u32 width, in lt6911uxc_rcv_supported_res() argument
371 v4l2_err(sd, "%s do not support res wxh: %dx%d\n", __func__, in lt6911uxc_rcv_supported_res()
379 static int lt6911uxc_get_detected_timings(struct v4l2_subdev *sd, in lt6911uxc_get_detected_timings() argument
382 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_get_detected_timings()
383 struct v4l2_bt_timings *bt = &timings->bt; in lt6911uxc_get_detected_timings()
385 u32 hbp, hs, hfp, vbp, vs, vfp; in lt6911uxc_get_detected_timings() local
394 lt6911uxc_i2c_enable(sd); in lt6911uxc_get_detected_timings()
396 ret = i2c_rd8(sd, FW_VER_A, &fw_a); in lt6911uxc_get_detected_timings()
397 ret |= i2c_rd8(sd, FW_VER_B, &fw_b); in lt6911uxc_get_detected_timings()
398 ret |= i2c_rd8(sd, FW_VER_C, &fw_c); in lt6911uxc_get_detected_timings()
399 ret |= i2c_rd8(sd, FW_VER_D, &fw_d); in lt6911uxc_get_detected_timings()
401 v4l2_err(sd, "%s: I2C transform err!\n", __func__); in lt6911uxc_get_detected_timings()
402 return -ENOLINK; in lt6911uxc_get_detected_timings()
405 v4l2_info(sd, "read fw_version:%#x", fw_ver); in lt6911uxc_get_detected_timings()
406 i2c_wr8(sd, INT_COMPARE_REG, RECEIVED_INT); in lt6911uxc_get_detected_timings()
408 i2c_rd8(sd, INT_STATUS_86A3, &val_h); in lt6911uxc_get_detected_timings()
409 i2c_rd8(sd, INT_STATUS_86A5, &val_l); in lt6911uxc_get_detected_timings()
410 v4l2_info(sd, "int status REG_86A3:%#x, REG_86A5:%#x\n", val_h, val_l); in lt6911uxc_get_detected_timings()
412 i2c_rd8(sd, HDMI_VERSION, &value); in lt6911uxc_get_detected_timings()
413 i2c_rd8(sd, TMDS_CLK_H, &clk_h); in lt6911uxc_get_detected_timings()
414 i2c_rd8(sd, TMDS_CLK_M, &clk_m); in lt6911uxc_get_detected_timings()
415 i2c_rd8(sd, TMDS_CLK_L, &clk_l); in lt6911uxc_get_detected_timings()
420 i2c_rd8(sd, MIPI_LANES, &lanes); in lt6911uxc_get_detected_timings()
421 lt6911uxc->csi_lanes_in_use = lanes; in lt6911uxc_get_detected_timings()
422 i2c_wr8(sd, FM1_DET_CLK_SRC_SEL, AD_LMTX_WRITE_CLK); in lt6911uxc_get_detected_timings()
423 i2c_rd8(sd, FREQ_METER_H, &clk_h); in lt6911uxc_get_detected_timings()
424 i2c_rd8(sd, FREQ_METER_M, &clk_m); in lt6911uxc_get_detected_timings()
425 i2c_rd8(sd, FREQ_METER_L, &clk_l); in lt6911uxc_get_detected_timings()
428 v4l2_info(sd, "MIPI Byte clk: %dKHz, MIPI bitrate: %dMbps, lanes:%d\n", in lt6911uxc_get_detected_timings()
431 i2c_rd8(sd, HTOTAL_H, &val_h); in lt6911uxc_get_detected_timings()
432 i2c_rd8(sd, HTOTAL_L, &val_l); in lt6911uxc_get_detected_timings()
434 i2c_rd8(sd, VTOTAL_H, &val_h); in lt6911uxc_get_detected_timings()
435 i2c_rd8(sd, VTOTAL_L, &val_l); in lt6911uxc_get_detected_timings()
437 i2c_rd8(sd, HACT_H, &val_h); in lt6911uxc_get_detected_timings()
438 i2c_rd8(sd, HACT_L, &val_l); in lt6911uxc_get_detected_timings()
440 i2c_rd8(sd, VACT_H, &val_h); in lt6911uxc_get_detected_timings()
441 i2c_rd8(sd, VACT_L, &val_l); in lt6911uxc_get_detected_timings()
443 i2c_rd8(sd, HS_H, &val_h); in lt6911uxc_get_detected_timings()
444 i2c_rd8(sd, HS_L, &val_l); in lt6911uxc_get_detected_timings()
445 hs = ((val_h << 8) | val_l) * 2; in lt6911uxc_get_detected_timings()
446 i2c_rd8(sd, VS, &value); in lt6911uxc_get_detected_timings()
448 i2c_rd8(sd, HFP_H, &val_h); in lt6911uxc_get_detected_timings()
449 i2c_rd8(sd, HFP_L, &val_l); in lt6911uxc_get_detected_timings()
451 i2c_rd8(sd, VFP, &value); in lt6911uxc_get_detected_timings()
453 i2c_rd8(sd, HBP_H, &val_h); in lt6911uxc_get_detected_timings()
454 i2c_rd8(sd, HBP_L, &val_l); in lt6911uxc_get_detected_timings()
456 i2c_rd8(sd, VBP, &value); in lt6911uxc_get_detected_timings()
458 lt6911uxc_i2c_disable(sd); in lt6911uxc_get_detected_timings()
460 if (!lt6911uxc_rcv_supported_res(sd, hact, vact)) { in lt6911uxc_get_detected_timings()
461 lt6911uxc->nosignal = true; in lt6911uxc_get_detected_timings()
462 v4l2_err(sd, "%s: rcv err res, return no signal!\n", __func__); in lt6911uxc_get_detected_timings()
463 return -EINVAL; in lt6911uxc_get_detected_timings()
466 lt6911uxc->nosignal = false; in lt6911uxc_get_detected_timings()
467 i2c_rd8(sd, AUDIO_IN_STATUS, &value); in lt6911uxc_get_detected_timings()
468 lt6911uxc->is_audio_present = (value & BIT(5)) ? true : false; in lt6911uxc_get_detected_timings()
469 i2c_rd8(sd, AUDIO_SAMPLE_RATAE_H, &val_h); in lt6911uxc_get_detected_timings()
470 i2c_rd8(sd, AUDIO_SAMPLE_RATAE_L, &val_l); in lt6911uxc_get_detected_timings()
471 lt6911uxc->audio_sampling_rate = ((val_h << 8) | val_l) + 2; in lt6911uxc_get_detected_timings()
472 v4l2_info(sd, "is_audio_present: %d, audio_sampling_rate: %dKhz\n", in lt6911uxc_get_detected_timings()
473 lt6911uxc->is_audio_present, in lt6911uxc_get_detected_timings()
474 lt6911uxc->audio_sampling_rate); in lt6911uxc_get_detected_timings()
476 timings->type = V4L2_DV_BT_656_1120; in lt6911uxc_get_detected_timings()
477 bt->width = hact; in lt6911uxc_get_detected_timings()
478 bt->height = vact; in lt6911uxc_get_detected_timings()
479 bt->vsync = vs; in lt6911uxc_get_detected_timings()
480 bt->hsync = hs; in lt6911uxc_get_detected_timings()
481 bt->pixelclock = pixel_clock; in lt6911uxc_get_detected_timings()
482 bt->hfrontporch = hfp; in lt6911uxc_get_detected_timings()
483 bt->vfrontporch = vfp; in lt6911uxc_get_detected_timings()
484 bt->hbackporch = hbp; in lt6911uxc_get_detected_timings()
485 bt->vbackporch = vbp; in lt6911uxc_get_detected_timings()
491 bt->interlaced = V4L2_DV_INTERLACED; in lt6911uxc_get_detected_timings()
492 bt->height *= 2; in lt6911uxc_get_detected_timings()
493 bt->il_vsync = bt->vsync + 1; in lt6911uxc_get_detected_timings()
495 bt->interlaced = V4L2_DV_PROGRESSIVE; in lt6911uxc_get_detected_timings()
498 v4l2_info(sd, "act:%dx%d, total:%dx%d, pixclk:%d, fps:%d\n", in lt6911uxc_get_detected_timings()
500 v4l2_info(sd, "hfp:%d, hs:%d, hbp:%d, vfp:%d, vs:%d, vbp:%d, inerlaced:%d\n", in lt6911uxc_get_detected_timings()
501 bt->hfrontporch, bt->hsync, bt->hbackporch, bt->vfrontporch, in lt6911uxc_get_detected_timings()
502 bt->vsync, bt->vbackporch, bt->interlaced); in lt6911uxc_get_detected_timings()
507 static void lt6911uxc_config_hpd(struct v4l2_subdev *sd) in lt6911uxc_config_hpd() argument
509 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_config_hpd()
512 plugin = tx_5v_power_present(sd); in lt6911uxc_config_hpd()
513 v4l2_dbg(2, debug, sd, "%s: plugin: %d\n", __func__, plugin); in lt6911uxc_config_hpd()
516 gpiod_set_value(lt6911uxc->hpd_ctl_gpio, 1); in lt6911uxc_config_hpd()
518 lt6911uxc->nosignal = true; in lt6911uxc_config_hpd()
519 gpiod_set_value(lt6911uxc->hpd_ctl_gpio, 0); in lt6911uxc_config_hpd()
528 struct v4l2_subdev *sd = <6911uxc->sd; in lt6911uxc_delayed_work_enable_hotplug() local
530 v4l2_dbg(2, debug, sd, "%s:\n", __func__); in lt6911uxc_delayed_work_enable_hotplug()
532 v4l2_ctrl_s_ctrl(lt6911uxc->detect_tx_5v_ctrl, tx_5v_power_present(sd)); in lt6911uxc_delayed_work_enable_hotplug()
533 lt6911uxc_config_hpd(sd); in lt6911uxc_delayed_work_enable_hotplug()
541 struct v4l2_subdev *sd = <6911uxc->sd; in lt6911uxc_delayed_work_res_change() local
543 v4l2_dbg(2, debug, sd, "%s:\n", __func__); in lt6911uxc_delayed_work_res_change()
544 lt6911uxc_format_change(sd); in lt6911uxc_delayed_work_res_change()
547 static int lt6911uxc_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd) in lt6911uxc_s_ctrl_detect_tx_5v() argument
549 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_s_ctrl_detect_tx_5v()
551 return v4l2_ctrl_s_ctrl(lt6911uxc->detect_tx_5v_ctrl, in lt6911uxc_s_ctrl_detect_tx_5v()
552 tx_5v_power_present(sd)); in lt6911uxc_s_ctrl_detect_tx_5v()
555 static int lt6911uxc_s_ctrl_audio_sampling_rate(struct v4l2_subdev *sd) in lt6911uxc_s_ctrl_audio_sampling_rate() argument
557 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_s_ctrl_audio_sampling_rate()
559 return v4l2_ctrl_s_ctrl(lt6911uxc->audio_sampling_rate_ctrl, in lt6911uxc_s_ctrl_audio_sampling_rate()
560 get_audio_sampling_rate(sd)); in lt6911uxc_s_ctrl_audio_sampling_rate()
563 static int lt6911uxc_s_ctrl_audio_present(struct v4l2_subdev *sd) in lt6911uxc_s_ctrl_audio_present() argument
565 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_s_ctrl_audio_present()
567 return v4l2_ctrl_s_ctrl(lt6911uxc->audio_present_ctrl, in lt6911uxc_s_ctrl_audio_present()
568 audio_present(sd)); in lt6911uxc_s_ctrl_audio_present()
571 static int lt6911uxc_update_controls(struct v4l2_subdev *sd) in lt6911uxc_update_controls() argument
575 ret |= lt6911uxc_s_ctrl_detect_tx_5v(sd); in lt6911uxc_update_controls()
576 ret |= lt6911uxc_s_ctrl_audio_sampling_rate(sd); in lt6911uxc_update_controls()
577 ret |= lt6911uxc_s_ctrl_audio_present(sd); in lt6911uxc_update_controls()
582 static inline void enable_stream(struct v4l2_subdev *sd, bool enable) in enable_stream() argument
584 v4l2_dbg(2, debug, sd, "%s: %sable\n", in enable_stream()
588 static void lt6911uxc_format_change(struct v4l2_subdev *sd) in lt6911uxc_format_change() argument
590 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_format_change()
597 if (lt6911uxc_get_detected_timings(sd, &timings)) { in lt6911uxc_format_change()
598 enable_stream(sd, false); in lt6911uxc_format_change()
600 v4l2_dbg(1, debug, sd, "%s: No signal\n", __func__); in lt6911uxc_format_change()
602 if (!v4l2_match_dv_timings(<6911uxc->timings, &timings, 0, in lt6911uxc_format_change()
604 enable_stream(sd, false); in lt6911uxc_format_change()
606 lt6911uxc_s_dv_timings(sd, &timings); in lt6911uxc_format_change()
607 v4l2_print_dv_timings(sd->name, in lt6911uxc_format_change()
613 if (sd->devnode) in lt6911uxc_format_change()
614 v4l2_subdev_notify_event(sd, <6911uxc_ev_fmt); in lt6911uxc_format_change()
617 static int lt6911uxc_isr(struct v4l2_subdev *sd, u32 status, bool *handled) in lt6911uxc_isr() argument
619 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_isr()
621 schedule_delayed_work(<6911uxc->delayed_work_res_change, HZ / 20); in lt6911uxc_isr()
632 lt6911uxc_isr(<6911uxc->sd, 0, &handled); in lt6911uxc_res_change_irq_handler()
640 struct v4l2_subdev *sd = <6911uxc->sd; in plugin_detect_irq_handler() local
643 schedule_delayed_work(<6911uxc->delayed_work_enable_hotplug, in plugin_detect_irq_handler()
645 tx_5v_power_present(sd); in plugin_detect_irq_handler()
650 static int lt6911uxc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, in lt6911uxc_subscribe_event() argument
653 switch (sub->type) { in lt6911uxc_subscribe_event()
655 return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); in lt6911uxc_subscribe_event()
657 return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); in lt6911uxc_subscribe_event()
659 return -EINVAL; in lt6911uxc_subscribe_event()
663 static int lt6911uxc_g_input_status(struct v4l2_subdev *sd, u32 *status) in lt6911uxc_g_input_status() argument
666 *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; in lt6911uxc_g_input_status()
667 v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); in lt6911uxc_g_input_status()
672 static int lt6911uxc_s_dv_timings(struct v4l2_subdev *sd, in lt6911uxc_s_dv_timings() argument
675 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_s_dv_timings()
678 return -EINVAL; in lt6911uxc_s_dv_timings()
681 v4l2_print_dv_timings(sd->name, "s_dv_timings: ", timings, false); in lt6911uxc_s_dv_timings()
683 if (v4l2_match_dv_timings(<6911uxc->timings, timings, 0, false)) { in lt6911uxc_s_dv_timings()
684 v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); in lt6911uxc_s_dv_timings()
690 v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); in lt6911uxc_s_dv_timings()
691 return -ERANGE; in lt6911uxc_s_dv_timings()
694 lt6911uxc->timings = *timings; in lt6911uxc_s_dv_timings()
696 enable_stream(sd, false); in lt6911uxc_s_dv_timings()
701 static int lt6911uxc_g_dv_timings(struct v4l2_subdev *sd, in lt6911uxc_g_dv_timings() argument
704 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_g_dv_timings()
706 *timings = lt6911uxc->timings; in lt6911uxc_g_dv_timings()
711 static int lt6911uxc_enum_dv_timings(struct v4l2_subdev *sd, in lt6911uxc_enum_dv_timings() argument
714 if (timings->pad != 0) in lt6911uxc_enum_dv_timings()
715 return -EINVAL; in lt6911uxc_enum_dv_timings()
721 static int lt6911uxc_query_dv_timings(struct v4l2_subdev *sd, in lt6911uxc_query_dv_timings() argument
724 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_query_dv_timings()
726 *timings = lt6911uxc->timings; in lt6911uxc_query_dv_timings()
728 v4l2_print_dv_timings(sd->name, "query_dv_timings: ", timings, false); in lt6911uxc_query_dv_timings()
732 v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); in lt6911uxc_query_dv_timings()
734 return -ERANGE; in lt6911uxc_query_dv_timings()
740 static int lt6911uxc_dv_timings_cap(struct v4l2_subdev *sd, in lt6911uxc_dv_timings_cap() argument
743 if (cap->pad != 0) in lt6911uxc_dv_timings_cap()
744 return -EINVAL; in lt6911uxc_dv_timings_cap()
751 static int lt6911uxc_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, in lt6911uxc_g_mbus_config() argument
754 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_g_mbus_config()
756 cfg->type = V4L2_MBUS_CSI2_DPHY; in lt6911uxc_g_mbus_config()
757 cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_CHANNEL_0; in lt6911uxc_g_mbus_config()
759 switch (lt6911uxc->csi_lanes_in_use) { in lt6911uxc_g_mbus_config()
761 cfg->flags |= V4L2_MBUS_CSI2_1_LANE; in lt6911uxc_g_mbus_config()
764 cfg->flags |= V4L2_MBUS_CSI2_2_LANE; in lt6911uxc_g_mbus_config()
767 cfg->flags |= V4L2_MBUS_CSI2_3_LANE; in lt6911uxc_g_mbus_config()
770 cfg->flags |= V4L2_MBUS_CSI2_4_LANE; in lt6911uxc_g_mbus_config()
774 return -EINVAL; in lt6911uxc_g_mbus_config()
780 static int lt6911uxc_s_stream(struct v4l2_subdev *sd, int enable) in lt6911uxc_s_stream() argument
782 enable_stream(sd, enable); in lt6911uxc_s_stream()
787 static int lt6911uxc_enum_mbus_code(struct v4l2_subdev *sd, in lt6911uxc_enum_mbus_code() argument
791 switch (code->index) { in lt6911uxc_enum_mbus_code()
793 code->code = LT6911UXC_MEDIA_BUS_FMT; in lt6911uxc_enum_mbus_code()
797 return -EINVAL; in lt6911uxc_enum_mbus_code()
803 static int lt6911uxc_enum_frame_sizes(struct v4l2_subdev *sd, in lt6911uxc_enum_frame_sizes() argument
807 if (fse->index >= ARRAY_SIZE(supported_modes)) in lt6911uxc_enum_frame_sizes()
808 return -EINVAL; in lt6911uxc_enum_frame_sizes()
810 if (fse->code != LT6911UXC_MEDIA_BUS_FMT) in lt6911uxc_enum_frame_sizes()
811 return -EINVAL; in lt6911uxc_enum_frame_sizes()
813 fse->min_width = supported_modes[fse->index].width; in lt6911uxc_enum_frame_sizes()
814 fse->max_width = supported_modes[fse->index].width; in lt6911uxc_enum_frame_sizes()
815 fse->max_height = supported_modes[fse->index].height; in lt6911uxc_enum_frame_sizes()
816 fse->min_height = supported_modes[fse->index].height; in lt6911uxc_enum_frame_sizes()
821 static int lt6911uxc_enum_frame_interval(struct v4l2_subdev *sd, in lt6911uxc_enum_frame_interval() argument
825 if (fie->index >= ARRAY_SIZE(supported_modes)) in lt6911uxc_enum_frame_interval()
826 return -EINVAL; in lt6911uxc_enum_frame_interval()
828 fie->code = LT6911UXC_MEDIA_BUS_FMT; in lt6911uxc_enum_frame_interval()
830 fie->width = supported_modes[fie->index].width; in lt6911uxc_enum_frame_interval()
831 fie->height = supported_modes[fie->index].height; in lt6911uxc_enum_frame_interval()
832 fie->interval = supported_modes[fie->index].max_fps; in lt6911uxc_enum_frame_interval()
837 static int lt6911uxc_get_fmt(struct v4l2_subdev *sd, in lt6911uxc_get_fmt() argument
841 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_get_fmt()
843 mutex_lock(<6911uxc->confctl_mutex); in lt6911uxc_get_fmt()
844 format->format.code = lt6911uxc->mbus_fmt_code; in lt6911uxc_get_fmt()
845 format->format.width = lt6911uxc->timings.bt.width; in lt6911uxc_get_fmt()
846 format->format.height = lt6911uxc->timings.bt.height; in lt6911uxc_get_fmt()
847 format->format.field = in lt6911uxc_get_fmt()
848 lt6911uxc->timings.bt.interlaced ? in lt6911uxc_get_fmt()
850 format->format.colorspace = V4L2_COLORSPACE_SRGB; in lt6911uxc_get_fmt()
851 mutex_unlock(<6911uxc->confctl_mutex); in lt6911uxc_get_fmt()
853 v4l2_dbg(1, debug, sd, "%s: fmt code:%d, w:%d, h:%d, field mode:%s\n", in lt6911uxc_get_fmt()
854 __func__, format->format.code, format->format.width, format->format.height, in lt6911uxc_get_fmt()
855 (format->format.field == V4L2_FIELD_INTERLACED) ? "I" : "P"); in lt6911uxc_get_fmt()
863 return abs(mode->width - framefmt->width) + in lt6911uxc_get_reso_dist()
864 abs(mode->height - framefmt->height); in lt6911uxc_get_reso_dist()
870 struct v4l2_mbus_framefmt *framefmt = &fmt->format; in lt6911uxc_find_best_fit()
873 int cur_best_fit_dist = -1; in lt6911uxc_find_best_fit()
878 if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { in lt6911uxc_find_best_fit()
887 static int lt6911uxc_set_fmt(struct v4l2_subdev *sd, in lt6911uxc_set_fmt() argument
891 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_set_fmt()
896 u32 code = format->format.code; in lt6911uxc_set_fmt()
897 int ret = lt6911uxc_get_fmt(sd, cfg, format); in lt6911uxc_set_fmt()
899 format->format.code = code; in lt6911uxc_set_fmt()
909 return -EINVAL; in lt6911uxc_set_fmt()
912 if (format->which == V4L2_SUBDEV_FORMAT_TRY) in lt6911uxc_set_fmt()
915 lt6911uxc->mbus_fmt_code = format->format.code; in lt6911uxc_set_fmt()
917 lt6911uxc->cur_mode = mode; in lt6911uxc_set_fmt()
918 enable_stream(sd, false); in lt6911uxc_set_fmt()
920 if (((mode->width == 720) && (mode->height == 576)) || in lt6911uxc_set_fmt()
921 ((mode->width == 720) && (mode->height == 480))) in lt6911uxc_set_fmt()
926 __v4l2_ctrl_s_ctrl(lt6911uxc->link_freq, index); in lt6911uxc_set_fmt()
927 v4l2_dbg(1, debug, sd, "%s res wxh:%dx%d, link freq:%llu", __func__, in lt6911uxc_set_fmt()
928 mode->width, mode->height, link_freq_menu_items[index]); in lt6911uxc_set_fmt()
933 static int lt6911uxc_g_frame_interval(struct v4l2_subdev *sd, in lt6911uxc_g_frame_interval() argument
936 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_g_frame_interval()
937 const struct lt6911uxc_mode *mode = lt6911uxc->cur_mode; in lt6911uxc_g_frame_interval()
939 mutex_lock(<6911uxc->confctl_mutex); in lt6911uxc_g_frame_interval()
940 fi->interval = mode->max_fps; in lt6911uxc_g_frame_interval()
941 mutex_unlock(<6911uxc->confctl_mutex); in lt6911uxc_g_frame_interval()
950 strscpy(inf->base.sensor, LT6911UXC_NAME, sizeof(inf->base.sensor)); in lt6911uxc_get_module_inf()
951 strscpy(inf->base.module, lt6911uxc->module_name, sizeof(inf->base.module)); in lt6911uxc_get_module_inf()
952 strscpy(inf->base.lens, lt6911uxc->len_name, sizeof(inf->base.lens)); in lt6911uxc_get_module_inf()
955 static long lt6911uxc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) in lt6911uxc_ioctl() argument
957 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_ioctl()
968 ret = -ENOIOCTLCMD; in lt6911uxc_ioctl()
976 static long lt6911uxc_compat_ioctl32(struct v4l2_subdev *sd, in lt6911uxc_compat_ioctl32() argument
988 ret = -ENOMEM; in lt6911uxc_compat_ioctl32()
992 ret = lt6911uxc_ioctl(sd, cmd, inf); in lt6911uxc_compat_ioctl32()
996 ret = -EFAULT; in lt6911uxc_compat_ioctl32()
1003 ret = -ENOMEM; in lt6911uxc_compat_ioctl32()
1007 ret = lt6911uxc_ioctl(sd, cmd, seq); in lt6911uxc_compat_ioctl32()
1011 ret = -EFAULT; in lt6911uxc_compat_ioctl32()
1016 ret = -ENOIOCTLCMD; in lt6911uxc_compat_ioctl32()
1084 gpiod_set_value(lt6911uxc->reset_gpio, 0); in lt6911uxc_reset()
1086 gpiod_set_value(lt6911uxc->reset_gpio, 1); in lt6911uxc_reset()
1088 gpiod_set_value(lt6911uxc->reset_gpio, 0); in lt6911uxc_reset()
1094 struct v4l2_subdev *sd; in lt6911uxc_init_v4l2_ctrls() local
1097 sd = <6911uxc->sd; in lt6911uxc_init_v4l2_ctrls()
1098 ret = v4l2_ctrl_handler_init(<6911uxc->hdl, 5); in lt6911uxc_init_v4l2_ctrls()
1102 lt6911uxc->link_freq = v4l2_ctrl_new_int_menu(<6911uxc->hdl, NULL, in lt6911uxc_init_v4l2_ctrls()
1104 ARRAY_SIZE(link_freq_menu_items) - 1, 0, in lt6911uxc_init_v4l2_ctrls()
1106 v4l2_ctrl_new_std(<6911uxc->hdl, NULL, V4L2_CID_PIXEL_RATE, in lt6911uxc_init_v4l2_ctrls()
1109 lt6911uxc->detect_tx_5v_ctrl = v4l2_ctrl_new_std(<6911uxc->hdl, in lt6911uxc_init_v4l2_ctrls()
1113 lt6911uxc->audio_sampling_rate_ctrl = in lt6911uxc_init_v4l2_ctrls()
1114 v4l2_ctrl_new_custom(<6911uxc->hdl, in lt6911uxc_init_v4l2_ctrls()
1116 lt6911uxc->audio_present_ctrl = v4l2_ctrl_new_custom(<6911uxc->hdl, in lt6911uxc_init_v4l2_ctrls()
1119 sd->ctrl_handler = <6911uxc->hdl; in lt6911uxc_init_v4l2_ctrls()
1120 if (lt6911uxc->hdl.error) { in lt6911uxc_init_v4l2_ctrls()
1121 ret = lt6911uxc->hdl.error; in lt6911uxc_init_v4l2_ctrls()
1122 v4l2_err(sd, "cfg v4l2 ctrls failed! ret:%d\n", ret); in lt6911uxc_init_v4l2_ctrls()
1126 if (lt6911uxc_update_controls(sd)) { in lt6911uxc_init_v4l2_ctrls()
1127 ret = -ENODEV; in lt6911uxc_init_v4l2_ctrls()
1128 v4l2_err(sd, "update v4l2 ctrls failed! ret:%d\n", ret); in lt6911uxc_init_v4l2_ctrls()
1137 struct device *dev = <6911uxc->i2c_client->dev; in lt6911uxc_check_chip_id()
1138 struct v4l2_subdev *sd = <6911uxc->sd; in lt6911uxc_check_chip_id() local
1144 lt6911uxc_i2c_enable(sd); in lt6911uxc_check_chip_id()
1145 ret = i2c_rd8(sd, CHIPID_L, &id_l); in lt6911uxc_check_chip_id()
1146 ret |= i2c_rd8(sd, CHIPID_H, &id_h); in lt6911uxc_check_chip_id()
1148 ret |= i2c_rd8(sd, FW_VER_A, &fw_a); in lt6911uxc_check_chip_id()
1149 ret |= i2c_rd8(sd, FW_VER_B, &fw_b); in lt6911uxc_check_chip_id()
1150 ret |= i2c_rd8(sd, FW_VER_C, &fw_c); in lt6911uxc_check_chip_id()
1151 ret |= i2c_rd8(sd, FW_VER_D, &fw_d); in lt6911uxc_check_chip_id()
1152 lt6911uxc_i2c_disable(sd); in lt6911uxc_check_chip_id()
1159 return -EINVAL; in lt6911uxc_check_chip_id()
1175 struct device *dev = <6911uxc->i2c_client->dev; in lt6911uxc_parse_of()
1176 struct device_node *node = dev->of_node; in lt6911uxc_parse_of()
1182 <6911uxc->module_index); in lt6911uxc_parse_of()
1184 <6911uxc->module_facing); in lt6911uxc_parse_of()
1186 <6911uxc->module_name); in lt6911uxc_parse_of()
1188 <6911uxc->len_name); in lt6911uxc_parse_of()
1191 return -EINVAL; in lt6911uxc_parse_of()
1194 lt6911uxc->power_gpio = devm_gpiod_get_optional(dev, "power", in lt6911uxc_parse_of()
1196 if (IS_ERR(lt6911uxc->power_gpio)) { in lt6911uxc_parse_of()
1198 ret = PTR_ERR(lt6911uxc->power_gpio); in lt6911uxc_parse_of()
1202 lt6911uxc->reset_gpio = devm_gpiod_get_optional(dev, "reset", in lt6911uxc_parse_of()
1204 if (IS_ERR(lt6911uxc->reset_gpio)) { in lt6911uxc_parse_of()
1206 ret = PTR_ERR(lt6911uxc->reset_gpio); in lt6911uxc_parse_of()
1210 lt6911uxc->plugin_det_gpio = devm_gpiod_get_optional(dev, "plugin-det", in lt6911uxc_parse_of()
1212 if (IS_ERR(lt6911uxc->plugin_det_gpio)) { in lt6911uxc_parse_of()
1214 ret = PTR_ERR(lt6911uxc->plugin_det_gpio); in lt6911uxc_parse_of()
1218 lt6911uxc->hpd_ctl_gpio = devm_gpiod_get_optional(dev, "hpd-ctl", in lt6911uxc_parse_of()
1220 if (IS_ERR(lt6911uxc->hpd_ctl_gpio)) { in lt6911uxc_parse_of()
1222 ret = PTR_ERR(lt6911uxc->hpd_ctl_gpio); in lt6911uxc_parse_of()
1226 ep = of_graph_get_next_endpoint(dev->of_node, NULL); in lt6911uxc_parse_of()
1229 ret = -EINVAL; in lt6911uxc_parse_of()
1241 dev_err(dev, "missing CSI-2 properties in endpoint\n"); in lt6911uxc_parse_of()
1242 ret = -EINVAL; in lt6911uxc_parse_of()
1246 lt6911uxc->xvclk = devm_clk_get(dev, "xvclk"); in lt6911uxc_parse_of()
1247 if (IS_ERR(lt6911uxc->xvclk)) { in lt6911uxc_parse_of()
1249 ret = -EINVAL; in lt6911uxc_parse_of()
1253 ret = clk_prepare_enable(lt6911uxc->xvclk); in lt6911uxc_parse_of()
1259 lt6911uxc->csi_lanes_in_use = endpoint.bus.mipi_csi2.num_data_lanes; in lt6911uxc_parse_of()
1260 lt6911uxc->bus = endpoint.bus.mipi_csi2; in lt6911uxc_parse_of()
1261 lt6911uxc->enable_hdcp = false; in lt6911uxc_parse_of()
1263 gpiod_set_value(lt6911uxc->hpd_ctl_gpio, 0); in lt6911uxc_parse_of()
1264 gpiod_set_value(lt6911uxc->power_gpio, 1); in lt6911uxc_parse_of()
1278 return -ENODEV; in lt6911uxc_parse_of()
1288 struct v4l2_subdev *sd; in lt6911uxc_probe() local
1289 struct device *dev = &client->dev; in lt6911uxc_probe()
1300 return -ENOMEM; in lt6911uxc_probe()
1302 sd = <6911uxc->sd; in lt6911uxc_probe()
1303 lt6911uxc->i2c_client = client; in lt6911uxc_probe()
1304 lt6911uxc->timings = default_timing; in lt6911uxc_probe()
1305 lt6911uxc->cur_mode = &supported_modes[0]; in lt6911uxc_probe()
1306 lt6911uxc->mbus_fmt_code = LT6911UXC_MEDIA_BUS_FMT; in lt6911uxc_probe()
1310 v4l2_err(sd, "lt6911uxc_parse_of failed! err:%d\n", err); in lt6911uxc_probe()
1323 mutex_init(<6911uxc->confctl_mutex); in lt6911uxc_probe()
1328 client->flags |= I2C_CLIENT_SCCB; in lt6911uxc_probe()
1330 v4l2_i2c_subdev_init(sd, client, <6911uxc_ops); in lt6911uxc_probe()
1331 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; in lt6911uxc_probe()
1335 lt6911uxc->pad.flags = MEDIA_PAD_FL_SOURCE; in lt6911uxc_probe()
1336 sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; in lt6911uxc_probe()
1337 err = media_entity_pads_init(&sd->entity, 1, <6911uxc->pad); in lt6911uxc_probe()
1339 v4l2_err(sd, "media entity init failed! err: %d\n", err); in lt6911uxc_probe()
1344 if (strcmp(lt6911uxc->module_facing, "back") == 0) in lt6911uxc_probe()
1349 snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s", in lt6911uxc_probe()
1350 lt6911uxc->module_index, facing, in lt6911uxc_probe()
1351 LT6911UXC_NAME, dev_name(sd->dev)); in lt6911uxc_probe()
1352 err = v4l2_async_register_subdev_sensor_common(sd); in lt6911uxc_probe()
1354 v4l2_err(sd, "v4l2 register subdev failed! err:%d\n", err); in lt6911uxc_probe()
1358 INIT_DELAYED_WORK(<6911uxc->delayed_work_enable_hotplug, in lt6911uxc_probe()
1360 INIT_DELAYED_WORK(<6911uxc->delayed_work_res_change, in lt6911uxc_probe()
1363 if (lt6911uxc->i2c_client->irq) { in lt6911uxc_probe()
1364 v4l2_dbg(1, debug, sd, "cfg lt6911uxc irq!\n"); in lt6911uxc_probe()
1366 lt6911uxc->i2c_client->irq, in lt6911uxc_probe()
1371 v4l2_err(sd, "request irq failed! err:%d\n", err); in lt6911uxc_probe()
1375 err = -EINVAL; in lt6911uxc_probe()
1376 v4l2_err(sd, "no irq cfg failed!\n"); in lt6911uxc_probe()
1380 lt6911uxc->plugin_irq = gpiod_to_irq(lt6911uxc->plugin_det_gpio); in lt6911uxc_probe()
1381 if (lt6911uxc->plugin_irq < 0) in lt6911uxc_probe()
1384 err = devm_request_threaded_irq(dev, lt6911uxc->plugin_irq, NULL, in lt6911uxc_probe()
1391 err = v4l2_ctrl_handler_setup(sd->ctrl_handler); in lt6911uxc_probe()
1393 v4l2_err(sd, "v4l2 ctrl handler setup failed! err:%d\n", err); in lt6911uxc_probe()
1397 lt6911uxc_config_hpd(sd); in lt6911uxc_probe()
1398 v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, in lt6911uxc_probe()
1399 client->addr << 1, client->adapter->name); in lt6911uxc_probe()
1404 cancel_delayed_work(<6911uxc->delayed_work_enable_hotplug); in lt6911uxc_probe()
1405 cancel_delayed_work(<6911uxc->delayed_work_res_change); in lt6911uxc_probe()
1408 media_entity_cleanup(&sd->entity); in lt6911uxc_probe()
1411 v4l2_ctrl_handler_free(<6911uxc->hdl); in lt6911uxc_probe()
1412 mutex_destroy(<6911uxc->confctl_mutex); in lt6911uxc_probe()
1418 struct v4l2_subdev *sd = i2c_get_clientdata(client); in lt6911uxc_remove() local
1419 struct lt6911uxc *lt6911uxc = to_state(sd); in lt6911uxc_remove()
1421 cancel_delayed_work_sync(<6911uxc->delayed_work_enable_hotplug); in lt6911uxc_remove()
1422 cancel_delayed_work_sync(<6911uxc->delayed_work_res_change); in lt6911uxc_remove()
1423 v4l2_async_unregister_subdev(sd); in lt6911uxc_remove()
1424 v4l2_device_unregister_subdev(sd); in lt6911uxc_remove()
1426 media_entity_cleanup(&sd->entity); in lt6911uxc_remove()
1428 v4l2_ctrl_handler_free(<6911uxc->hdl); in lt6911uxc_remove()
1429 mutex_destroy(<6911uxc->confctl_mutex); in lt6911uxc_remove()
1430 clk_disable_unprepare(lt6911uxc->xvclk); in lt6911uxc_remove()
1465 MODULE_DESCRIPTION("Lontium LT6911UXC HDMI to MIPI CSI-2 bridge driver");
1466 MODULE_AUTHOR("Dingxian Wen <shawn.wen@rock-chips.com>");