4.2 ADV7441A I2C寄存器设置
42 03 0C ; Disable TOD
42 05 02 ; Prim_Mode =010b for automatic graphics mode
42 06 07 ; VID_STD=00111b for automatic graphics mode
42 1D 40 ; Disable TRI_LLC
42 3C A8 ; SOG Sync level for atenuated sync, PLL Qpump to default
42 37 00 ; PCLK Polarity
42 47 0A ; Enable Automatic PLL_Qpump and VCO Range
42 68 F2 ; Auto CSC, RGB Out
42 6B F2 ; Setup CPOP_SEL & DE Enable
42 7B 1D ; Turn off EAV and SAV codes
42 7C 00 ; HS/VS Positive
42 7E 03 ; HS Adjust
42 7F 88 ; VS Adjust
42 F4 3F ; Max Drive Strength
42 87 E8 ; Enable Manual PLL Divider Ratio 0x870 = 2160
42 88 70 ; Set PLL Divider Ratio
42 8C 07 ; HS adjust
42 8D 5A ; HS adjust
42 8E 87 ; VBI Adjust
42 8F 01 ; Set Free Run Line Length 0x17E = 382
42 90 7E ; Set Free Run Line Length
42 AB 4E ; Set Line Count Max 0x4E2 = 1250
42 AC 20 ; Set Line Count Max
42 B5 08 ; Deglitch Filter adjust
42 91 10 ; Progressive
4.3 引脚定义
static iomux_v3_cfg_t mx6q_sabresd_csi1_sensor_pads[] = { /* IPU2 tvin */ MX6Q_PAD_EIM_DA0__IPU2_CSI1_D_9, MX6Q_PAD_EIM_DA1__IPU2_CSI1_D_8, MX6Q_PAD_EIM_DA2__IPU2_CSI1_D_7, MX6Q_PAD_EIM_DA3__IPU2_CSI1_D_6, MX6Q_PAD_EIM_DA4__IPU2_CSI1_D_5, MX6Q_PAD_EIM_DA5__IPU2_CSI1_D_4, MX6Q_PAD_EIM_DA6__IPU2_CSI1_D_3, MX6Q_PAD_EIM_DA7__IPU2_CSI1_D_2, MX6Q_PAD_EIM_EB2__IPU2_CSI1_D_19, MX6Q_PAD_EIM_D16__IPU2_CSI1_D_18, MX6Q_PAD_EIM_D18__IPU2_CSI1_D_17, MX6Q_PAD_EIM_D19__IPU2_CSI1_D_16, MX6Q_PAD_EIM_D20__IPU2_CSI1_D_15, MX6Q_PAD_EIM_D26__IPU2_CSI1_D_14, MX6Q_PAD_EIM_D27__IPU2_CSI1_D_13, MX6Q_PAD_EIM_D28__IPU2_CSI1_D_12, MX6Q_PAD_EIM_D17__IPU2_CSI1_PIXCLK, MX6Q_PAD_EIM_EB3__IPU2_CSI1_HSYNC, MX6Q_PAD_EIM_D29__IPU2_CSI1_VSYNC, MX6Q_PAD_EIM_D31__GPIO_3_31, /* tvin reset , low */
};
4.4 adv7441a复位和CPU相应寄存器初始化
#define SABRESD_TVIN_REST IMX_GPIO_NR(3, 31) static void mx6q_csi1_io_init(void) { mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_csi1_sensor_pads, ARRAY_SIZE(mx6q_sabresd_csi1_sensor_pads)); /* tvin reset */ gpio_request(SABRESD_TVIN_REST, "tvin-rest"); gpio_direction_output(SABRESD_TVIN_REST, 1); gpio_direction_output(SABRESD_TVIN_REST, 0); msleep(10); gpio_direction_output(SABRESD_TVIN_REST, 1); /* For MX6Q: * GPR1 bit19 and bit20 meaning: * Bit19: 0 - Enable mipi to IPU1 CSI0 * virtual channel is fixed to 0 * 1 - Enable parallel interface to IPU1 CSI0 * Bit20: 0 - Enable mipi to IPU2 CSI1 * virtual channel is fixed to 3 * 1 - Enable parallel interface to IPU2 CSI1 * IPU1 CSI1 directly connect to mipi csi2, * virtual channel is fixed to 1 * IPU2 CSI0 directly connect to mipi csi2, * virtual channel is fixed to 2 * For MX6DL: * GPR13 bit 0-2 IPU_CSI0_MUX * 000 MIPI_CSI0 * 100 IPU CSI0 if (cpu_is_mx6q()) mxc_iomux_set_gpr_register(1, 20, 1, 1); // CPU工作在IPU2 CSI1
else if (cpu_is_mx6dl()) mxc_iomux_set_gpr_register(13, 0, 3, 4); }
4.5 V4L主设备驱动
static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm)
if (ifparm.if_type == V4L2_IF_TYPE_BT656) { if (ifparm.u.bt656.clock_curr == 0) { csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; } else { if (cam-> device_type != 1) csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; else csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; } if (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT) { csi_param.data_width = IPU_CSI_DATA_WIDTH_8; } else if (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT) { csi_param.data_width = IPU_CSI_DATA_WIDTH_10; } else { csi_param.data_width = IPU_CSI_DATA_WIDTH_8; } csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv; csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv; csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv; csi_param.ext_vsync = ifparm.u.bt656.bt_sync_correct; } if (ifparm.if_type == V4L2_IF_TYPE_BT1120) { { if (ifparm.u.bt1120.clock_curr == 0) { csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR; }
else { if (cam-> device_type != 1) csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; else csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR; } } if (ifparm.u.bt1120.mode == V4L2_IF_TYPE_BT1120_MODE_BT_8BIT) { csi_param.data_width = IPU_CSI_DATA_WIDTH_8; } else if (ifparm.u.bt1120.mode == V4L2_IF_TYPE_BT1120_MODE_BT_16BIT) { csi_param.data_width = IPU_CSI_DATA_WIDTH_16; } else { csi_param.data_width = IPU_CSI_DATA_WIDTH_8; } csi_param.Vsync_pol = ifparm.u.bt1120.nobt_vs_inv; csi_param.Hsync_pol = ifparm.u.bt1120.nobt_hs_inv; csi_param.pixclk_pol = ifparm.u.bt1120.latch_clk_inv; csi_param.ext_vsync = ifparm.u.bt1120.bt_sync_correct; }
4.6 adv7441a_probe函数
static int adv7441a_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; tvin_plat = client-> dev.platform_data; if (tvin_plat-> io_init) tvin_plat-> io_init(); if (tvin_plat-> reset) tvin_plat-> reset(); if (tvin_plat-> pwdn) tvin_plat-> pwdn(0); msleep(1); /* Set initial values for the sensor struct. */ memset(&adv7441a_data, 0, sizeof(adv7441a_data)); adv7441a_data.sen.i2c_client = client; adv7441a_data.sen.streamcap.timeperframe.denominator = 30; adv7441a_data.sen.streamcap.timeperframe.numerator = 1; adv7441a_data.std_id = V4L2_STD_ALL; video_idx = ADV7441A_NOT_LOCKED; adv7441a_data.sen.streamcap.capability = V4L2_MODE_HIGHQUALITY | V4L2_CAP_TIMEPERFRAME; adv7441a_data.sen.pix.width = video_fmts[video_idx].raw_width; adv7441a_data.sen.pix.height = video_fmts[video_idx].raw_height; adv7441a_data.sen.pix.pixelformat = V4L2_PIX_FMT_YUYV; //像素格式
adv7441a_data.sen.pix.priv = 1; /* 1 is used to indicate TV in */ adv7441a_data.sen.on = true; adv7441a_data.sen.csi = 1; }
4.7 V4L从设备给V4L主设备的获取时序模式参数的函数
static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) { if (s == NULL) { pr_err(" ERROR!! no slave device set!\n"); return -1; } /* Initialize structure to 0s then set any non-0 values. */ memset(p, 0, sizeof(*p)); p-> if_type = V4L2_IF_TYPE_BT1120;/* This is the only possibility. */ p-> u.bt656.mode = V4L2_IF_TYPE_BT1120_MODE_BT_8BIT; p-> u.bt656.clock_curr = 1; return 0; }
4.8 V4L从设备给V4L主设备的获取分辨率的函数
static int ioctl_enum_framesizes(struct v4l2_int_device *s, struct v4l2_frmsizeenum *fsize) { if (fsize-> index > = 1) return -EINVAL; fsize-> discrete.width = (hdmi_read(0x07) & 0x0f) * 256 + hdmi_read(0x08); fsize-> discrete.height = (hdmi_read(0x09) & 0x0f) * 256 + hdmi_read(0x0a); adv7441a_autoset(fsize-> discrete.width, fsize-> discrete.height); fsize-> discrete.height -= (fsize-> discrete.height) % 8; return 0; } 更多详细技术信息请参看成都嵌智捷科技网站或咨询公司技术支持,