一,保留现场
换了个板子和kernel版本后,ov13850驱动起不来了,报如下错误
root@feifeirk:/tmp# insmod rk_ov.ko
335.315715 rk_ov: loading out-of-tree module taints kernel.
335.322983 ov13850 3-0010: driver version: 00.01.03
335.328061 ov13850 3-0010: GPIO lookup for consumer reset
335.333545 ov13850 3-0010: using device tree for GPIO lookup
335.339356 of_get_named_gpiod_flags: parsed 'reset-gpios' property of node '/i2c@ff150000/ov13850@100' - status (0)
335.350337 ov13850 3-0010: GPIO lookup for consumer pwdn
335.355762 ov13850 3-0010: using device tree for GPIO lookup
335.361522 of_get_named_gpiod_flags: parsed 'pwdn-gpios' property of node '/i2c@ff150000/ov13850@100' - status (0)
335.374348 ov13850 3-0010: Unexpected sensor id(000000), ret(-5)
root@feifeirk:/tmp#
跟踪日志到ov13850_probe->ov13850_check_sensor_id
ret = ov13850_read_reg(client, OV13850_REG_CHIP_ID,
OV13850_REG_VALUE_16BIT, &id);
if (id != CHIP_ID) {
dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
return -ENODEV;
}
原先的代码ov13850_check_sensor_id出错后会关闭power
ret = ov13850_check_sensor_id(ov13850, client);
if (ret)
goto err_power_off;
先改成直接返回成功,保留现场
ret = ov13850_check_sensor_id(ov13850, client);
return 0;
二,分析pin脚和pwr
引脚:
引脚3表示数字电压DVDD,给芯片的数字信号供电,CIF_POWER (GPIO7_B4)引脚控制
引脚4是芯片引脚出来的电压IOVDD,rk3288中受DVP_PWR(GPIO0_B3)控制
引脚7是模拟电压AVDD,给芯片中的模拟器件供电,比如camera供电就要用到AVDD,也是相对于DVDD区别出来的,rk3288中受DVP_PWR(GPIO0_B3)控制
引脚11复位信号输出,GPIO2_B7,硬件上拉
引脚12是Power Down 信号输出,GPIO2_B6
引脚14是时钟输出(提供给外部摄像头的主时钟),GPIO2_B3
电源引脚3/4/7先不看,直接量电压。
reset和Power Down都是高,都是正常的,引脚14暂时还用不到,说明pin脚没有问题。
三,分析power
从dts中总结有三个:
dvdd_1v2: dvdd-1v2 {
status = "okay";
compatible = "regulator-fixed";
enable-active-high;
gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&cif_pwr>;
regulator-name = "dvdd_1v2";
};
vcc28_dvp: vcc28-dvp-regulator {
compatible = "regulator-fixed";
enable-active-high;
gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&dvp_pwr>;
regulator-name = "vcc28_dvp";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
regulator-always-on;
vin-supply = <&vcc_io>;
};
dovdd_1v8: dovdd-1v8-regulator {
compatible = "regulator-fixed";
regulator-name = "dovdd_1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
vin-supply = <&vcc28_dvp>;
};
root@feifeirk:/tmp# ls /sys/class/regulator/regulator.*/name
/sys/class/regulator/regulator.0/name
/sys/class/regulator/regulator.1/name
/sys/class/regulator/regulator.10/name
/sys/class/regulator/regulator.11/name
/sys/class/regulator/regulator.12/name
/sys/class/regulator/regulator.13/name
/sys/class/regulator/regulator.14/name
/sys/class/regulator/regulator.15/name
/sys/class/regulator/regulator.16/name
/sys/class/regulator/regulator.17/name
/sys/class/regulator/regulator.18/name
/sys/class/regulator/regulator.19/name
/sys/class/regulator/regulator.2/name
/sys/class/regulator/regulator.20/name
/sys/class/regulator/regulator.21/name
/sys/class/regulator/regulator.3/name
/sys/class/regulator/regulator.4/name
/sys/class/regulator/regulator.5/name
/sys/class/regulator/regulator.6/name
/sys/class/regulator/regulator.7/name
/sys/class/regulator/regulator.8/name
/sys/class/regulator/regulator.9/name
root@feifeirk:/tmp# cat /sys/class/regulator/regulator.*/name
regulator-dummy
dvdd_1v2
vcc_ddr
vcc_io
vdd_log
vcc_20
vccio_sd
vdd10_lcd
vcca_codec
vcc_lan
vccio_pmu
vdd_10
vcc28_dvp
vcc_18
vcc18_lcd
dovdd_1v8
vcc1v8_sys
vcc_host
vcc_phy
vcc_sys
vdd_cpu
vdd_gpu
root@feifeirk:/tmp# cat /sys/class/regulator/regulator.*/state
disabled
enabled
enabled
enabled
enabled
enabled
enabled
enabled
enabled
enabled
enabled
enabled
enabled
enabled
enabled
enabled
enabled
enabled
万用表量三个电源都没有问题,
但是cat /sys/class/regulator/regulator.*/state查看dvdd_1v2偶尔没有state文件,说明dvdd_1v2电源有关闭情况。
给dvdd_1v2加上regulator-always-on属性后测试/sys/class/regulator/regulator稳定了,但还是probe失败。
四,分析原因
分析可能的原因:
1,dovdd_1v8需要io_domain配置dvp-supply = <&dovdd_1v8>,且摄像头驱动要在iodomain配置之后启动电源,iodomain寄存器配置错误
2,三个电源的启动顺序不对,影响了时序
3,reset或pwdn有拉低再拉高情况,没有走正常的pm_ops
第一点通过读寄存器验证没有问题
第二点通过临时去掉休眠,直接在probe关闭三个电源后,reset和pwdn拉低后,重新操作电源启动测试,
第三点通过确认dts没有干扰后,在每次操作reset和pwdn加日志打印确认拉高拉低确认
五,修复后的代码
1,dvdd_1v2加了regulator-always-on属性
2,增加了CONFIG_VIDEO_OV13850=y,将驱动写入了内核,这个是想看iodomain和ov的配置顺序,虽然没有问题,但是保留了这个修改
3,13850驱动里面,修改
(1)
(2)
(3)
改了这几处之后正常出流了:
因为发现dvdd_1v2中间被系统关闭了,所以ko改成编进内核,切屏蔽了dev_pm_ops,电源不被系统接管;
ov13850_s_power直接返回是临时屏蔽isp调用摄像头的s_pwr off功能造成的干扰,s_pwr off里面后操作reset拉低,先临时关闭;
因为ov13850_s_power直接返回了,所以里面的初始化序列加载了probe函数里面。
六,总结
修复的代码方式只是规避,但是能证明问题跟硬件没关系,跟三个pwr的顺序或reset有关,后续微调就能找到问题,比较好解决了。
开始以为引脚有问题,测量和加日志后发现没有任何问题。当时还怀疑硬件出问题了,这个引脚比较多,时序复杂,示波器line不够,如果没有一个出流的方案估计得上逻辑分析仪测试下电源启动顺序了,找到一个规避方法就能来回切换测试了。