XS9922驱动

XS9922B 是一款四通道多合一模拟高清解码器,支持HDcctv高清协议CVBS标清协议。它最大支持1080p @ 30fps的视频分辨率,具有以下亮点:

此芯片将接收到的高清模拟复合视频信号经过模数转化、视频解码以及2D图像处理之后,转化为YCbCr,并以MIPI CSI接口输出。

此外,XS9922A/B 是另一款四通道模拟复合视频解码芯片方案,同样支持HDcctv高清协议和CVBS标清协议,最高支持4路2M@30fps。它也将接收到的高清模拟复合视频信号转化为YCbCr并以MIPI CSI接口输出

硬件原理图连接:

设备树配置

RK3568 MIPI CSI RX端配置

&csi2_dphy_hw {
	status = "okay";
};

&csi2_dphy0 {
	status = "okay";

	ports {
		#address-cells = <1>;
		#size-cells = <0>;
		port@0 {
			reg = <0>;
			#address-cells = <1>;
			#size-cells = <0>;

			mipi_in_ucam0: endpoint@1 {
				reg = <1>;
				remote-endpoint = <&ucam_out0>;
				data-lanes = <1 2 3 4>;
			}; 
		};
		port@1 {
			reg = <1>;
			#address-cells = <1>;
			#size-cells = <0>;

			csidphy_out: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&mipi_csi2_input>;
			};
		};
	};
};


&mipi_csi2 {

status = "okay";

        ports {
                #address-cells = <1>;
                #size-cells = <0>;
                port@0 {
                        reg = <0>;
                        #address-cells = <1>;
                        #size-cells = <0>;

                        mipi_csi2_input: endpoint@1 {
                                reg = <1>;
                                remote-endpoint = <&csidphy_out>;
                                data-lanes = <1 2 3 4>;
                        };
                };
                port@1 {
                        reg = <1>;
                        #address-cells = <1>;
                        #size-cells = <0>;

                        mipi_csi2_output: endpoint@0 {
                                reg = <0>;
                                remote-endpoint = <&cif_mipi_in>;
                        };
                };
        };

};


&rkcif_mipi_lvds {

	status = "okay";
        port {
                cif_mipi_in: endpoint {
                        remote-endpoint = <&mipi_csi2_output>;
                        data-lanes = <1 2 3 4>;
                        };
                };
};

xs9922设备树配置

		xs9922: xs9922@31 {
                
                compatible = "xs9922";
                status = "okay";
                reg = <0x31>;
		        clocks = <&cru CLK_CAM0_OUT>; 
                clock-names = "xvclk";
				pinctrl-names = "rockchip,camera_default";
                //使用CAM CLK0引脚
                pinctrl-0 = <&cam_clkout0>;

                power-domains = <&power RK3568_PD_VI>;
                //复位GPIO
                reset-gpios = <&gpio4 RK_PB7 GPIO_ACTIVE_HIGH>;
                //外接摄像头电源GPIO
				power2-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_HIGH>;
                rockchip,camera-module-index = <0>;
                rockchip,camera-module-facing = "front";
                rockchip,camera-module-name = "default";
                rockchip,camera-module-lens-name = "default";
                port {
                        ucam_out0: endpoint {
                                remote-endpoint = <&mipi_in_ucam0>;
                                data-lanes = <1 2 3 4>;
                        };
                };
        };

RK3568 SDK默认支持XS9922驱动:

drivers\media\i2c\xs9922\xs9922_reg_cfg.h

xs9922_init_cfg


typedef struct regval {
    unsigned short addr;  //芯片数据地址
    unsigned char val;    //i2c数据
    unsigned char nDelay; // 延时
}REG_VAL;

xs9922 i2c初始化配置
REG_VAL xs9922_init_cfg[] = {
    {0x4200, 0x3f, 0x00},
    {0x4210, 0x3f, 0x00},
    {0x4220, 0x3f, 0x00},
...
    //图像调优参数
    //{0x0106, 0x80}, // contrast 
    //{0x0107, 0x00}, // brightness
    //{0x0108, 0x80}, // staturation
    //{0x0109, 0x00}, // hue
...
    xs9922MIPI 输出速率,默认1.2G
    {0x511b, 0x36, 0x00},//0x78=1.5G,0x36=1.2G,0x34=1G,0x32=800M
...
    
};
//1080p 配置
REG_VAL xs9922_1080p_4lanes_25fps[] = {
...
};

