RK3568 Camera 使用
RK3568 Sensor驱动开发移植(1)
RK3568 Sensor驱动开发移植(2)
RK3568 Sensor驱动开发移植(3)
根据 struct i2c_driver 说明实现以下成员:
struct driver.name
struct driver.pm
struct driver. of_match_table
probe 函数
remove 函数
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, ®_H);
ret |= gc8034_read_reg(client, GC8034_REG_CHIP_ID_L, ®_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 能否通讯成功,chip id 检查是否正确。如果是,说明上电时序没有
问题。
使用 media-ctl 获取拓扑结构,查看 Sensor 是否已经注册成一个 entity。如果是,说明 Sensor 已经注册成功。
通过抓图工具如 v4l2-ctl 、 gstreamer 、camera app等获取图像。
利用 v4l2-ctl 设置相关的参数,如 gain、exposure、blanking 并生成图片,查看 sensor 的 controls 是否有生效。例如增加 gain 或 exposure图片亮度是否增加;加大 blanking帧率是否下降。