1、从ST官方下载en.STSW-IMG005软件包,当前最新为1.0.4版本,软件包中有LinuxDriverMassMarket_1.0.7文件夹,继续打开LinuxDriverMassMarket_1.0.7\kernel\drivers\input\misc目录,将目录下的vl53L0X文件夹及内容拷贝到SDK的\kernel\drivers\input\misc目录下,修改misc目录下的Makefile及Kconfig添加VL53L0X。
Makefile末尾添加:
obj-$(CONFIG_STMVL53L0X) += vl53L0X/
Kconfig末尾添加:
config STMVL53L0X
tristate "ST VL53L0x haptics support"
depends on INPUT && I2C
select INPUT_FF_MEMLESS
select REGMAP_I2C
help
Say Y to enable support for the ST VL53L0x haptics driver.
To compile this driver as a module, choose M here: the
module will be called vl53l0x-haptics.
添加再endif之前。
2、修改vl53L0X目录下的Makefile,改为以下内容:
#
# Makefile for the vl53L0X drivers.
#
# Each configuration option enables a list of files.
FEATURE_USE_CCI := false
#FEATURE_USE_CCI := true
ifeq ($(FEATURE_USE_CCI), true)
ccflags-y += -Idrivers/input/misc/vl53L0X/inc -DCAMERA_CCI
else
ccflags-y += -Idrivers/input/misc/vl53L0X/inc -DSTM_TEST
ccflags-y += -Idrivers/input/misc/vl53L0X
endif
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ccflags-y += -Idrivers/media/platform/msm/camera_v2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
SRCS := $(wildcard ./src/*.c)
OBJS = $(SRCS:.c=.o)
obj-$(CONFIG_STMVL53L0X) += stmvl53l0x.o
stmvl53l0x-objs := stmvl53l0x_module.o stmvl53l0x_module-i2c.o stmvl53l0x_module-cci.o src/vl53l0x_api_calibration.o src/vl53l0x_api_core.o src/vl53l0x_api_ranging.o src/vl53l0x_api_strings.o src/vl53l0x_api.o src/vl53l0x_platform.o src/vl53l0x_i2c_platform.o src/vl53l0x_port_i2c.o
不修改编译会报错。
3、DTS文件中添加设备节点,需根据电路图确定VL53L01传感器是挂在那个i2c总线上,比如I2C2总线上,需在I2C2节点下方增加vl53l01的节点:
vl53l0x: vl53l0x@29 {
compatible = "st,stmvl53l0";
reg = <0x29>;
status = "okay";
};
4、进入SDK的kernel目录下,执行make menuconfig ARCH=arm64修改内核配置文件,添加 ST VL53L0x xxx
然后选择save,然后Exit,然后执行cp .config arch/arm64/configs/rockchip_linux_defconfig保存配置文件,然后重新编译内核,编译完成后烧写进主板。
5、接上传感器并将主板的日志打印串口连接到电脑的终端软件,然后启动主板,系统启动完成之后在终端输入dmesg | grep vl,查看vl53l01的加载日志:
[root@RK356X:/]# dmesg | grep stmvl
[ 0.896764] stmvl53l0x_init: Enter
[ 0.896781] stmvl53l0x_init_i2c: Enter
[ 0.896824] stmvl53l0x_init_i2c: End with rc:-22
[ 0.896839] stmvl53l0x_init: 1986 failed with -22
[ 0.896849] stmvl53l0x_init: End
[ 1.021873] stmvl53l0x_probe: Enter
[ 1.021899] stmvl53l0x_parse_vdd: Enter
[ 1.021919] stmvl53l0 2-0029: Looking up vdd-supply from device tree
[ 1.021926] stmvl53l0 2-0029: Looking up vdd-supply property in node /i2c@fe5b0000/vl53l0x@29 failed
[ 1.021953] stmvl53l0 2-0029: 2-0029 supply vdd not found, using dummy regulator
[ 1.022028] stmvl53l0 2-0029: Linked as a consumer to regulator.0
[ 1.022043] stmvl53l0x_parse_vdd: End
[ 1.022056] stmvl53l0x_setup: Enter
[ 1.022220] stmvl53l0x_poll_thread(758) : Starting Polling thread
[ 1.022524] stmvl53l0x_setup: Misc device registration name:2-0029
[ 1.022660] stmvl53l0x_setup: support ver. 1.0.5 enabled
[ 1.022676] stmvl53l0x_setup: End
[ 1.022678] stmvl53l0x_probe: End
经过实际测试,无论传感器与主板连接与否,都是这些日志,所以不能通过启动日志判断传感器是否正常连接。
6、可通过i2c tool工具查看传感器是否连接,命令终端输入i2cdetect -y 2即可查看i2c2总线上挂载的设备,如果传感器连接正常即可看到有0x29地址的设备。
7、测试传感器读取距离值
使用SDK的编译工具编译LinuxDriverMassMarket_1.0.7\kernel目录下的vl53l0x_test应用,编译成功后将执行文件推送到主板,然后运行,正常情况即可看到日志打印距离值,由于没有进行传感器校准,所以读取的距离值和实际距离值有偏差。
运行vl53l01x_test的日志
[root@RK356X:/userdata/bin]# ./vl53l0x_test
[ 175.411550] VL53L0X_GetDeviceInfo:
[ 175.420316] Device Name : VL53L0X ES1 or later
[ 175.420355] Device Type : VL53L0X
[ 175.420363] Device ID : VL53L0C
[ 175.420370] Product type: 238
[ 175.420378] ProductRevisionMajor : 1
[ 175.420385] ProductRevisionMinor : 1
[ 175.420391] Call of VL53L0X_StaticInit
[ 175.497162] Call of VL53L0X_SetDeviceMode
[ 175.501836] DeviceMode:0x1, interMeasurems:30==
[ 175.503118] Configure Long Ranging
[ 175.503555] Set Timing Budget = 26000
Range: 45, Error:0, SigRate_mcps:1744896, AmbRate_mcps: 1536
8、中断或查询模式
stmvl53l0x_module.cwe文件中有#define USE_INT宏定义用于定义使用中断模式或查询模式读取寄存器状态,如果取消USE_INT的注释,则使用中断模式,使用中断模式需要连接传感器的INT管脚到处理器的GPIO上。
1、通过宏定义开启或关闭日志打印,需要修改下stmvl53l0x.h文件:
将
#define DEBUG
#define vl53l0x_dbgmsg(str, args...) \
pr_err("%s: " str, __func__, ##args)
#define vl53l0x_errmsg(str, args...) \
pr_err("%s: " str, __func__, ##args)
改为:
#define DEBUG
#ifdef DEBUG
#define vl53l0x_dbgmsg(str, args...) \
pr_err("%s: " str, __func__, ##args)
#define vl53l0x_errmsg(str, args...) \
pr_err("%s: " str, __func__, ##args)
#else
#define vl53l0x_dbgmsg(str, args...) \
(void)0
#define vl53l0x_errmsg(str, args...) \
(void)0
#endif
如果想关闭日志打印,则注释#define DEBUG即可。
2、在stmvl53l0x_module-i2c.c文件的stmvl53l0x_probe()加入检测传感器是否连接的代码,通过读取传感器的ID号以判断传感器是否连接,在stmvl53l0x_parse_vdd(&i2c_object->client->dev, i2c_object);之后加入如下代码:
/* read VL53L0X ID */
Status = VL53L0X_RdByte(vl53l0x_data, VL53L0X_REG_IDENTIFICATION_MODEL_ID,
&module_id);
if( Status )
{
vl53l0x_dbgmsg("get module_id err:%d\n", Status );
}
else
{
vl53l0x_dbgmsg("module_id:%02X\n", module_id );
}
3、中断模式的IRQ_NUM从DTS文件中解析
驱动默认注释了USE_INT (/* #define USE_INT */),即不使用中断模式,并且中断的GPIO号实在驱动中定义的,这样方便管脚的更换,可修改为从DTS文件中解析。
stmvl53l0x.h文件的struct stmvl53l0x_data{ }结构中增加irq_gpiounsigned和irq_gpio_flags两个变量:
struct stmvl53l0x_data {
/* !
stmvl53l0x_module-i2c.c文件中增加#include
stmvl53l0x_module-i2c.c文件中增加stmvl53l0x_parse_dt()函数:
static int stmvl53l0x_parse_dt(struct device *dev, struct stmvl53l0x_data *pdata)
{
int ret = 0;
struct device_node *np = dev->of_node;
const struct of_device_id *match;
match=of_match_device(st_stmvl53l0x_dt_match,dev);
if(!match){
vl53l0x_errmsg("DTS Unable to find matchv device.");
return -1;
}
pdata->irq_gpio = of_get_named_gpio_flags(np, "st,irq-gpio", 0, &pdata->irq_gpio_flags);
if (pdata->irq_gpio < 0){
vl53l0x_errmsg("DTS Unable to get irq_gpio");
ret = -1;
}
else
{
vl53l0x_dbgmsg("irq gpio:%d", pdata->irq_gpio);
}
return ret;
}
在stmvl53l0x_probe()函数中调用此函数:
static int stmvl53l0x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc = 0;
struct stmvl53l0x_data *vl53l0x_data = NULL;
struct i2c_data *i2c_object = NULL;
VL53L0X_Error Status = VL53L0X_ERROR_NONE;
uint8_t module_id;
vl53l0x_dbgmsg("Enter\n");
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
rc = -EIO;
return rc;
}
vl53l0x_data = kzalloc(sizeof(struct stmvl53l0x_data), GFP_KERNEL);
if (!vl53l0x_data) {
rc = -ENOMEM;
return rc;
}
if (vl53l0x_data) {
vl53l0x_data->client_object =
kzalloc(sizeof(struct i2c_data), GFP_KERNEL);
i2c_object = (struct i2c_data *)vl53l0x_data->client_object;
}
i2c_object->client = client;
/* setup bus type */
vl53l0x_data->bus_type = I2C_BUS;
/* setup regulator */
stmvl53l0x_parse_vdd(&i2c_object->client->dev, i2c_object);
/* setup dt */
stmvl53l0x_parse_dt(&i2c_object->client->dev, vl53l0x_data);
/* read VL53L0X ID */
Status = VL53L0X_RdByte(vl53l0x_data, VL53L0X_REG_IDENTIFICATION_MODEL_ID,
&module_id);
if( Status )
{
vl53l0x_dbgmsg("get module_id err:%d\n", Status );
}
else
{
vl53l0x_dbgmsg("module_id:%02X\n", module_id );
}
/* setup device name */
vl53l0x_data->dev_name = dev_name(&client->dev);
/* setup device data */
dev_set_drvdata(&client->dev, vl53l0x_data);
/* setup client data */
i2c_set_clientdata(client, vl53l0x_data);
/* setup other stuff */
rc = stmvl53l0x_setup(vl53l0x_data);
/* init default value */
i2c_object->power_up = 0;
vl53l0x_dbgmsg("End\n");
return rc;
}
修改stmvl53l0x_module.c文件,
将
gpio_request(IRQ_NUM, "vl53l0x_gpio_int");
gpio_direction_input(IRQ_NUM);
irq = gpio_to_irq(IRQ_NUM);
if (irq < 0) {
vl53l0x_errmsg("filed to map GPIO: %d to interrupt:%d\n",
IRQ_NUM, irq);
改为
gpio_request( data->irq_gpio, "vl53l0x_gpio_int");
gpio_direction_input(data->irq_gpio);
irq = gpio_to_irq(data->irq_gpio);
if (irq < 0) {
vl53l0x_errmsg("filed to map GPIO: %d to interrupt:%d\n",
data->irq_gpio, irq);