//720p配置
REG_VAL xs9922_720p_4lanes_25fps[] = {	
...
};
//xs9922音频配置参数
REG_VAL xs9922_audio_codec[] = {
   ...
};

xs9922.c

static const struct xs9922_mode supported_modes[] = {
	{
         //supported_modes[0] 720p配置
		.bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8, // MEDIA_BUS_FMT_UYVY8_2X8,
		.width = 1280,
		.height = 720,
		.max_fps = {
			.numerator = 10000,
			.denominator = 150000,
		},
		.global_reg_list = xs9922_init_cfg,
		.reg_list = xs9922_720p_4lanes_25fps,
        ...
	},
	{
        //supported_modes[1] 1920p配置
		.bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8, // MEDIA_BUS_FMT_UYVY8_2X8,
		.width = 1920,
		.height = 1080,
		.max_fps = {
			.numerator = 10000,
			.denominator = 150000,
		},
		.global_reg_list = xs9922_init_cfg,
		.reg_list = xs9922_1080p_4lanes_25fps,
        ...
	}};

驱动配置函数
static int xs9922_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
    ...
    //走1080p,supported_modes[0]为720p
    xs9922->cur_mode = &supported_modes[1]; 
    ...
    //上电时许  RK3568 CLK时钟初始化
    ret = __xs9922_power_on(xs9922);
	if (ret) {
		dev_err(dev, "Failed to power on xs9922\n");
		goto err_free_handler;
	}
    //读芯片ID 比较
	ret = check_chip_id(client);
	if (ret) {
		dev_err(dev, "Failed to check senosr id\n");
		goto err_free_handler;
	}

    //热插拔事件初始化 一般没啥用
	xs9922->input_dev = devm_input_allocate_device(dev);
	if (xs9922->input_dev == NULL) {
		dev_err(dev, "failed to allocate xs9922 input device\n");
		return -ENOMEM;
	}
	xs9922->input_dev->name = "xs9922_input_event";
	set_bit(EV_MSC, xs9922->input_dev->evbit);
	set_bit(MSC_RAW, xs9922->input_dev->mscbit);

    ...
    //PM电源管理初始化
    pm_runtime_set_active(dev);
	pm_runtime_enable(dev);
	pm_runtime_idle(dev);

    //初始化I2C数据,启动热拔插线程
    read_config(xs9922);
}

static int read_config(void *data) //初始化I2C数据,启动热拔插线程

static int read_config(void *data)
{
    ...
    //I2C 写入初始化配置
	xs9922_write_array(xs9922->client, xs9922->cur_mode->global_reg_list);
    ....
     //打开驱动文件/etc/board.conf 获取走的分辨率配置,没有文件则走软件默认配置
	do {
      
		fp = filp_open(config_file, O_RDONLY, 0);
	    ...
	} while (tries > 0);

	if (IS_ERR(fp)) {
		printk(KERN_ERR "open " config_file " fail!!!\n");
		// return -1;
	} else {
       .....
	}
    //写入分辨率配置 数据
	switch_mode(xs9922);
    
	xs9922_write_array(xs9922->client, xs9922_lastInit);
	热拔插线程
    detect_thread_start(xs9922);
	printk("__xs9922_init out\n");

	return 0;
}

 xs9922_ioctl一般由RK热拔插capture.c调用

static long xs9922_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
    ...
    //RK热拔插驱动获取热拔插状态
    	case RKMODULE_GET_VICAP_RST_INFO:
		xs9922_get_vicap_rst_inf(
			xs9922, (struct rkmodule_vicap_reset_info *)arg);
		// printk("[chad] Get vicap reset info --->>> is_reset : %d\n", xs9922->is_reset);
		break;

	case RKMODULE_SET_VICAP_RST_INFO:
		xs9922_set_vicap_rst_inf(
			xs9922, *(struct rkmodule_vicap_reset_info *)arg);
		// printk("[chad] Set vicap reset info --->>> is_reset : %d\n", xs9922->is_reset);
		break;

    //由RK热拔插驱动调用,复位MIPI数据
	case RKMODULE_SET_QUICK_STREAM:
		stream = *((u32 *)arg);
		if (stream) {
			dev_info(
				&xs9922->client->dev,
				"[chad]======== quick stream on: do xs9922 mipi reset start =======\n");
			ret = xs9922_write_reg(xs9922->client, 0x5004,
					       XS9922_REG_VALUE_08BIT, 0x00);
            ...

			dev_info(
				&xs9922->client->dev,
				"[chad]======== quick stream on: do xs9922 mipi reset end =======\n");
		} else {
			xs9922_write_reg(xs9922->client, 0x0e08,
					 XS9922_REG_VALUE_08BIT, 0x00);
	        ....
			dev_info(
				&xs9922->client->dev,
				"[chad]======== quick stream off:xs9922 mipi Disabled =======\n");
			
			usleep_range(100 * 1000, 110 * 1000);
		}
		
		// mutex_unlock(&xs9922->mutex);
		break;
     ...
	return ret;
}

