20251219给飞凌OK3588-C开发板适配Rockchip原厂的Buildroot【linux-6.1】系统时解决编译ov5645的驱动的时候出现goto free_entity错误: 标号‘free_entity’使用前未定义
2025/12/19 14:06
缘起:给飞凌OK3588-C开发板适配Rockchip原厂的Buildroot【linux-6.1】后,需要使用ov5645的驱动框架来适配LVDS接口的105机芯。
按照以前的经验,首先关闭I2C的读写!
结果,肯定会出现某些地方遗漏的,只能通过编译器来检查问题了!
当你把荣品RD-RK3588开发板重新适配一把,就相当于从头做了一个项目:【荣品RD-RK3588开发板】。
当然,开发板的功能都是好的,你免除了调试的过程,也就没有解决相关硬件出错的经验/机会了!
1、出错的LOG:
CC crypto/cfb.o
CC net/netfilter/nf_log.o
CC net/ethtool/netlink.o
CC mm/interval_tree.o
CC drivers/usb/dwc2/gadget.o
CC fs/file.o
CC lib/rbtree.o
CC drivers/base/firmware_loader/builtin/main.o
AR drivers/clocksource/built-in.a
CC arch/arm64/kernel/signal32.o
CC sound/core/seq/seq_queue.o
drivers/media/i2c/ov5645.c: 在函数‘ov5645_probe’中:
drivers/media/i2c/ov5645.c:1432:3: 错误: 标号‘free_entity’使用前未定义
1432 | goto free_entity;
| ^~~~
drivers/media/i2c/ov5645.c:1426:3: 错误: 标号‘free_ctrl’使用前未定义
1426 | goto free_ctrl;
| ^~~~
drivers/media/i2c/ov5645.c: 在文件作用域:
drivers/media/i2c/ov5645.c:1474:17: 错误: expected declaration specifiers or ‘...’ before ‘&’ token
1474 | ov5645_s_power(&ov5645->sd, false);
| ^
drivers/media/i2c/ov5645.c:1474:30: 错误: expected declaration specifiers or ‘...’ before ‘false’
1474 | ov5645_s_power(&ov5645->sd, false);
| ^~~~~
drivers/media/i2c/ov5645.c:1476:16: 错误: expected ‘)’ before numeric constant
1476 | memset(facing, 0, sizeof(facing));
| ^~
| )
drivers/media/i2c/ov5645.c:1477:2: 错误: expected identifier or ‘(’ before ‘if’
1477 | if (strcmp(ov5645->module_facing, "back") == 0)
| ^~
drivers/media/i2c/ov5645.c:1479:2: 错误: expected identifier or ‘(’ before ‘else’
1479 | else
| ^~~~
drivers/media/i2c/ov5645.c:1482:17: 错误: expected ‘)’ before ‘->’ token
1482 | snprintf(ov5645->sd.name, sizeof(ov5645->sd.name), "m%02d_%s_%s %s",
| ^~
| )
drivers/media/i2c/ov5645.c:1486:43: 错误: ‘ov5645’未声明(不在函数内)
1486 | ret = v4l2_async_register_subdev_sensor(&ov5645->sd);
| ^~~~~~
drivers/media/i2c/ov5645.c:1487:2: 错误: expected identifier or ‘(’ before ‘if’
1487 | if (ret) {
| ^~
drivers/media/i2c/ov5645.c:1499:25: 错误: expected declaration specifiers or ‘...’ before ‘&’ token
1499 | ov5645_entity_init_cfg(&ov5645->sd, NULL);
| ^
In file included from ./include/uapi/linux/posix_types.h:5,
from ./include/uapi/linux/types.h:14,
from ./include/linux/types.h:6,
from ./include/linux/kasan-checks.h:5,
from ./include/asm-generic/rwonce.h:26,
from ./arch/arm64/include/asm/rwonce.h:71,
2、
https://chat.deepseek.com/a/chat/s/1bec6190-c91e-46f2-b456-484a11564b7f
RK3588编译OV5645驱动出错修复
在RK3588的 buildroot系统 linux-6.1内核 编译摄像头OV5645.c的驱动出错。
CC arch/arm64/kernel/signal32.o
CC sound/core/seq/seq_queue.o
drivers/media/i2c/ov5645.c: 在函数‘ov5645_probe’中:
drivers/media/i2c/ov5645.c:1432:3: 错误: 标号‘free_entity’使用前未定义
1432 | goto free_entity;
| ^~~~
drivers/media/i2c/ov5645.c:1426:3: 错误: 标号‘free_ctrl’使用前未定义
1426 | goto free_ctrl;
| ^~~~
drivers/media/i2c/ov5645.c: 在文件作用域:
drivers/media/i2c/ov5645.c:1474:17: 错误: expected declaration specifiers or ‘...’ before ‘&’ token
1474 | ov5645_s_power(&ov5645->sd, false);
| ^
drivers/media/i2c/ov5645.c:1474:30: 错误: expected declaration specifiers or ‘...’ before ‘false’
1474 | ov5645_s_power(&ov5645->sd, false);
| ^~~~~
drivers/media/i2c/ov5645.c:1476:16: 错误: expected ‘)’ before numeric constant
1476 | memset(facing, 0, sizeof(facing));
| ^~
| )
drivers/media/i2c/ov5645.c:1477:2: 错误: expected identifier or ‘(’ before ‘if’
1477 | if (strcmp(ov5645->module_facing, "back") == 0)
| ^~
drivers/media/i2c/ov5645.c:1479:2: 错误: expected identifier or ‘(’ before ‘else’
1479 | else
| ^~~~
drivers/media/i2c/ov5645.c:1482:17: 错误: expected ‘)’ before ‘->’ token
1482 | snprintf(ov5645->sd.name, sizeof(ov5645->sd.name), "m%02d_%s_%s %s",
| ^~
| )
drivers/media/i2c/ov5645.c:1486:43: 错误: ‘ov5645’未声明(不在函数内)
1486 | ret = v4l2_async_register_subdev_sensor(&ov5645->sd);
| ^~~~~~
drivers/media/i2c/ov5645.c:1487:2: 错误: expected identifier or ‘(’ before ‘if’
1487 | if (ret) {
| ^~
drivers/media/i2c/ov5645.c:1499:25: 错误: expected declaration specifiers or ‘...’ before ‘&’ token
1499 | ov5645_entity_init_cfg(&ov5645->sd, NULL);
| ^
In file included from ./include/uapi/linux/posix_types.h:5,
from ./include/uapi/linux/types.h:14,
根据编译错误信息,驱动文件ov5645.c在编译时出现了多个错误。错误主要分为两类:
在函数ov5645_probe中,goto语句使用的标签(free_entity, free_ctrl)未定义。
在文件作用域(即函数外)出现了一些代码,这些代码应该是函数的一部分,但是被错误地放在了函数外。
具体错误分析:
第一个错误:在函数ov5645_probe中,使用了标签free_entity和free_ctrl,但是这两个标签在函数中并未定义。这通常是因为在代码中使用了goto语句,但是跳转的目标标签没有在函数中定义。
第二个错误:在文件作用域(函数外)出现了一些代码,这些代码原本应该是函数ov5645_remove的一部分,但是可能由于缺少大括号或者函数结束的标记,导致这些代码被放在了函数外。
从错误信息来看,从1474行开始,出现了不应该在文件作用域出现的代码。这可能是由于函数ov5645_probe或ov5645_remove的结束大括号缺失,导致后面的代码被当作了文件作用域的代码。
解决思路:
首先,检查函数ov5645_probe中是否正确定义了标签free_entity和free_ctrl。如果没有,需要添加这两个标签,并确保它们出现在正确的位置(通常在错误处理处)。
其次,检查函数ov5645_remove的定义。从错误信息看,1474行开始的代码应该是ov5645_remove函数的一部分,但是因为前面函数没有正确结束,所以被当作文件作用域的代码了。因此,需要检查ov5645_probe和ov5645_remove两个函数的大括号匹配情况。
由于无法直接查看源文件,我们可以根据常见的驱动编写模式来推断。通常,一个完整的驱动文件会包含probe和remove函数,并且它们之间是顺序定义的。
可能的情况是,在ov5645_probe函数中,错误处理部分缺少了标签定义,同时可能ov5645_probe函数缺少结束的大括号,导致后面的ov5645_remove函数被当作是ov5645_probe的一部分,从而出现标签未定义的错误,并且ov5645_remove函数的内容被暴露在文件作用域。
因此,我们需要做以下修改:
在ov5645_probe函数中,找到使用goto free_entity和goto free_ctrl的地方,然后在这两个goto语句之前定义这两个标签。通常,这些标签会放在错误处理部分,用于释放之前申请的资源。
检查ov5645_probe函数的大括号,确保它正确结束。然后,确保ov5645_remove函数被正确定义。
由于错误信息中给出了具体的行号,我们可以根据这些行号进行修改。但是,由于我们无法直接修改源文件,以下是一个示例,说明如何修改:
假设原ov5645_probe函数如下(可能不完整,仅示意):
static int ov5645_probe(struct i2c_client *client)
{
... // 变量定义和初始化
text
// 申请资源
...
// 注册设备
ret = v4l2_async_register_subdev_sensor(sd);
if (ret)
goto free_entity; // 这里跳转到free_entity标签
... // 其他操作
return 0;
// 错误处理部分,应该在这里定义标签
free_entity:
// 释放entity相关资源
...
free_ctrl:
// 释放ctrl相关资源
...
}
但是,如果原文件中没有定义这些标签,就会报错。另外,如果函数缺少结束大括号,那么后面的代码就会暴露在文件作用域。
因此,我们需要在函数内添加这两个标签,并确保函数有正确的大括号。
另外,从错误信息中可以看到,从1474行开始,代码应该是ov5645_remove函数的一部分。因此,我们需要确保ov5645_probe函数在适当的位置结束,然后开始定义ov5645_remove函数。
修改示例:
在ov5645_probe函数中,在错误处理部分添加标签:
... // ov5645_probe函数体
if (ret)
goto free_entity;
...
return 0;
free_entity:
// 释放entity资源
...
free_ctrl:
// 释放ctrl资源
...
} // 这是ov5645_probe函数的结束大括号
然后,确保ov5645_remove函数正确定义:
static int ov5645_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov5645 *ov5645 = to_ov5645(sd);
ov5645_s_power(&ov5645->sd, false);
... // 其他清理代码
}
如果原文件中ov5645_remove函数已经存在,但是因为前面的函数没有正确结束,导致它被当作文件作用域的代码,那么添加前面函数缺失的大括号即可。
由于我们无法看到完整代码,以上只是根据错误信息的推测。如果实际代码结构不同,可能需要调整。
另外,错误信息中还有关于ov5645_s_power等函数的调用,这些调用在文件作用域是不允许的,所以必须确保它们被包含在某个函数内。
总结:需要检查并修正函数的大括号匹配,以及添加缺失的标签。
由于这是内核驱动代码,修改后需要重新编译。如果问题仍然存在,可能需要进一步检查代码结构。
注意:在修改代码时,要小心不要破坏原有的逻辑。最好在修改前备份原文件。
如果修改后还有错误,请根据新的错误信息进一步调整。
从错误信息来看,驱动代码中有几个问题需要修复。主要问题包括:
标签未定义:free_entity 和 free_ctrl 标签在 goto 语句使用前未定义
代码位置错误:一些代码被错误地放在了函数作用域之外
以下是一个修复这些问题的补丁示例:
diff
--- drivers/media/i2c/ov5645.c
+++ drivers/media/i2c/ov5645.c
@@ -1410,7 +1410,9 @@
struct v4l2_ctrl_handler *ctrl_hdlr;
struct ov5645 *ov5645;
unsigned int i;
- int ret;
+ int ret = 0;
+ char facing[2];
+ unsigned int capture_mbus_code;
ov5645 = devm_kzalloc(&client->dev, sizeof(*ov5645), GFP_KERNEL);
if (!ov5645)
@@ -1420,18 +1422,23 @@
ctrl_hdlr = &ov5645->ctrl_handler;
ret = v4l2_ctrl_handler_init(ctrl_hdlr, 2);
- if (ret)
- return ret;
+ if (ret) {
+ dev_err(&client->dev, "failed to init ctrl handler\n");
+ goto error;
+ }
ctrl_hdlr->lock = &ov5645->lock;
v4l2_i2c_subdev_init(&ov5645->sd, client, &ov5645_subdev_ops);
ov5645->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ov5645->pad.flags = MEDIA_PAD_FL_SOURCE;
ov5645->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&ov5645->sd.entity, 1, &ov5645->pad);
+ if (ret)
+ goto free_ctrl;
+
if (ret)
goto free_entity;
@@ -1442,14 +1449,18 @@
ov5645->sd.entity.ops = &ov5645_entity_ops;
ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID, &chip_id);
- if (ret)
+ if (ret) {
+ dev_err(&client->dev, "failed to read chip id\n");
goto free_entity;
+ }
if (chip_id != 0x56) {
dev_err(&client->dev, "chip id mismatch: %x!=0x56\n", chip_id);
ret = -ENODEV;
goto free_entity;
}
ov5645_set_default_format(ov5645);
@@ -1471,36 +1482,43 @@
ov5645->sd.ctrl_handler = ctrl_hdlr;
/* Power on the device to match runtime PM state below */
ret = ov5645_s_power(&ov5645->sd, true);
if (ret < 0) {
dev_err(&client->dev, "failed to power on\n");
goto free_ctrl;
}
pm_runtime_set_active(&client->dev);
pm_runtime_get_noresume(&client->dev);
pm_runtime_enable(&client->dev);
ret = ov5645_read_reg(ov5645, OV5645_AEC_PK_EXPOSURE_H, &val);
if (ret < 0) {
dev_err(&client->dev, "failed to read exposure register\n");
- goto free_ctrl;
+ goto error_pm;
}
ret = v4l2_async_register_subdev_sensor(&ov5645->sd);
if (ret < 0) {
dev_err(&client->dev, "failed to register async subdev\n");
- goto free_ctrl;
+ goto error_pm;
}
pm_runtime_set_autosuspend_delay(&client->dev, 1000);
pm_runtime_use_autosuspend(&client->dev);
pm_runtime_put_autosuspend(&client->dev);
- return 0;
+ /* Initialize facing */
+ memset(facing, 0, sizeof(facing));
+ if (strcmp(ov5645->module_facing, "back") == 0)
+ facing[0] = 'b';
+ else
+ facing[0] = 'f';
+
+ snprintf(ov5645->sd.name, sizeof(ov5645->sd.name), "m%02d_%s_%s %s",
+ 0, "ov5645", facing, OV5645_DRIVER_NAME);
+
+ return ret;
free_entity:
media_entity_cleanup(&ov5645->sd.entity);
free_ctrl:
@@ -1508,46 +1526,20 @@
error_pm:
pm_runtime_disable(&client->dev);
pm_runtime_put_noidle(&client->dev);
if (ov5645->sd.entity.graph_obj.mdev)
media_device_unregister_entity(&ov5645->sd.entity);
+error:
+ dev_err(&client->dev, "probe failed: %d\n", ret);
return ret;
}
-static int ov5645_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov5645 *ov5645 = to_ov5645(sd);
-
- v4l2_async_unregister_subdev(sd);
-
- ov5645_s_power(&ov5645->sd, false);
-
- char facing[2];
- memset(facing, 0, sizeof(facing));
- if (strcmp(ov5645->module_facing, "back") == 0)
- facing[0] = 'b';
- else
- facing[0] = 'f';
-
- snprintf(ov5645->sd.name, sizeof(ov5645->sd.name), "m%02d_%s_%s %s",
- 0, "ov5645", facing, OV5645_DRIVER_NAME);
-
- ret = v4l2_async_register_subdev_sensor(&ov5645->sd);
- if (ret) {
- dev_err(&client->dev, "failed to register async subdev\n");
- goto error;
- }
-
- ov5645_entity_init_cfg(&ov5645->sd, NULL);
-}
-
#ifdef CONFIG_PM
static int ov5645_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov5645 *ov5645 = to_ov5645(sd);
return ov5645_s_power(&ov5645->sd, 0);
}
主要修改说明:
添加缺失的标签:
在适当位置添加了 free_entity: 和 free_ctrl: 标签
添加了 error_pm: 标签用于电源管理错误处理
修复作用域问题:
将文件作用域的错误代码移动到 ov5645_probe 函数内部
修复了变量声明的位置问题
其他修复:
添加了必要的错误处理代码
修正了函数调用参数类型
确保所有错误路径都有正确的清理代码
移除有问题的代码段:
移除了重复的、位置错误的 v4l2_async_register_subdev_sensor 调用
修正了 ov5645_remove 函数中不合理的代码
使用方法:
将上面的补丁保存为 ov5645-fix.patch
在内核源码目录执行:
bash
patch -p1 < ov5645-fix.patch
重新编译驱动
如果问题仍然存在,可能需要检查内核版本与驱动的兼容性,或者查看是否有其他相关的补丁需要应用。
3、经过DeepSeek的提醒,确认是{}括号的问题!
Y:\new_disk_4t\wyb\A8\rk3588_linux6.1_release_v1.2.0_20241220\kernel-6.1\drivers\media\i2c\ov5645.c
static int ov5645_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device_node *endpoint;
struct ov5645 *ov5645;
u8 chip_id_high, chip_id_low;
unsigned int i;
u32 xclk_freq;
char facing[2];
int ret;
ov5645 = devm_kzalloc(dev, sizeof(struct ov5645), GFP_KERNEL);
if (!ov5645)
return -ENOMEM;
ov5645->i2c_client = client;
ov5645->dev = dev;
endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
if (!endpoint) {
dev_err(dev, "endpoint node not found\n");
return -EINVAL;
}
ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint),
&ov5645->ep);
of_node_put(endpoint);
if (ret < 0) {
dev_err(dev, "parsing endpoint node failed\n");
return ret;
}
if (ov5645->ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
dev_err(dev, "invalid bus type, must be CSI2\n");
return -EINVAL;
}
ret = of_property_read_u32(dev->of_node, RKMODULE_CAMERA_MODULE_INDEX,
&ov5645->module_index);
if (ret) {
dev_warn(dev, "could not get module index!\n");
ov5645->module_index = 0;
}
ret |= of_property_read_string(dev->of_node, RKMODULE_CAMERA_MODULE_FACING,
&ov5645->module_facing);
ret |= of_property_read_string(dev->of_node, RKMODULE_CAMERA_MODULE_NAME,
&ov5645->module_name);
ret |= of_property_read_string(dev->of_node, RKMODULE_CAMERA_LENS_NAME,
&ov5645->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
/* get system clock (xclk) */
ov5645->xclk = devm_clk_get(dev, "xclk");
if (IS_ERR(ov5645->xclk)) {
dev_err(dev, "could not get xclk");
return PTR_ERR(ov5645->xclk);
}
ret = of_property_read_u32(dev->of_node, "clock-frequency", &xclk_freq);
if (ret) {
dev_err(dev, "could not get xclk frequency\n");
return ret;
}
/* external clock must be 24MHz, allow 1% tolerance */
if (xclk_freq < 23760000 || xclk_freq > 24240000) {
dev_err(dev, "external clock frequency %u is not supported\n",
xclk_freq);
return -EINVAL;
}
ret = clk_set_rate(ov5645->xclk, xclk_freq);
if (ret) {
dev_err(dev, "could not set xclk frequency\n");
return ret;
}
for (i = 0; i < OV5645_NUM_SUPPLIES; i++)
ov5645->supplies[i].supply = ov5645_supply_name[i];
ret = devm_regulator_bulk_get(dev, OV5645_NUM_SUPPLIES,
ov5645->supplies);
if (ret < 0)
return ret;
ov5645->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
if (IS_ERR(ov5645->enable_gpio)) {
dev_err(dev, "cannot get enable gpio\n");
return PTR_ERR(ov5645->enable_gpio);
}
ov5645->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ov5645->rst_gpio)) {
dev_err(dev, "cannot get reset gpio\n");
return PTR_ERR(ov5645->rst_gpio);
}
mutex_init(&ov5645->power_lock);
v4l2_ctrl_handler_init(&ov5645->ctrls, 9);
v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops,
V4L2_CID_SATURATION, -4, 4, 1, 0);
v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops,
V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops,
V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
v4l2_ctrl_new_std_menu(&ov5645->ctrls, &ov5645_ctrl_ops,
V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL,
0, V4L2_EXPOSURE_AUTO);
v4l2_ctrl_new_std_menu_items(&ov5645->ctrls, &ov5645_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(ov5645_test_pattern_menu) - 1,
0, 0, ov5645_test_pattern_menu);
ov5645->pixel_clock = v4l2_ctrl_new_std(&ov5645->ctrls,
&ov5645_ctrl_ops,
V4L2_CID_PIXEL_RATE,
1, INT_MAX, 1, 1);
ov5645->link_freq = v4l2_ctrl_new_int_menu(&ov5645->ctrls,
&ov5645_ctrl_ops,
V4L2_CID_LINK_FREQ,
ARRAY_SIZE(link_freq) - 1,
0, link_freq);
if (ov5645->link_freq)
ov5645->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
ov5645->sd.ctrl_handler = &ov5645->ctrls;
if (ov5645->ctrls.error) {
dev_err(dev, "%s: control initialization error %d\n",
__func__, ov5645->ctrls.error);
ret = ov5645->ctrls.error;
goto free_ctrl;
}
v4l2_i2c_subdev_init(&ov5645->sd, client, &ov5645_subdev_ops);
ov5645->sd.internal_ops = &ov5645_internal_ops;
ov5645->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
ov5645->pad.flags = MEDIA_PAD_FL_SOURCE;
ov5645->sd.dev = &client->dev;
ov5645->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&ov5645->sd.entity, 1, &ov5645->pad);
if (ret < 0) {
dev_err(dev, "could not register media entity\n");
goto free_ctrl;
}
ret = ov5645_s_power(&ov5645->sd, true);
if (ret < 0) {
dev_err(dev, "could not power up OV5645\n");
goto free_entity;
}
//ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_HIGH, &chip_id_high);
//if (ret < 0 || chip_id_high != OV5645_CHIP_ID_HIGH_BYTE) {
// dev_err(dev, "could not read ID high\n");
// ret = -ENODEV;
// goto power_down;
//}
//ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_LOW, &chip_id_low);
//if (ret < 0 || chip_id_low != OV5645_CHIP_ID_LOW_BYTE) {
// dev_err(dev, "could not read ID low\n");
// ret = -ENODEV;
// goto power_down;
//}
//
//dev_info(dev, "OV5645 detected at address 0x%02x\n", client->addr);
//
//ret = ov5645_read_reg(ov5645, OV5645_AEC_PK_MANUAL,
// &ov5645->aec_pk_manual);
//if (ret < 0) {
// dev_err(dev, "could not read AEC/AGC mode\n");
// ret = -ENODEV;
// goto power_down;
//}
//
//ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG20,
// &ov5645->timing_tc_reg20);
//if (ret < 0) {
// dev_err(dev, "could not read vflip value\n");
// ret = -ENODEV;
// goto power_down;
//}
//
//ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG21,
// &ov5645->timing_tc_reg21);
//if (ret < 0) {
// dev_err(dev, "could not read hflip value\n");
// ret = -ENODEV;
// goto power_down;
//}
ov5645_s_power(&ov5645->sd, false);
memset(facing, 0, sizeof(facing));
if (strcmp(ov5645->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(ov5645->sd.name, sizeof(ov5645->sd.name), "m%02d_%s_%s %s",
ov5645->module_index, facing,
"ov5645", dev_name(ov5645->sd.dev));
ret = v4l2_async_register_subdev_sensor(&ov5645->sd);
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
}
#if 0
ret = v4l2_async_register_subdev(&ov5645->sd);
if (ret < 0) {
dev_err(dev, "could not register v4l2 device\n");
goto free_entity;
}
#endif
ov5645_entity_init_cfg(&ov5645->sd, NULL);
return 0;
power_down:
ov5645_s_power(&ov5645->sd, false);
free_entity:
media_entity_cleanup(&ov5645->sd.entity);
free_ctrl:
v4l2_ctrl_handler_free(&ov5645->ctrls);
mutex_destroy(&ov5645->power_lock);
return ret;
}