RK3568 Sensor驱动开发移植(3)

RK3568 Camera 使用
RK3568 Sensor驱动开发移植(1)
RK3568 Sensor驱动开发移植(2)
RK3568 Sensor驱动开发移植(3)

实现标准 I2C 子设备驱动部分

根据 struct i2c_driver 说明实现以下成员:
struct driver.name
struct driver.pm
struct driver. of_match_table
probe 函数
remove 函数

Probe 实现细节描述

Probe 函数中,通常先对 dts 进行解析,获取CAMERA_MODULE 信息:

	ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
		&gc8034->module_index);
	ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
		&gc8034->module_facing);
	ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
		&gc8034->module_name);
	ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
		&gc8034->len_name);
	if (ret) {
		dev_err(dev, "could not get module information!\n");
		return -EINVAL;
	}

之后再获取 regulator、gpio、clk 等信息用以对 sensor 上下电。

	gc8034->xvclk = devm_clk_get(dev, "xvclk");
	if (IS_ERR(gc8034->xvclk)) {
		dev_err(dev, "Failed to get xvclk\n");
		return -EINVAL;
	}

	gc8034->power_gpio = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW);
	if (IS_ERR(gc8034->power_gpio))
		dev_warn(dev, "Failed to get power-gpios, maybe no use\n");
	gc8034->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
	if (IS_ERR(gc8034->reset_gpio))
		dev_warn(dev, "Failed to get reset-gpios\n");

	gc8034->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
	if (IS_ERR(gc8034->pwdn_gpio))
		dev_warn(dev, "Failed to get pwdn-gpios\n");

	ret = gc8034_configure_regulators(gc8034);
	if (ret) {
		dev_err(dev, "Failed to get power regulators\n");
		return ret;
	}

	ret = gc8034_parse_of(gc8034);
	if (ret != 0)
		return -EINVAL;

	gc8034->pinctrl = devm_pinctrl_get(dev);
	if (!IS_ERR(gc8034->pinctrl)) {
		gc8034->pins_default =
			pinctrl_lookup_state(gc8034->pinctrl,
					     OF_CAMERA_PINCTRL_STATE_DEFAULT);
		if (IS_ERR(gc8034->pins_default))
			dev_err(dev, "could not get default pinstate\n");

		gc8034->pins_sleep =
			pinctrl_lookup_state(gc8034->pinctrl,
					     OF_CAMERA_PINCTRL_STATE_SLEEP);
		if (IS_ERR(gc8034->pins_sleep))
			dev_err(dev, "could not get sleep pinstate\n");
	}
	...
	ret = __gc8034_power_on(gc8034);
	if (ret)
		goto err_free_handler;

	ret = gc8034_check_sensor_id(gc8034, client);
	if (ret)
		goto err_power_off;

其次注册media entity、v4l2 subdev、v4l2 controller 信息。注意到 v4l2 subdev 的注册是异步。如下几个关键的函数调用。

	sd = &gc8034->subdev;
	//注册为一个 v4l2 subdev,参数中提供回调函数
	v4l2_i2c_subdev_init(sd, client, &gc8034_subdev_ops);
	//初始化 v4l2 controls
	ret = gc8034_initialize_controls(gc8034);
	if (ret)
		goto err_destroy_mutex;
	....
	//声明 Sensor 需要异步注册。
	ret = v4l2_async_register_subdev_sensor_common(sd);
	if (ret) {
		dev_err(dev, "v4l2 async register subdev failed\n");
		goto err_clean_entity;
	}	

在.probe()阶段会去尝试读取 chip id, 如果能够正确读取到
chip id,一般就认为上电时序正确,Sensor 能够正常进行 i2c 通信。

static int gc8034_check_sensor_id(struct gc8034 *gc8034,
				struct i2c_client *client)
{
	struct device *dev = &gc8034->client->dev;
	u16 id = 0;
	u8 reg_H = 0;
	u8 reg_L = 0;
	int ret;

	ret = gc8034_read_reg(client, GC8034_REG_CHIP_ID_H, &reg_H);
	ret |= gc8034_read_reg(client, GC8034_REG_CHIP_ID_L, &reg_L);
	id = ((reg_H << 8) & 0xff00) | (reg_L & 0xff);
	if (id != CHIP_ID) {
		dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
		return -ENODEV;
	}
	dev_info(dev, "detected gc%04x sensor\n", id);
	return ret;
}

Sensor调试

完成Sensor驱动移植后,需要检查是否正常工作

i2c 能否通讯成功

Sensor 调试的第一个关键节点是 i2c 能否通讯成功,chip id 检查是否正确。如果是,说明上电时序没有
问题。

Sensor是否注册成功

使用 media-ctl 获取拓扑结构,查看 Sensor 是否已经注册成一个 entity。如果是,说明 Sensor 已经注册成功。

抓图是否有输出

通过抓图工具如 v4l2-ctl 、 gstreamer 、camera app等获取图像。

检查control是否生效

利用 v4l2-ctl 设置相关的参数,如 gain、exposure、blanking 并生成图片,查看 sensor 的 controls 是否有生效。例如增加 gain 或 exposure图片亮度是否增加;加大 blanking帧率是否下降。

你可能感兴趣的:(RK356X,驱动开发)