MIPI输出 关闭

static int __xs9922_start_stream(struct xs9922 *xs9922)
{

	struct i2c_client *client = xs9922->client;
#ifdef OPEN_XS9922_INIT
	xs9922_write_array(xs9922->client, xs9922->cur_mode->global_reg_list);
	switch_mode(xs9922);
	xs9922_write_array(xs9922->client, xs9922_lastInit);
#endif
	xs9922_write_reg(client, 0x5004, XS9922_REG_VALUE_08BIT, 0x00);
	xs9922_write_reg(client, 0x5005, XS9922_REG_VALUE_08BIT, 0x00);
	xs9922_write_reg(client, 0x5006, XS9922_REG_VALUE_08BIT, 0x00);
	xs9922_write_reg(client, 0x5007, XS9922_REG_VALUE_08BIT, 0x01);

	usleep_range(220 * 1000, 230 * 1000);
	xs9922_write_reg(client, 0x0e08, XS9922_REG_VALUE_08BIT, 0x01);
	xs9922_write_reg(client, 0x1e08, XS9922_REG_VALUE_08BIT, 0x01);
	xs9922_write_reg(client, 0x2e08, XS9922_REG_VALUE_08BIT, 0x01);
	xs9922_write_reg(client, 0x3e08, XS9922_REG_VALUE_08BIT, 0x01);

	dev_dbg(&client->dev, "%s OUT---<<<\n", __func__);
	return 0;
}

static int __xs9922_stop_stream(struct xs9922 *xs9922)
{
	struct i2c_client *client = xs9922->client;

	dev_dbg(&client->dev, "%s In---<<<\n", __func__);
	// usleep_range(50 * 1000, 60 * 1000);

	xs9922_write_reg(client, 0x0e08, XS9922_REG_VALUE_08BIT, 0x00);
	xs9922_write_reg(client, 0x1e08, XS9922_REG_VALUE_08BIT, 0x00);
	xs9922_write_reg(client, 0x2e08, XS9922_REG_VALUE_08BIT, 0x00);
	xs9922_write_reg(client, 0x3e08, XS9922_REG_VALUE_08BIT, 0x00);
	// usleep_range(150 * 1000, 160 * 1000);
	xs9922_write_reg(client, 0x5004, XS9922_REG_VALUE_08BIT, 0x00);
	xs9922_write_reg(client, 0x5005, XS9922_REG_VALUE_08BIT, 0x00);
	xs9922_write_reg(client, 0x5006, XS9922_REG_VALUE_08BIT, 0x00);
	xs9922_write_reg(client, 0x5007, XS9922_REG_VALUE_08BIT, 0x00);
#if __CLOSE_SENSOR__
	detect_thread_stop(xs9922);
#endif
	dev_dbg(&client->dev, "%s OUT---<<<\n", __func__);

	return 0;
}

BUG:

1.720P 也可用 xs9922_1080p_4lanes_25fps 配置,V4L2下发获取分辨率720P即可

2.图像有绿条,测试配置1.5G速率  {0x511b, 0x78, 0x00},//0x78=1.5G,0x36=1.2G,0x34=1G,0x32=800M 是否改善

3.I2C 数据无法写入,使用外部晶振确认是否起振,使用RK3568 CameraCLK引脚确认有无时钟

4.可以获取寄存器地址 1<<12 ,2<<12,3<<12,4<<12 ,获取接入摄像头的 分辨率

	for (i = 0; i < PAD_MAX; i++) {
		xs9922_read_reg(xs9922->client, 0x0001 | (i << 12), 1, &value);

		if (value == 64) {
			printk("i= %d,AutoPareVideoSize 720p\n",i);
		} else if (value == 68) {
			printk("i = %d 1080p\n",i);
        }
}

5.打开摄像头 预览画面出现图像断层,请尝试延长__xs9922_start_stream 里的延时 

  • 10
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hmbbPdx_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值