全志MR536 Tina Linux TWI(I2C) VEML7700光感驱动实现

全志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 设备驱动就基本上可以了,后面再更新一下源码上来这里。    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值