IMX335摄像头驱动注册分析
设备树
设备树中对imx335设备摄像头节点的描述信息:
&i2c1 { #&i2c1: 表示使用 I2C 总线 1,这通常在设备树中用于引用特定的 I2C 控制器
status = "okay"; #I2C 总线 1 已启用并且工作正常
clock-frequency = <400000>; #设置 I2C 总线的频率为 400 kHz,即工作在快速模式。该频率在sensor数据手册指定
imx335: imx335@1a { #imx335 的设备节点,@1a 表示 I2C 地址为 0x1a
compatible = "sony,imx335";
/* i2c client address: 0x34 >> 1 == 0x1a */ # 设备地址由来,右移1位,是最低位为I2C设备的读写位
reg = <0x1a>; # I2C 地址,即 0x1a
clocks = <&cru CLK_MIPICSI_OUT>; #指定了该设备所依赖的时钟源。&cru CLK_MIPICSI_OUT 是设备树中的时钟节点,表示为摄像头提供时钟信号
clock-names = "xvclk"; #指定了时钟名称,用于与其他设备或系统组件协调
power-domains = <&power RV1126_PD_VI>; #指定了设备所属的电源域(在此为 RV1126_PD_VI)
pinctrl-names = "rockchip,camera_default"; #指定了使用的引脚的默认状态
pinctrl-0 = <&mipicsi_clk0>; #MIPI时钟引脚
avdd-supply = <&vcc3v3_sys>; #电源要求 - 模拟电压3.3v
dovdd-supply = <&vcc_1v8>; #电源要求 - 接口电压1.8v
dvdd-supply = <&vcc_dvdd>; #电源要求 - 数字电压1.2v
/* reset is always pulled high in v10 */
reset-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_LOW>;#复位引脚。GPIO引脚是gpio1中的RK_PD5,低电平有效
rockchip,camera-module-index = <1>; #指定摄像头模块的索引号(此处为 1)
rockchip,camera-module-facing = "front"; #指定摄像头的朝向(此处为 "front",表示前置摄像头)
rockchip,camera-module-name = "YT10092"; #指定摄像头模块的名称(此处为 "YT10092")
rockchip,camera-module-lens-name = "IR0147-50IRC-8M-F20";#指定摄像头镜头的名称(此处为 "IR0147-50IRC-8M-F20")
//ir-cut = <&cam_ircut0>;
//flash-leds = <&flash_ir>;
lens-focus = <&hal_dc_motor>; #指定了用于控制镜头对焦的电机(此处为hal_dc_motor)。这通常与硬件对焦组件(如DC 电机)相关联
port { #定义 MIPI 数据端口的节点
ucam_out0: endpoint { 定义了一个名为 ucam_out0 的端点
remote-endpoint = <&mipi_in_ucam0>;#指定了这个端点与另一个节点(mipi_in_ucam0)相连接,这是另一个设备或控制器,负责接收摄像头数据
data-lanes = <1 2 3 4>; #定义了 MIPI 数据通道的编号,通常用于设置数据传输的通道
};
};
};
imx335摄像头驱动分析
驱动文件路径:linux-4.19.111/drivers/media/i2c
由设备树可知,imx335摄像头设备其实对内核来说,是一个i2c设备,故驱动程序是以一个i2c设备形式进行驱动的注册
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id imx335_of_match[] = {
{ .compatible = "sony,imx335" },
{},
};
MODULE_DEVICE_TABLE(of, imx335_of_match);
#endif
static const struct i2c_device_id imx335_match_id[] = {
{ "sony,imx335", 0 },
{ },
};
static struct i2c_driver imx335_i2c_driver = {
.driver = {
.name = IMX335_NAME,
.pm = &imx335_pm_ops,
.of_match_table = of_match_ptr(imx335_of_match),
},
.probe = &imx335_probe,
.remove = &imx335_remove,
.id_table = imx335_match_id,
};
static int __init sensor_mod_init(void)
{
return i2c_add_driver(&imx335_i2c_driver);
}
static void __exit sensor_mod_exit(void)
{
i2c_del_driver(&imx335_i2c_driver);
}
device_initcall_sync(sensor_mod_init);
module_exit(sensor_mod_exit);
MODULE_DESCRIPTION("Sony imx335 sensor driver");
MODULE_LICENSE("GPL v2");
在驱动中,中来描述一个imx335设备
struct imx335 {
struct i2c_client *client; // I2C 客户端
struct clk *xvclk; // 外部时钟(XCLK)
struct gpio_desc *reset_gpio; // 重置 GPIO 引脚
struct regulator_bulk_data supplies[IMX335_NUM_SUPPLIES]; // 电源管理,supplies 数组用来管理多个电源输入
struct pinctrl *pinctrl; // 引脚控制
struct pinctrl_state *pins_default; // 默认引脚配置
struct pinctrl_state *pins_sleep; // 休眠状态下的引脚配置
struct v4l2_subdev subdev; // V4L2 子设备,用于将 IMX335 摄像头与 V4L2 子设备框架集成。subdev 用于在 V4L2 系统中注册和管理设备
struct media_pad pad; // 媒体接口中的连接点,用于描述视频输入或输出的连接点,通常与摄像头的输入或输出数据流相关
struct v4l2_ctrl_handler ctrl_handler; // 控制器处理,用于管理与摄像头相关的控制参数(如曝光、增益等)
struct v4l2_ctrl *exposure; // 曝光控制器
struct v4l2_ctrl *anal_a_gain; // 模拟增益控制器,用于调节模拟信号的增益,即提高或降低图像信号的强度
struct v4l2_ctrl *digi_gain; // 数字增益控制器,用于调整数字信号的增益。
struct v4l2_ctrl *hblank; // 图像传感器水平空白控制器
struct v4l2_ctrl *vblank; // 图像传感器垂直空白控制器
struct v4l2_ctrl *pixel_rate; // 像素率控制器。用于设置传感器的像素传输速率
struct v4l2_ctrl *link_freq; // 链路频率控制器,用于控制摄像头与主机之间的数据传输频率
struct mutex mutex; // 互斥锁,保证线程安全
bool streaming; // 是否正在传输视频流
bool power_on; // 电源状态
const struct imx335_mode *cur_mode; // 当前模式配置
u32 module_index; // 摄像头模块索引
u32 cfg_num; // 配置编号
const char *module_facing; // 摄像头模块朝向
const char *module_name; // 摄像头模块名称
const char *len_name; // 镜头名称,标识连接到摄像头模块的镜头名称
u32 cur_vts; // 当前垂直同步时间,通常与图像传感器的垂直扫描时间有关
bool has_init_exp; // 标志位,表示是否已初始化曝光值。
struct preisp_hdrae_exp_s init_hdrae_exp; // 曝光配置。用于存储在初始化时的自动曝光参数
};
设备与驱动匹配成功后,执行probe函数:
static int imx335_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct imx335 *imx335;
struct v4l2_subdev *sd;
char facing[2];
int ret;
u32 i, hdr_mode = 0;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
//动态申请内容,保存imx335结构体参数
imx335 = devm_kzalloc(dev, sizeof(*imx335), GFP_KERNEL);
if (!imx335)
return -ENOMEM;
//设备树获取模块的索引号、摄像头的方向、摄像头模块的名称、摄像头镜头的名称
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&imx335->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&imx335->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&imx335->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&imx335->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
ret = of_property_read_u32(node, OF_CAMERA_HDR_MODE, &hdr_mode); //从设备树中获取hdr模式
if (ret) {
hdr_mode = NO_HDR;
dev_warn(dev, " Get hdr mode failed! no hdr default\n");
}
imx335->client = client;
imx335->cfg_num = ARRAY_SIZE(supported_modes); //获取支持模式的成员数
for (i = 0; i < imx335->cfg_num; i++) {
if (hdr_mode == supported_modes[i].hdr_mode) { //匹配设备树中的模式,并设置hdr下的参数
imx335->cur_mode = &supported_modes[i];
break;
}
}
imx335->xvclk = devm_clk_get(dev, "xvclk"); //从设备树中获取imx335的时钟值
if (IS_ERR(imx335->xvclk)) {
dev_err(dev, "Failed to get xvclk\n");
return -EINVAL;
}
imx335->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); //设备树中获取复位引脚值
if (IS_ERR(imx335->reset_gpio))
dev_warn(dev, "Failed to get reset-gpios\n");
imx335->pinctrl = devm_pinctrl_get(dev); //获取设备树中的引脚状态
if (!IS_ERR(imx335->pinctrl)) {
imx335->pins_default =
pinctrl_lookup_state(imx335->pinctrl,
OF_CAMERA_PINCTRL_STATE_DEFAULT); //绑定pinctrl默认状态
if (IS_ERR(imx335->pins_default))
dev_info(dev, "could not get default pinstate\n");
imx335->pins_sleep =
pinctrl_lookup_state(imx335->pinctrl,
OF_CAMERA_PINCTRL_STATE_SLEEP); //绑定pinctrl睡眠状态
if (IS_ERR(imx335->pins_sleep))
dev_info(dev, "could not get sleep pinstate\n");
} else {
dev_info(dev, "no pinctrl\n");
}
ret = imx335_configure_regulators(imx335); //配置电源管理
if (ret) {
dev_err(dev, "Failed to get power regulators\n");
return ret;
}
mutex_init(&imx335->mutex); //初始化互斥锁
sd = &imx335->subdev; //imx335子设备,这里指的sensor
v4l2_i2c_subdev_init(sd, client, &imx335_subdev_ops); //初始化v4l2子设备
ret = imx335_initialize_controls(imx335); //初始化imx335->subdev下的control 处理
if (ret)
goto err_destroy_mutex;
ret = __imx335_power_on(imx335); //设置上电前的准备,配置引脚状态、时钟频率
if (ret)
goto err_free_handler;
ret = imx335_check_sensor_id(imx335, client); //检查sersor id
if (ret)
goto err_power_off;
sd->internal_ops = &imx335_internal_ops; //subdev 内部操作函数
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
#if defined(CONFIG_MEDIA_CONTROLLER)
imx335->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &imx335->pad); //建立 subdev->entity和imx335->pad联系
if (ret < 0)
goto err_power_off;
#endif
memset(facing, 0, sizeof(facing));
if (strcmp(imx335->module_facing, "back") == 0) //前置还是后置摄像头
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
imx335->module_index, facing,
IMX335_NAME, dev_name(sd->dev)); //subdev 名字
ret = v4l2_async_register_subdev_sensor_common(sd); //注册v4l2 subdev
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
goto err_clean_entity;
}
pm_runtime_set_active(dev); //设置电源管理的状态
pm_runtime_enable(dev);
pm_runtime_idle(dev);
return 0;
err_clean_entity:
#if defined(CONFIG_MEDIA_CONTROLLER)
media_entity_cleanup(&sd->entity);
#endif
err_power_off:
__imx335_power_off(imx335);
err_free_handler:
v4l2_ctrl_handler_free(&imx335->ctrl_handler);
err_destroy_mutex:
mutex_destroy(&imx335->mutex);
return ret;
}