工作记录与回顾:
移植过程:
一般按照厂商提供的代码移植,注意以下框架
1.添加设备树信息(对应总线下)
路径:arch-arm64-boot-dts-rochchip-rk3588-vehicle-s66-v10.dtsi
omi8658_acc@6a {
status = "okay";
reg = <0x6a>;
compatible ="qmi8658_acc";
type = <SENSOR_TYPE_ACCEL>;
poll_delay_ms =<30>;
power-off-in-suspend = <1>;layout = <4>;
};qmi8658_gyro@6a {
status ="okay";
compatible ="qmi8658_gyro";
reg = <0x6a>;
type = <SENSOR_TYPE_GYROSCOPE>;
power-off-in-suspend = <1>;
poll_delay_ms = <30>;
};
2。在include/linux/sensor-dev.h下进行设备的排号
enum sensor_id {
。。。
COMPASS_ID_AK09918,
ACCEL_ID_QMI8658,。。。
GYRO_ID_IAM20680,
GYRO_ID_QMI8658,。。。
}
这只需要把需要加的功能添加到相应的区域
3,。按照厂商给的驱动的.c文件进行注册
路径一般按照注册的sensor类型来决定
drivers-input-gyro
drivers-input-accle
驱动如下:
/* drivers/input/sensors/access/qmi8658_acc.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: oeh<oeh@rock-chips.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <linux/of_gpio.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/sensor-dev.h>
#include <linux/qmi8658.h>
static int qmi8658_set_rate(struct i2c_client *client, int rate)
{
const short hz[] = {448, 224, 112, 56, 28};
const int d[] = {0x24, 0x25,0x26, 0x27, 0x28};
int i =0, data =0, result =0;
/* always use poll mode, no need to set rate */
return 0;
if ((rate < 1) || (rate > 480))
return -1;
while ((rate > hz[i]) && (i < 5))
i++;
data = d[i];
result = sensor_write_reg(client, QMI8658_REG_CTRL2, data);
if (result)
return -1;
return 0;
}
static int sensor_active(struct i2c_client *client, int enable, int rate)
{
// struct sensor_private_data *sensor =
// (struct sensor_private_data *) i2c_get_clientdata(client);
int result = 0;
u8 databuf[2] = {0};
databuf[0] = sensor_read_reg(client, QMI8658_REG_CTRL7);
if (!enable) {
databuf[0] = (databuf[0] & 0xFE) | 0x80; //accel disable;
} else {
databuf[0] = (databuf[0] & 0xFE) | 0x81; //accel enable;
qmi8658_set_rate(client, rate);
}
result = sensor_write_reg(client, QMI8658_REG_CTRL7, databuf[0]);
if (result) {
dev_err(&client->dev, "%s:fail to set pwrm1\n", __func__);
return -1;
}
dev_err(&client->dev, "zhoucs %s:activer OK, enable=%d, result=%d\n", __func__, enable, result);
return result;
}
static int sensor_init(struct i2c_client *client)
{
int res = 0;
u8 read_data = 0,reg_value = 0;
struct sensor_private_data *sensor =
(struct sensor_private_data *) i2c_get_clientdata(client);
read_data = sensor_read_reg(client, sensor->ops->id_reg);
if (read_data != sensor->ops->id_data) {
dev_err(&client->dev, "%s:check id err,read_data:%d,ops->id_data:%d\n",
__func__, read_data, sensor->ops->id_data);
return -1;
}else{
dev_err(&client->dev, "%s:check id success -->qmi8658\n", __func__);
}
res = sensor_write_reg(client, QMI8658_REG_RESET, QMI8658_SW_RESET);
if (res) {
dev_err(&client->dev, "set QMI8658_SW_RESET error,res: %d!\n", res);
return res;
}
msleep(15);
res = sensor_write_reg(client, QMI8658_REG_CTRL1, QMI8658_ADDR_AI_BE);
if (res) {
dev_err(&client->dev, "set QMI8658_REG_CTRL1 error,res: %d!\n", res);
return res;
}
reg_value = QMI8658_ACC_RANGE_DEF|QMI8658_ODR_470HZ_REG_VALUE;// ±8g,odr=479hz
res = sensor_write_reg(client, QMI8658_REG_CTRL2, reg_value);
if (res) {
dev_err(&client->dev, "set QMI8658_REG_CTRL2 error,res: %d!\n", res);
return res;
}
reg_value = QMI8658_GYR_RANGE_2048DPS|QMI8658_ODR_470HZ_REG_VALUE;//2048dps,odr=479hz
res = sensor_write_reg(client, QMI8658_REG_CTRL3, reg_value);
if (res) {
dev_err(&client->dev, "set QMI8658_REG_CTRL3 error,res: %d!\n", res);
return res;
}
res = sensor->ops->active(client, 0, sensor->pdata->poll_delay_ms);
if (res) {
dev_err(&client->dev, "%s:line=%d,error\n", __func__, __LINE__);
return res;
}
return res;
}
static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis)
{
struct sensor_private_data *sensor =
(struct sensor_private_data *) i2c_get_clientdata(client);
if (sensor->status_cur == SENSOR_ON) {
/* Report acceleration sensor information */
input_report_abs(sensor->input_dev, ABS_X, axis->x);
input_report_abs(sensor->input_dev, ABS_Y, axis->y);
input_report_abs(sensor->input_dev, ABS_Z, axis->z);
input_sync(sensor->input_dev);
}
return 0;
}
static int sensor_report_value(struct i2c_client *client)
{
struct sensor_private_data *sensor =
(struct sensor_private_data *) i2c_get_clientdata(client);
struct sensor_platform_data *pdata = sensor->pdata;
int ret = 0;
short x, y, z;
struct sensor_axis axis;
u8 buffer[6] = {0};
// char value = 0, count = 0;
if (sensor->ops->read_len < 6) {
dev_err(&client->dev, "%s:lenth is error,len=%d\n", __func__, sensor->ops->read_len);
return -1;
}
memset(buffer, 0, 6);
/* Data bytes from hardware xL, xH, yL, yH, zL, zH */
// while(((value & 0x03)!= 0x03)&&(count++ < 3)){
// value = sensor_read_reg(client, QMI8658_REG_STATUSINT);
// }
*buffer = QMI8658_REG_GYR_XOUT_LSB;
ret = sensor_rx_data(client, buffer, sensor->ops->read_len);
*buffer = sensor->ops->read_reg;
ret = sensor_rx_data(client, buffer, sensor->ops->read_len);
if (ret < 0)
return ret;
x = ((buffer[1] << 8) & 0xFF00) + (buffer[0] & 0xFF);
y = ((buffer[3] << 8) & 0xFF00) + (buffer[2] & 0xFF);
z = ((buffer[5] << 8) & 0xFF00) + (buffer[4] & 0xFF);
//dev_err(&client->dev, "raw_acc=%4d,%4d,%4d\n", (signed short)x, (signed short)y, (signed short)z);
axis.x = (pdata->orientation[0]) * x + (pdata->orientation[1]) * y + (pdata->orientation[2]) * z;
axis.y = (pdata->orientation[3]) * x + (pdata->orientation[4]) * y + (pdata->orientation[5]) * z;
axis.z = (pdata->orientation[6]) * x + (pdata->orientation[7]) * y + (pdata->orientation[8]) * z;
gsensor_report_value(client, &axis);
mutex_lock(&(sensor->data_mutex));
sensor->axis = axis;
mutex_unlock(&(sensor->data_mutex));
//if ((sensor->pdata->irq_enable) && (sensor->ops->int_status_reg >= 0))
// value = sensor_read_reg(client, sensor->ops->int_status_reg);
return ret;
}
struct sensor_operate gsensor_qmi8658_ops = {
.name = "qmi8658_acc",
.type = SENSOR_TYPE_ACCEL,
.id_i2c = ACCEL_ID_QMI8658,
.read_reg = QMI8658_REG_ACC_XOUT_LSB,
.read_len = 6,
.id_reg = QMI8658_REG_WHO_AM_I,
.id_data = SENSOR_CHIP_ID_QMI8658,
.precision = QMI8658_PRECISION,
.ctrl_reg = QMI8658_REG_CTRL7,
.int_status_reg = QMI8658_REG_STATUS0,
.range = {-32768, 32768},
.trig = IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
.active = sensor_active,
.init = sensor_init,
.report = sensor_report_value,
};
/****************operate according to sensor chip:end************/
static int gsensor_qmi8658_probe(struct i2c_client *client,
const struct i2c_device_id *devid)
{
return sensor_register_device(client, NULL, devid, &gsensor_qmi8658_ops);
}
static int gsensor_qmi8658_remove(struct i2c_client *client)
{
return sensor_unregister_device(client, NULL, &gsensor_qmi8658_ops);
}
static const struct i2c_device_id gsensor_qmi8658_id[] = {
{"qmi8658_acc", ACCEL_ID_QMI8658},
{}
};
static struct i2c_driver gsensor_qmi8658_driver = {
.probe = gsensor_qmi8658_probe,
.remove = gsensor_qmi8658_remove,
.shutdown = sensor_shutdown,
.id_table = gsensor_qmi8658_id,
.driver = {
.name = "gsensor_qmi8658",
#ifdef CONFIG_PM
.pm = &sensor_pm_ops,
#endif
},
};
module_i2c_driver(gsensor_qmi8658_driver);
MODULE_AUTHOR("ouenhui <oeh@rock-chips.com");
MODULE_DESCRIPTION("qmi8658_acc 3-Axis accelerometer driver");
MODULE_LICENSE("GPL");
驱动中需要注意的点就是这个结构体中需要的值
struct sensor_operate gsensor_qmi8658_ops = {
.name = "qmi8658_acc",
.type = SENSOR_TYPE_ACCEL, //sensor-dev.h定义,设备树部分也有定义类型
.id_i2c = ACCEL_ID_QMI8658, //前面提到的标号的类型
.read_reg = QMI8658_REG_ACC_XOUT_LSB,//第一个读取的寄存器地址
.read_len = 6, //读取长度
.id_reg = QMI8658_REG_WHO_AM_I,
.id_data = SENSOR_CHIP_ID_QMI8658,
.precision = QMI8658_PRECISION,
.ctrl_reg = QMI8658_REG_CTRL7,
.int_status_reg = QMI8658_REG_STATUS0,
.range = {-32768, 32768},
.trig = IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
.active = sensor_active, //框架中需要给hal做控制
.init = sensor_init, //初始化
.report = sensor_report_value, //我这里使用的模式是轮询
};
开始我认为这个可以做中断触发和轮询上报的两种模式,但是后面发现rk平台不支持中断触发的方式去做,
因为是一个6轴加速器,加有温度传感器,实际是有3个驱动,另两个驱动大同小异,只是init部分是通过accle部分就已经初始化好,后面的就没有再次做初始化,然后就是读取的寄存器部分和注册的名称有一定的差异,还是比较简单的
驱动部分的测试:
我以前没怎么接触rk平台,不知道有对应工具去抓,就自己写啦测试程序来测试,这部分不想了解的可以直接用系统带的(getevent)测试,当时我测试的主要就是看是否能抓数据,模拟100ms轮询去读取数据,后面还会有一个读取时间戳等等的一些功能
test1.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/input.h>
#include <poll.h>
#include <errno.h>
#define GSENSOR_IOCTL_MAGIC 'a'
#define GSENSOR_IOCTL_START _IO(GSENSOR_IOCTL_MAGIC, 0x03)
#define GSENSOR_IOCTL_APP_SET_RATE _IOW(GSENSOR_IOCTL_MAGIC, 0x10, short)
#define L3G4200D_IOCTL_BASE 77
#define L3G4200D_IOCTL_SET_DELAY _IOW(L3G4200D_IOCTL_BASE, 0, int)
#define L3G4200D_IOCTL_SET_ENABLE _IOW(L3G4200D_IOCTL_BASE, 2, int)
#define TEMPERATURE_IOCTL_MAGIC 't'
#define TEMPERATURE_IOCTL_GET_ENABLED _IOR(TEMPERATURE_IOCTL_MAGIC, 1, int *)
#define TEMPERATURE_IOCTL_ENABLE _IOW(TEMPERATURE_IOCTL_MAGIC, 2, int *)
int main()
{
int fd = -1;
int fd2 = -1;
int ret = 0;
int fd3 = -1;
int fd4 = -1;
int fd6 = -1;
struct input_event ev;
struct pollfd fds[1];
nfds_t nfds = 1;
int timeout_ms = 100; // 设置为-1表示无限等待,可以根据需要调整为超时时间
int enable = 1;
fd = open("/dev/mma8452_daemon", O_RDWR);
if (fd == -1)
{
printf("can not open file mma8452_daemon\n");
return -1;
}
ret = ioctl(fd,GSENSOR_IOCTL_START);
if(ret == -1)
{
printf("ioctl1 fail\n");
}
fd2 = open("/dev/gyrosensor", O_RDWR);
if (fd2 == -1)
{
printf("can not open file gyrosensor\n");
return -1;
}
ret = ioctl(fd,GSENSOR_IOCTL_APP_SET_RATE,&timeout_ms);
if(ret == -1)
{
printf("ioctl2.01 fail\n");
}
ret = ioctl(fd2,L3G4200D_IOCTL_SET_DELAY,&timeout_ms);
if(ret == -1)
{
printf("ioctl2.1 fail\n");
}
ret = ioctl(fd2,L3G4200D_IOCTL_SET_ENABLE,&enable);
if(ret == -1)
{
printf("ioctl2.2 fail\n");
}
///
fd6 = open("/dev/temperature", O_RDWR);
if (fd6 == -1)
{
printf("can not open file temperature\n");
return -1;
}
if (ioctl(fd6, TEMPERATURE_IOCTL_GET_ENABLED, &enable) == -1) {
perror("Failed to get temperature enable status");
}
enable = 1;
ret = ioctl(fd6,TEMPERATURE_IOCTL_ENABLE,&enable);
if(ret == -1)
{
printf("ioctl2.2 tmp fail\n");
fprintf(stderr, "Error number: %d\n", errno); // 输出错误号
}
/
close(fd);
close(fd2);
// 打开设备文件,这里以event1为例,请根据实际情况修改
if ((fd3 = open("/dev/input/event1", O_RDONLY)) == -1) {
perror("Failed to open /dev/input/event1");
return EXIT_FAILURE;
}
// 打开设备文件,这里以event1为例,请根据实际情况修改
if ((fd4 = open("/dev/input/event2", O_RDONLY)) == -1) {
perror("Failed to open /dev/input/event2");
return EXIT_FAILURE;
}
if (fcntl(fd3, F_SETFL, fcntl(fd3, F_GETFL, 0) | O_NONBLOCK) == -1) {
perror("Failed to set non-blocking");
close(fd3);
return EXIT_FAILURE;
}
// 初始化pollfd结构
fds[0].fd = fd3;
fds[0].events = POLLIN;
int fd5;
char buffera[256];
off_t offset = 0;
// 打开设备文件,假设它是一个只读权限
fd5 = open("/dev/input/event3", O_RDONLY);
if (fd5 == -1) {
perror("Failed to open temperature device");
return EXIT_FAILURE;
}
// 读取设备文件内容
while (offset < sizeof(buffera)) {
ssize_t bytes_read = read(fd5, buffera + offset, sizeof(buffera) - offset);
if (bytes_read == -1) {
perror("Read error");
break;
} else if (bytes_read == 0) {
// 文件结束
break;
}
offset += bytes_read;
}
// 关闭合设备文件
close(fd5);
close(fd6);
// 确单假设温度值为纯文本且在buffer中,打印出来
buffera[offset] = '\0'; // 确保字符串结尾
printf("Temperature Reading: %s\n", buffera);
while (1) {
// 读取一个输入事件
int ret = poll(fds, nfds, timeout_ms);
//int ret_2 = poll(fds_2, nfds_2, timeout_ms);
if (ret == -1 ) {
perror("Poll error");
break;
} else if (ret == 0 ) {
// 超时
printf("Poll timeout\n");
continue;
}
if (fds[0].revents & POLLIN) {
// 读取事件
//event1
ssize_t bytes_read = read(fd3, &ev, sizeof(struct input_event));
if (bytes_read == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 没有更多数据可读,继续下一轮循环
continue;
} else {
perror("Read error");
break;
}
} else if (bytes_read != sizeof(struct input_event)) {
fprintf(stderr, "Unexpected read size: %zd\n", bytes_read);
continue;
}
printf("Time1: %ld.%06ld, Type: %d, Code: %u, Value: %d\n",
ev.time.tv_sec, ev.time.tv_usec,
ev.type, ev.code, ev.value);
// //event2
// ssize_t bytes_read_2 = read(fd4, &ev, sizeof(struct input_event));
// if (bytes_read_2 == -1) {
// if (errno == EAGAIN || errno == EWOULDBLOCK) {
// // 没有更多数据可读,继续下一轮循环
// continue;
// } else {
// perror("Read error");
// break;
// }
// } else if (bytes_read_2 != sizeof(struct input_event)) {
// fprintf(stderr, "Unexpected read size: %zd\n", bytes_read_2);
// continue;
// }
// printf("Time2: %ld.%06ld, Type: %d, Code: %u, Value: %d\n",
// ev.time.tv_sec, ev.time.tv_usec,
// ev.type, ev.code, ev.value);
}
}
close(fd3);
close(fd4);
return 0;
}
test2.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include <signal.h>
#include <time.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include <errno.h>
#include <string.h>
static int timer_fd = -1; // 定时器文件描述符
static int event_fd1, event_fd2;
// 定时器到期处理函数
void timer_handler(int sig, siginfo_t *si, void *uc) {
// 读取event1和event2的数据
(void)sig; // 告诉编译器这个变量是被特意弃用的
(void)si;
(void)uc;
}
// long long getTimeInMilliseconds() {
// struct timespec spec;
// clock_gettime(CLOCK_REALTIME, &spec);
// return spec.tv_sec * 1000 + spec.tv_nsec / 1000000;
// }
void printCurrentTime() {
time_t rawtime;
struct tm * timeinfo;
// 获取当前时间(自1970年1月1日以来的秒数)
time(&rawtime);
// 将秒数转换为本地时间的tm结构体
timeinfo = localtime(&rawtime);
// 打印格式化的时间字符串
// long long nesc = getTimeInMilliseconds();
printf("当前系统时间: %d-%02d-%02d %02d:%02d:%02d, %lld\n",
timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday,
timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
}
int main() {
struct sigaction sa;
struct itimerspec its;
struct epoll_event ev;
int epoll_fd;
struct input_event ev2;
// 打开设备文件
if ((event_fd1 = open("/dev/input/event1", O_RDONLY)) == -1 ||
(event_fd2 = open("/dev/input/event2", O_RDONLY)) == -1) {
perror("Failed to open device files");
return EXIT_FAILURE;
}
// 创建定时器
timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
if (timer_fd == -1) {
perror("Failed to create timer");
return EXIT_FAILURE;
}
// 设置信号处理函数
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = timer_handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGRTMIN, &sa, NULL) == -1) {
perror("Failed to set signal handler");
return EXIT_FAILURE;
}
// 初始化定时器
its.it_value.tv_sec = 0;
// its.it_value.tv_nsec = 100000000; // 100毫秒,纳秒
// its.it_value.tv_nsec = 10000000; // 10毫秒,纳秒
its.it_interval = its.it_value; // 重复周期与初始值相同
if (timerfd_settime(timer_fd, 0, &its, NULL) == -1) {
perror("Failed to arm timer");
return EXIT_FAILURE;
}
// 设置EPOLL以监控定时器事件
epoll_fd = epoll_create1(0);
if (epoll_fd == -1) {
perror("Failed to create epoll");
return EXIT_FAILURE;
}
ev.events = EPOLLIN;
ev.data.fd = timer_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, timer_fd, &ev) == -1) {
perror("Failed to add timer to epoll");
return EXIT_FAILURE;
}
// 主循环,使用epoll_wait等待事件
while (1) {
int ready = epoll_wait(epoll_fd, &ev, 1, -1);
if (ready == -1 && errno != EINTR) {
perror("epoll_wait");
break;
}
// 定时器触发,处理事件
if (ready > 0 && ev.events & EPOLLIN) {
read(timer_fd, &its, sizeof(its)); // 清除到期事件
printCurrentTime();
ssize_t bytes_read = read(event_fd1, &ev2, sizeof(struct input_event));
if (bytes_read == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 没有更多数据可读,继续下一轮循环
continue;
} else {
perror("Read error");
break;
}
} else if (bytes_read != sizeof(struct input_event)) {
fprintf(stderr, "Unexpected read size: %zd\n", bytes_read);
continue;
}
printf("Time1: %ld.%06ld, Type: %d, Code: %u, Value: %d\n",
ev2.time.tv_sec, ev2.time.tv_usec,
ev2.type, ev2.code, ev2.value);
//event2
read(timer_fd, &its, sizeof(its)); // 清除到期事件
bytes_read = read(event_fd2, &ev2, sizeof(struct input_event));
if (bytes_read == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 没有更多数据可读,继续下一轮循环
continue;
} else {
perror("Read error");
break;
}
} else if (bytes_read != sizeof(struct input_event)) {
fprintf(stderr, "Unexpected read size: %zd\n", bytes_read);
continue;
}
printf("Time2: %ld.%06ld, Type: %d, Code: %u, Value: %d\n",
ev2.time.tv_sec, ev2.time.tv_usec,
ev2.type, ev2.code, ev2.value);
}
}
close(event_fd1);
close(event_fd2);
if (timer_fd != -1) close(timer_fd);
return 0;
}
后面的test2好像打印不出来微秒级别的,用getevent -t +event节点会好点,显示跟内核打印的时间戳精度一致
碰到的难题:
1.开始因为不熟悉框架,在/dev下注册成功啦还是不知道叫啥名,这部分可以看sensor-dev.c,因为是杂项设备的注册规则,这个就遵循啦多种相同功能设备都使用同一个名称,代码太多就不copy太多
static int sensor_misc_device_register(struct sensor_private_data *sensor, int type)
{
int result = 0;
switch (type) {
case SENSOR_TYPE_ANGLE:
if (!sensor->ops->misc_dev) {
sensor->fops.owner = THIS_MODULE;
sensor->fops.unlocked_ioctl = angle_dev_ioctl;
sensor->fops.open = angle_dev_open;
sensor->fops.release = angle_dev_release;
sensor->miscdev.minor = MISC_DYNAMIC_MINOR;
sensor->miscdev.name = "angle";
sensor->miscdev.fops = &sensor->fops;
} else {
memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev));
}
break;
case SENSOR_TYPE_ACCEL:
if (!sensor->ops->misc_dev) {
sensor->fops.owner = THIS_MODULE;
sensor->fops.unlocked_ioctl = gsensor_dev_ioctl;
#ifdef CONFIG_COMPAT
sensor->fops.compat_ioctl = gsensor_dev_ioctl;
#endif
sensor->fops.open = gsensor_dev_open;
sensor->fops.release = gsensor_dev_release;
sensor->miscdev.minor = MISC_DYNAMIC_MINOR;
sensor->miscdev.name = "mma8452_daemon";
sensor->miscdev.fops = &sensor->fops;
} else {
memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev));
}
break;
2.rk平台时间戳到微妙级时会出现一部分问题(本文重点)
在hal层测试过程中,抓到的数据有问题,时间戳会出现波动异常,100ms的轮询延时,会出现10ms左右的波动,
调试中发现,厂商给的驱动有一个重读机制会重新做retry,根据寄存器状态再次读取需要上传的值,保证值的正确性,然而在驱动上传数据到接口时,这个状态寄存器并不稳定,可能1次到10次的概率过这个case,所以我直接删掉啦retry的这个机制,
如果有做过这个的人就可能有疑问,那上传的值是不是就是上次上传的值,导致hal报错呢,这个我再补充一下机制,hal层是100ms采样,然而sensor的采样是可以设定的,驱动中设定的是5ms的采样,删除retry机制也不会影响到寄存器中已经更新的数据,这个部分就解决啦一部分时间戳的问题,
为啥说解决的是一部分你,因为后面测试还是有概率(大概hal采样几十次)出现一次到2次的不稳定现象,这个问题查啦2天,后面锁定在rk平台在做工作队列的唤醒时出现的问题,
假如打印的位置sensor-dev.c
实际测试:
异常100ms是因为rk平台有补偿值可以修改,一个轮询的时间我已经补偿到92-93是属于正常,100ms就是突然出现的一次,这个目前还不知道怎么修改,只能暂时先用着,
做完总结,sensor驱动只是移植还是挺简单的,主要是写测试,了解平台以及调整时间戳有点恶心