一、添加、编译驱动
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比如总线I2C需要在总线上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即可查看i2c如果传感器连接正常,2总线上挂载的设备可以看到0x地址设备。
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...) \ p_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 {
/* !<embed ST VL53L0 Dev data as "dev_data" */
VL53L0X_DevData_t Data;
/*!< i2c device address user specific field*/
uint8_t I2cDevAddr;
/*!< Type of comms : VL53L0_COMMS_I2C or VL53L0_COMMS_SPI */
uint8_t comms_type;
/*!< Comms speed [kHz] : typically 400kHz for I2C */
uint16_t comms_speed_khz;
/* CCI_BUS; I2C_BUS */
uint8_t bus_type;
void *client_object; /* cci or i2c client */
struct mutex update_lock;
struct delayed_work dwork; /* for PS work handler */
struct input_dev *input_dev_ps;
struct kobject *range_kobj;
const char *dev_name;
/* function pointer */
/* misc device */
struct miscdevice miscdev;
int irq_gpio;
unsigned int irq_gpio_flags;
int irq;
unsigned int reset;
/* control flag from HAL */
unsigned int enable_ps_sensor;
/* PS parameters */
unsigned int ps_data; /* to store PS data */
/* Calibration parameters */
unsigned int offsetCalDistance;
unsigned int xtalkCalDistance;
/* Range Data */
VL53L0X_RangingMeasurementData_t rangeData;
/* Device parameters */
VL53L0X_DeviceModes deviceMode;
uint32_t interMeasurems;
VL53L0X_GpioFunctionality gpio_function;
VL53L0X_InterruptPolarity gpio_polarity;
FixPoint1616_t low_threshold;
FixPoint1616_t high_threshold;
/* delay time in miniseconds*/
uint8_t delay_ms;
/* Timing Budget */
uint32_t timingBudget;
/* Use this threshold to force restart ranging */
uint32_t noInterruptCount;
/* Use this flag to use long ranging*/
int useLongRange;
/* Polling thread */
struct task_struct *poll_thread;
/* Wait Queue on which the poll thread blocks */
wait_queue_head_t poll_thread_wq;
/* Recent interrupt status */
uint32_t interruptStatus;
struct mutex work_mutex;
/* Debug */
unsigned int enableDebug;
uint8_t interrupt_received;
};
stmvl53l0x_module-i2c.c文件中增加#include <linux/of_device.h>
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);