全志MR536 Tina TWI(I2C) VEML7700光感驱动实现
实现该驱动计划分几个步骤走:
1、规格书
2、上层i2ctools 测试基本的读写
3、linux内核的设备定义
4、内核驱动实现
1、规格书
I2CADD
关键的点为:
I2C ADD = 0x10

验证I2C ADD 可以用i2ctools工具来测试,比如i2cget veml7700 的ID
root@TinaLinux:~# i2cget -f -y 0 0x10 0x07 w
0xc481

获取的device ID 是0xc481 可以和上面的寄存器对应上。
2、设备实现
&twi0 {
clock-frequency = <400000>;
pinctrl-0 = <&twi0_pins_default>;
pinctrl-1 = <&twi0_pins_sleep>;
pinctrl-names = "default", "sleep";
/* For stability and backwards compatibility, we recommend setting ‘twi_drv_used’ to 1 */
twi_drv_used = <1>;
status = "okay";
veml7700: veml7700@20 {
compatible = "allwinner,veml7700";
reg = <0x20>;
status = "okay";
};
};
实现上面的设备后,可以进入tina 系统下验证是否可以看到device的存在:
root@TinaLinux:~# find / -name "*veml7700*"
/sys/firmware/devicetree/base/soc@3000000/twi@2510000/veml7700@20
/sys/firmware/devicetree/base/__symbols__/veml7700
root@TinaLinux:/sys/bus/i2c/devices# ls
0-0020 7-0035 i2c-0 i2c-2 i2c-5
5-0039 7-0036 i2c-1 i2c-4 i2c-7
root@TinaLinux:/sys/bus/i2c/devices# cd 0-0020/
root@TinaLinux:/sys/devices/platform/soc@3000000/2510000.twi/i2c-0/0-0020# ls
modalias power waiting_for_supplier
name subsystem
of_node uevent
root@TinaLinux:/sys/devices/platform/soc@3000000/2510000.twi/i2c-0/0-0020# cat n
ame
veml7700
root@TinaLinux:/sys/devices/platform/soc@3000000/2510000.twi/i2c-0/0-0020# cat m
odalias
of:Nveml7700T(null)Callwinner,veml7700
以上信息即可看到定义的设备已经出来了。
3、驱动实现
1、Kconfig
kernel/linux-5.15-origin/drivers/iio/light/Kconfig
config VEML7700
tristate "VEML7700 UV A light sensor"
depends on I2C
help
Say Y here if you want to build a driver for the Vishay VEML7700 UV A
light sensor.
To compile this driver as a module, choose M here: the
module will be called VEML7700.
2、makefile
kernel/linux-5.15-origin/drivers/iio/light/Kconfig
obj-$(CONFIG_VEML7700) += veml7700.o
3、driver 实现
主要参考veml6070.c的代码实现,完整正常的驱动后面再更新;代码关键的点如下:
/* Device registers */
#define VEML7700_REG_ALS_CONF 0x00
#define VEML7700_REG_ALS_WH 0x01
#define VEML7700_REG_ALS_WL 0x02
#define VEML7700_REG_ALS_PSM 0x03
#define VEML7700_REG_ALS_DATA 0x04
#define VEML7700_REG_WH_DATA 0x05
#define VEML7700_REG_ALS_INT 0x06
#define VEML7700_REG_ID 0x07
#define DEVICE_ID1 0xC481 // i2c add=0x20(0x10<<1) -> 0xc481
#define DEVICE_ID2 0xD481 // i2c add=0x90(0x50<<1) -> 0xD481
static const struct dev_pm_ops veml7700_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(veml7700_runtime_suspend,
veml7700_runtime_resume, NULL)
};
static const struct of_device_id veml7700_of_match[] = {
{ .compatible = "allwinner,veml7700" },
{ }
};
MODULE_DEVICE_TABLE(of, veml7700_of_match);
static const struct i2c_device_id veml7700_id[] = {
{ "allwinner,veml7700", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, veml7700_id);
static struct i2c_driver veml7700_driver = {
.driver = {
.name = "allwinner,veml7700",
.of_match_table = veml7700_of_match,
.pm = &veml7700_pm_ops,
},
.probe = veml7700_probe,
.id_table = veml7700_id,
};
module_i2c_driver(veml7700_driver);
可以看到驱动有加载了,失败原因留在下节在更新。
上面的驱动中,I2C报了三行关键的错,
[ 493.718320] sunxi:twi-2510000.twi:[ERR]: drv-mode: Timeout when sending 9th SCL clk
[ 493.719285] sunxi:twi-2510000.twi:[ERR]: drv mode: TWI BUS error state is drv:0x1 eng:0x20
[ 493.720385] sunxi:twi-2510000.twi:[ERR]: drv-mode: xfer failed (dev addr:0x20)
这也是调试I2C比较花时间的地方,网上有一些类似的问题,不过实际情况可能都不一样,现在我们用的veml7700在用户空间用i2ctools是能测试成功的,那说明硬件没有问题,那就要从软件入手了,首先检查i2c地址,前面的内容中,我们把i2c add定义为0x20,实际规格书7bit中是0x10,那我们把i2c add 改为0x20再看看是否正常。更新设备定义字段的i2c add:
&twi0 {
clock-frequency = <400000>;
pinctrl-0 = <&twi0_pins_default>;
pinctrl-1 = <&twi0_pins_sleep>;
pinctrl-names = "default", "sleep";
/* For stability and backwards compatibility, we recommend setting ‘twi_drv_used’ to 1 */
twi_drv_used = <1>;
status = "okay";
veml7700: veml7700@10 {
compatible = "allwinner,veml7700";
reg = <0x10>;
status = "okay";
};
};
更新I2C add后,再次加载驱动,即可以成功加载了:
root@TinaLinux:/lib/modules/5.15.147# dmesg -c
[ 201.999844] allwinner,veml7700 0-0010: veml7700_probe start ...
[ 202.000591] allwinner,veml7700 0-0010: veml7700_probe devm_regmap_init_i2c ...
[ 202.001532] allwinner,veml7700 0-0010: veml7700_probe devm_iio_device_alloc ...
[ 202.002443] allwinner,veml7700 0-0010: veml7700_probe veml7700_hw_init ...
[ 202.008718] allwinner,veml7700 0-0010: veml7700_probe devm_add_action_or_reset ...
[ 202.009648] allwinner,veml7700 0-0010: veml7700_probe devm_iio_device_register ...
再看看系统下有那些和veml7700相关的节点:
root@TinaLinux:/lib/modules/5.15.147# find / -name "*veml*"
/lib/modules/5.15.147/veml7700.ko
/overlay/upper/lib/modules/5.15.147/veml7700.ko
/sys/kernel/debug/regmap/0-0010-veml7700_regmap
/sys/bus/i2c/drivers/allwinner,veml7700
/sys/firmware/devicetree/base/soc@3000000/twi@2510000/veml7700@10
/sys/firmware/devicetree/base/__symbols__/veml7700
/sys/module/veml7700
/sys/module/veml7700/drivers/i2c:allwinner,veml7700
先来看看/sys/kernel/debug/regmap/0-0010-veml7700_regmap
root@TinaLinux:/sys/kernel/debug/regmap/0-0010-veml7700_regmap# cat name
allwinner,veml7700
root@TinaLinux:/sys/kernel/debug/regmap/0-0010-veml7700_regmap# cat range
0-7
root@TinaLinux:/sys/kernel/debug/regmap/0-0010-veml7700_regmap# cat registers
0: 0001
1: 0000
2: 0000
3: 0000
4: 0000
5: 0000
6: 1018
7: c481
root@TinaLinux:/sys/kernel/debug/regmap/0-0010-veml7700_regmap#
其中 4 和 5 是光感值, 7是device ID,前面有提到过。
因为用Linux IIO框架,所以再看看IIO目录:
root@TinaLinux:/sys/devices/platform/soc@3000000/2510000.twi/i2c-0/0-0010/iio:device0# ls
dev
events
in_illuminance_input
in_illuminance_integration_time
in_illuminance_integration_time_available
in_illuminance_raw
in_illuminance_scale
in_illuminance_scale_available
in_intensity_both_input
in_intensity_both_raw
name
of_node
power
subsystem
root@TinaLinux:/sys/devices/platform/soc@3000000/2510000.twi/i2c-0/0-0010/iio:device0# cat name
veml7700
4、编译进固件
以上步骤只能编译veml7700.ko,需要手动insmod,如何编译进固件,并自动加载呢,那有两个文件可以加入:
tina-mr536-v1.3/openwrt/target/mr536/mr536-common/modules.mk
tina-mr536-v1.3/openwrt/target/mr536/mr536-evb1/modules.mk
其中,第一个路径为公共路径,第二个路径为板卡路径,veml7700的选项加入到第二个文件中:
define KernelPackage/vin
SUBMENU:=$(VIDEO_MENU)
TITLE:=vin support
DEPENDS:=+kmod-video-videobuf2
FILES+=$(CONFIG_EXTERNAL_KERNEL_TREE)/drivers/media/common/videobuf2/videobuf2-dma-contig.ko
FILES+=$(CONFIG_EXTERNAL_KERNEL_TREE)/bsp/drivers/vin/vin_io.ko
FILES+=$(CONFIG_EXTERNAL_KERNEL_TREE)/bsp/drivers/vin/modules/sensor/ov8856_mipi.ko
FILES+=$(CONFIG_EXTERNAL_KERNEL_TREE)/bsp/drivers/vin/modules/sensor/sc035hgs_mipi.ko
FILES+=$(CONFIG_EXTERNAL_KERNEL_TREE)/bsp/drivers/vin/vin_v4l2.ko
KCONFIG:=\
CONFIG_V4L_PLATFORM_DRIVERS=y \
CONFIG_MEDIA_CONTROLLER=y \
CONFIG_MEDIA_SUBDRV_AUTOSELECT=y \
CONFIG_VIDEO_SUNXI_VIN \
CONFIG_CSI_VIN \
CONFIG_CCI
AUTOLOAD:=$(call AutoLoad,95,videobuf2-common videobuf2-memops videobuf2-dma-contig videobuf2-v4l2 vin_io ov8856_mipi sc035hgs_mipi vin_v4l2)
endef
define KernelPackage/vin/description
Kernel modules for vin support
endef
$(eval $(call KernelPackage,vin))
#### for VEML7700 ASL
define KernelPackage/veml7700
SUBMENU:=$(IIO_MENU)
TITLE:=veml7700 support
DEPENDS:=
FILES+=$(CONFIG_EXTERNAL_KERNEL_TREE)/drivers/iio/light/veml7700.ko
KCONFIG:=
AUTOLOAD:=
endef
define KernelPackage/vin/description
Kernel modules for veml7700 support
endef
$(eval $(call KernelPackage,veml7700))
veml的内容也是参考上面vin的内容进行修改,如果要开机自动加载veml7700.ko,那在AUTOLOAD加入
AUTOLOAD:=$(call AutoLoad,95,veml7700.ko)
然后在make menuconfig中选中veml7700即可

到这里,这个VEML7700的I2C 设备驱动就基本上可以了,后面再更新一下源码上来这里。
332

被折叠的 条评论
为什么被折叠?



