文章目录
-
- 1、preface
- 2、IIO架构
- 3、源码分析
-
- 1、源码目录
-
- [1.IIO core](#1.IIO core)
- 2.纷繁复杂的传感器
- 2、数据结构
- 3、关键接口
- 4、IIO框架之saradc
-
- 1)preface
- 2)probe
- 3)fops/匿名文件句柄
- [4)复杂的iio sysfs](#4)复杂的iio sysfs)
- [5)trigger sysfs](#5)trigger sysfs)
- [5、light sensor IIO场景分析](#5、light sensor IIO场景分析)
- 6、rockchip_adc_key场景分析
1、preface
1)资料快车
1)Linux设备驱动之IIO子系统--IIO框架
https://www.cnblogs.com/yongleili717/p/10744252.html
2)Linux下IIO子系统驱动
https://www.cnblogs.com/fuzidage/p/18299137
3)Linux下IIO子系统的使用和源码分析
https://blog.csdn.net/tang_vincent/article/details/147337470
2)概述
1、IIO基本概念
1)(Industrial Input/Output 工业输入/输出),专门处理ADC、DAC以及其它工业传感器(加速度计、陀螺仪、磁力计);
2)与input子系统的关系? 框架上比较相近,应用场景不同,另外可以组合使用!
2、IIO子系统解决什么问题?
1.用户在固定目录找到自己的设备节点,使用Lib定义的接口获取IIO设备的数据,driver提供给IIO预定义的接口;
2.设备种类繁多,操作也各不相同
1)数据类型 - 单字节、buffer;
2)获取方式 - 单次、连续获取等;
3)通信方式 - I2C\SPI等;
IIO子系统都要实现它们!
3.hal层实现读写算法逻辑,driver提供功能接口
总的来说三点:
1)IIO子系统向用户层提供统一的接口:IIO提供了一个标准化的用户API(/sys/bus/iio/devices/*) 和 统一的数据结构(类似parcel);
2)IIO内核能够支持多种设备类型 (接口和数据结构 能 覆盖常用的传感器外设);
3)IIO子系统支持事件和触发机制 (使用对应的API),比如当某个传感器的值超过阈值时触发中断 (支持硬件和软件触发);
2、IIO架构
1)架构1
《Linux Device Drivers Development》--John Madieu

2)架构2

1、重点理解IIO Trigger/IIO Buffer/IIO Event,其它都是通用的Linux机制;
2、IIO device driver一般使用其他子系统 + 调用iio core接口实现;
3)buffer和trigger机制
IIO 缓冲区架构:
用户空间 内核空间
│ │
│ read() / char device │
│◄────────────────────────►│
│ │
│ ┌─────────────┐ │
│ │ /dev/iio:deviceN │
│ │ (字符设备) │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ iio_buffer │ │
│ │ (环形缓冲区) │ │
│ │ │ │
│ │ ┌───┐┌───┐┌───┐ │
│ │ │scan│scan│scan│...│ ← 扫描元素
│ │ └───┘└───┘└───┘ │
│ │ │ │
│ │ 触发源: 中断/timer │
│ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 设备驱动 │ │
│ │ (accel/adc/...)│ │
│ └─────────────┘ │
│ │
触发模式:
├─ 软件触发:用户空间 write /sys/.../trigger_now
├─ 硬件触发:外部中断、定时器、其他传感器
└─ 连续模式:定时器周期性采样
4)用户空间接口
1、以mpu6050为例
sysfs 标准路径:
/sys/bus/iio/devices/iio:deviceN/
通用属性:
├─ name # 设备名称
├─ dev # 主次设备号
├─ sampling_frequency # 采样频率
├─ buffer/ # 缓冲区控制
│ ├─ enable # 使能缓冲区
│ ├─ length # 缓冲区长度
│ └─ watermark # 水印级别
├─ scan_elements/ # 扫描元素配置
│ ├─ in_voltage0_en # 使能通道0
│ ├─ in_voltage1_en # 使能通道1
│ ├─ in_voltage0_type # 数据类型
│ └─ in_voltage0_index # 扫描索引
└─ trigger/ # 触发器
├─ current_trigger # 当前触发器
└─ ...
通道数据读取:
/sys/bus/iio/devices/iio:device0/
├─ in_accel_x_raw # X轴原始数据 (accel)
├─ in_accel_y_raw # Y轴原始数据
├─ in_accel_z_raw # Z轴原始数据
├─ in_accel_scale # 缩放因子 (g/LSB)
├─ in_anglvel_x_raw # X轴角速度 (gyro)
├─ in_magn_x_raw # X轴磁场 (magnetometer)
├─ in_temp_raw # 温度原始值
├─ in_voltage0_raw # ADC 通道0原始值
└─ ...
# 1. 查找 IIO 设备
ls /sys/bus/iio/devices/
# iio:device0 iio:device1 iio_sysfs_trigger
# 2. 查看设备信息
cat /sys/bus/iio/devices/iio:device0/name
# mpu6050
# 3. 读取加速度数据
cat /sys/bus/iio/devices/iio:device0/in_accel_x_raw
cat /sys/bus/iio/devices/iio:device0/in_accel_y_raw
cat /sys/bus/iio/devices/iio:device0/in_accel_z_raw
# 4. 读取缩放因子
cat /sys/bus/iio/devices/iio:device0/in_accel_scale
# 0.000598 (约 0.000598 * 9.8 = 0.00586 m/s²/LSB)
# 5. 计算实际值
# 实际加速度(g) = raw * scale
# 实际加速度(m/s²) = raw * scale * 9.8
# 6. 缓冲区模式 (高速采集)
echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_x_en
echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_y_en
echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_z_en
echo 100 > /sys/bus/iio/devices/iio:device0/buffer/length
echo 1 > /sys/bus/iio/devices/iio:device0/buffer/enable
# 7. 读取缓冲数据
cat /dev/iio:device0 | xxd # 二进制数据
3、源码分析
1、源码目录
1.IIO core
1.源码
1)
/kernel/drivers/iio/*
/kernel/drivers/iio/buffer/* -- buffer缓冲区框架
/kernel/drivers/iio/trigger/* -- 触发器
/kernel/drivers/iio/industrialio-*
/kernel/drivers/iio/industrialio-core.c --核心层
2)
/kernel/drivers/iio/common/* --常见厂商sensors驱动模板库(直接使用或二次简单改造) - 比如st_sensors
ST 通用库方式(代码复用)
common/st_sensors/ (共享库)
│ ├─ st_sensors_i2c.c ← I2C 读写封装
│ ├─ st_sensors_spi.c ← SPI 读写封装
│ ├─ st_sensors_core.c ← 寄存器操作
│ │ ├─ 设备识别 (WHO_AM_I)
│ │ ├─ 量程配置 (FS)
│ │ ├─ 输出速率 (ODR)
│ │ ├─ 数据读取
│ │ └─ 电源管理
│ ├─ st_sensors_trigger.c ← 中断触发器
│ └─ st_sensors_buffer.c ← 批量采集缓冲
3)
/kernel/drivers/iio/"传感器" -- 各式各样的传感器
2.头文件
/kernel/include/linux/iio/*
2.纷繁复杂的传感器
| 目录 | 全称 | 用途 | 典型设备 |
|---|---|---|---|
| accel | Accelerometer | 加速度计 | MPU6050、BMI160、LIS3DH |
| adc | Analog-to-Digital Converter | 模数转换器 | ADS1015、SAR-ADC (RK3568) |
| afe | Analog Front End | 模拟前端 | 信号调理电路 |
| amplifiers | Amplifiers | 放大器 | 仪表放大器、可编程增益 |
| buffer | Buffer | 缓冲区框架 | IIO 数据缓冲核心代码 |
| chemical | Chemical Sensors | 化学传感器 | 气体传感器、PH 传感器 |
| common | Common Code | 通用代码 | 所有 IIO 驱动共享的代码 |
| counter | Counter | 计数器 | 脉冲计数、频率计数 |
| dac | Digital-to-Analog Converter | 数模转换器 | DAC0832、PWM-DAC |
| dummy | Dummy Driver | 虚拟/测试驱动 | 用于测试框架,无真实硬件 |
| frequency | Frequency | 频率相关 | 时钟、频率计 |
| gyro | Gyroscope | 陀螺仪 | MPU6050、BMI160 |
| health | Health Sensors | 健康传感器 | 心率、血氧、生物传感器 |
| humidity | Humidity | 湿度传感器 | DHT11、SHT30、BME280 |
| imu | Inertial Measurement Unit | 惯性测量单元 | 9轴/10轴传感器(accel+gyro+mag) |
| light | Light | 光线传感器 | BH1750、AP3216C、TSL2561 |
| magnetometer | Magnetometer | 磁力计 | HMC5883L、AK09911、QMC5883 |
| multiplexer | Multiplexer | 多路复用器 | 模拟开关、通道切换 |
| orientation | Orientation | 方向传感器 | 电子罗盘、倾角传感器 |
| potentiometer | Potentiometer | 电位器/数字电位器 | AD5272、数字可调电阻 |
| potentiostat | Potentiostat | 恒电位仪 | 电化学分析仪器 |
| pressure | Pressure | 压力传感器 | BMP280、MS5611、气压计 |
| proximity | Proximity | 接近传感器 | AP3216C、红外接近检测 |
| resolver | Resolver | 旋转变压器 | 电机角度传感器(工业) |
| temperature | Temperature | 温度传感器 | LM75、TMP102、NTC 热敏电阻 |
2、数据结构
1.ii0_dev - iio设备(基类)
/kernel/include/linux/iio/iio.h
struct iio_dev {
int modes; //Device operating modes
struct iio_event_interface *event_interface; //事件接口
struct iio_buffer *buffer; //iio缓冲区
struct iio_head buffer_list;
int scan_bytes;
struct iio_triger *trig; //iio触发器
struct iio_poll_func *pollfunc; //事件查询
struct iio_poll_func *pollfunc_event;
struct iio_chan_spec const *channels; //传感器通道
int num_channels;
struct list_head channel_attr_list;
struct attribute_group chan_attr_group;
struct iio_info *info; //constant information about device - 属性group和读写接口
struct iio_buffer_setup_ops *setup_ops;
struct cdev chrdev;
struct dentry *debugfs_entry;
};
1) 设备收集数据方式
/kernel/include/linux/iio/iio.h
/* Device operating modes */
#define INDIO_DIRECT_MODE 0x01 //表示设备提供sysfs,用户手动触发收集数据(单次采集)
#define INDIO_BUFFER_TRIGGERED 0x02 //表示设备采用自动持续收集数据,并填充到buffer
#define INDIO_BUFFER_SOFTWARE 0x04 //采用软件FIFO,buffer方式管理采样,要连续数据流但无硬件FIFO场合使用
#define INDIO_BUFFER_HARDWARE 0x08 //设备自身具有FIFO,以硬件buffer方式管理采样
#define INDIO_EVENT_TRIGGERED 0x10 //IIO事件机制(阈值越界、状态变化等),上报"事件"而不是持续样本流
#define INDIO_HARDWARE_TRIGGERED 0x20 //硬件信号直接触发采样,常与INDIO_BUFFER_TRIGGERED联用,时序要求高场合使用
2.iio_event_interface -- chrdev interface for an event line
/kernel/drivers/iio/industrialio-event.c
struct iio_event_interface {
wait_queue_head_t wait; //等待队列
DECLARE_KFIFO(det_events, struct iio_event_data, 16); //声明一个fifo结构存放iio event数据
struct list_head dev_attr_list;
struct attribute_group group;
};
3.iio_buffer - 缓冲区
/kernel/include/linux/iio/buffer_impl.h
struct iio_buffer {
unsigned int length; //缓存区数据单元数量
size_t bytes_per_datum; //单个数据单元大小
struct iio_buffer_access_funcs *access; //读写函数
};
4.iio_buffer_access_funcs
/kernel/include/linux/iio/buffer_impl.h
struct iio_buffer_access_funcs {
int (*store_to)(struct iio_buffer *buffer, const void *data);
int (*read_first_n)(struct iio_buffer *buffer, size_t n, char __user *buf);
}
5.iio_trigger - 触发器
/kernel/include/linux/iio/trigger.h
struct trigger {
struct iio_tigger_Ops *ops;
char *name;
struct irq_chip subirq_chip; //中断
int subirq_base;
struct iio_subirq subirqs[2];
unsigned long pool[]
};
6.iio_info - iio属性及操作集
/kernel/include/linux/iio/iio.h
struct iio_info {
struct attribute_group *event_attrs;
struct attribute_group *attrs;
int (*read_raw)(struct iio_dev, struct iio_chan_spec, int *val, int *val2,.);
int (*read_raw_mulit)();
int (*read_avail)();
int (*write_raw)();
int (*write_raw_get_fmt)();
int (*read_event_config)(struct iio_dev,struct iio_chan_spec, enum iio_event_type,enum iio_event_direction);
int (*write_event_config)();
int (*read_event_value)();
int (*write_event_value)();
};
7.iio_buffer_setup_ops
/kernel/include/linux/iio/iio.h
struct iio_buffer_setup_ops {
int (*preenable)(struct iio_dev *);
}
8.iio_dev_opaque
/kernel/include/linux/iio/iio-opaque.h
struct iio_dev_opaque {
struct iio_dev indio_dev;
int id;
struct module *driver_module;
struct mutex info_exist_lock;
struct iio_event_interface *event_interface;
struct list_head buffer_list;
struct list_head channel_attr_list;
struct attribute_group chan_attr_group;
struct list_head ioctl_handlers;
struct cdev chrdev;
}
3、关键接口
1.iio_push_to_buffers_with_timestamp - int数据存放在buffer中
/kernel/include/linux/iio/buffer.h
iio_push_to_buffers_with_timestamp(str5uct iio_dev *indio_dev, void *data, int64_t timestamp)
/android/common/common14-5.15/common/drivers/iio/industrialio-buffer.c
--iio_push_to_buffers()
----iio_push_to_buffer()
------buffer->access->store_to(buffer, dataout);
2.devm_iio_kfifo_allocate - 分配buffer
/kernel/include/linux/iio/buffer/kfifo_buf.c
devm_iio_kfifo_allocate(struct device *dev)
--devres_alloc(devm_iio_kfifo_release, sizeof(*ptr), GFP_KERNEL);
--iio_kfifo_allocate();
----kzalloc(sizeof(struct iio_kfifo), GFP_KERNEL);
3.iio_device_attach_buffer
/kernel/include/linux/iio/industrialio-buffer.c
iio_device_attach_buffer(struct iio_dev *indio_dev, struct iio_buffer *buffer){
new = krealloc(old, sizeof(*new) * cnt, GFP_KERNEL);
buffer = iio_buffer_get(buffer);
iio_dev_opaque->attached_buffers[cnt - 1] = buffer;
iio_dev_opaque->attached_buffers_cnt = cnt;
}
4、IIO框架之saradc
1)preface
1、saradc调用IIO core的接口进行初始化和注册,通过简单的rockchip saradc来看IIO子系统
2、重点框架
1)IIO框架之register
2)IIO框架之fops/匿名文件句柄
3)IIO框架之event
4)IIO框架之复杂的sysfs组织
5)IIO框架之triger
2)probe
1.IIO probe
/kernel/drivers/iio/adc/rockchip_saradc.c
rockchip_saradc_probe(struct platform_device *pdev)
1) 定义iio设备、传感器设备数据结构
--struct rockchip_saradc *info
--struct iio_dev *indio_dev
--indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
--info = iio_priv(indio_dev);
2)匹配设备树并 获取设备资源(ADC平台定义)
match = of_match_device(rockchip_saradc_match, &pdev->dev);
info->data = match->data;
info->regs = devm_ioremap_resource(&pdev->dev, mem);
2) 申请中断-ADC/DAC转换完成后硬件触发中断
--devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr, 0, dev_name(&pdev->dev),info);
3) 构造indio
--plaform_set_drvdata(pdev, indio_dev);
--indio_dev->name = dev_name(&pdev->dev);
--indio_dev->info = &rockchip_saradc_iio_info; //属性和操作集
--indio_dev->modes = INDIO_DIRECT_MODE; // 设置工作模式为直接模式
--indio_dev->channels = info->data->channels; //ADC通道
--indio_dev->num_channels = info->data->num_channels;
4) 注册iio
--devm_iio_device_register(&pdev->dev, indio_dev);
2.
iio读实现
static const struct iio_info rockchip_saradc_iio_info = {
.read_raw = rockchip_saradc_read_raw,
};
iio通道定义 - ADC的详细定义
struct iio_chan_spec rockchip_saradc_iio_channels[] = {
ADC_CHANNEL(0, "adc0"),
ADC_CHANNEL(1, "adc1"),
ADC_CHANNEL(2, "adc2"),
};
3.devm_iio_device_register - 根据设备驱动中给的信息进行构造sysfs、event、trigger等等
/kernel/drivers/iio/industrialio-core.c
__devm_iio_device_register((dev), (indio_dev), THIS_MODULE)
--devres_alloc(struct iio_dev)
--__iio_device_register(indio_dev, this_mod);
----iio_device_register_debugfs(indio_dev); //创建debugfs
----iio_device_register_sysfs(indio_dev); //根据iio info创建/sys/bus/iio/devices/iio:deviceN/*各路sysfs属性
----iio_device_register_eventset(indio_dev); //IIO事件,常见事件包括阈值事件、数据就绪事件、状态变化事件等等
//IIO 子系统利用 FIFO 队列缓存检测到的事件数据,等待队列实现事件通知机制以唤醒监听者,通过链表动态维护事件相关属性并通过 sysfs 暴露给用户空间以便配置和监控
------INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list);
------iio_setup_ev_int(struct iio_event_interface); //初始化等待队列头
----iio_device_register_trigger_consumer(indio_dev); //触发器,函数注册触发消费者,支持设备响应外部触发信号
----indio_dev->setup_ops = &noop_ring_setup_ops;//提供默认的缓冲区操作函数
----cdev_init(&indio_dev->chrdev, &iio_buffer_fileops); //创建字符设备
----cdev_device_add(&indio_dev->chrdev, &indio_dev->dev);
--devres_add(dev, ptr);
3)fops/匿名文件句柄
1.匿名文件(anon_inode_getfd)
1)匿名文件描述符它是一种特殊的文件描述符,它并不与实际的文件系统路径或设备节点关联,而是通过内核动态创建的一种虚拟文件。匿名的文件描述符 fd 也有着他自己的文件操作集,所以我们可以通过 ioctl 创建虚拟文件描述符,从而为用户提供额外的系统调用接口,与内核中的某些功能或数据进行交互,而无需依赖传统的文件系统;
2)总的来说,匿名的文件句柄,实现了两级ioctl,并且不会污染文件系统的效果;
2.顶层file ops
struct file_operations iio_buffer_fileops = {
.read = iio_buffer_read_first_n_outer_addr, //读,在probe时挂接进来
.open = iio_chrdev_open,
.compat_ioctl = iio_ctrl,
};
3.iio_buffer_read_frist_n_outer_addr
/kernel/drivers/iio/industrialio-buffer.c
iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, size_t n, loff_t *f_ps)
--DEFINE_WAIT_FUNC(wait, woken_wake_function); //定义一个等待队列的等待函数,用于处理阻塞读取
--add_wait_queue(&rb->pollq, &wait);
--iio_buffer_ready(); 等待数据就绪
--wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
--rb->access->read_first_n(rb, n, buf); //读取数据放入Buffer
3.iio_ctrl
/kernel/drivers/iio/industrialio-core.c
iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
/kernel/drivers/iio/industrialio-event.c
--iio_event_getfs(indio_dev);
----struct iio_event_interface *ev_int = indio_dev->event_interface;
----anon_inode_getfd("iio:event", &iio_event_chrdev_fileops, indio_dev,..)
--copy_to_user()
4.匿名file ops
static const struct file_operations iio_event_chrdev_fileops = {
.read = iio_event_chrdev_read,
.poll = iio_event_poll,
};
1) iio_event_chrdev_read() -阻塞IO
--do while循环
----kfifo_is_empty(iio_event_interface->det_events);
----wait_event_interruptible(iio_event_interface->wait,...);
----kfifo_to_user();
2) iio_event_poll() - 非阻塞IO
/kernel/drivers/iio/industrialio-event.c
iio_event_poll(struct file,strcut poll_table_struct)
--poll_wait(file, &iio_event_interface->wait, struct poll_table_struct)
--kfifo_is_empty(&iio_event_interface->det_events)
4)复杂的iio sysfs
1.面对繁杂的传感器设备,sysfs要管理很多属性文件,因此iio sysfs对属性文件进行规范约束,以方便上层统一接口
2.iio_device_register_sysfs - 填充sysfs数据结构内容
/kernel/drivers/iio/industrialio-core.c
iio_device_register_sysfs(struct iio_dev *indio_dev)
--iio_device_add_channel_sysfs(indio_dev, chan); //遍历所有通道并将sysfs属性添加到系统中
按照iio_shared_by属性的共享类型 依次填充info, info会在probe时构造传入
----iio_device_add_info_mask_type(indio_dev, chan, IIO_SEPARATE, &chan->info_mask_separate);
------__iio_add_chan_devattr(iio_chan_info_postfix[i], //规范化的属性 信息填充
chan,
&iio_read_channel_info,
&iio_write_channel_info,
i,
shared_by,
&indio_dev->dev,
&indio_dev->channel_attr_list);
----iio_device_add_info_mask_type_avail(indio_dev, chan,IIO_SEPARATE, &chan->info_mask_separate_available);
1)iio 属性共享类型
/kernel/include/linux/iio/iio.h
enum iio_shared_by {
IIO_SEPARATE,//独立属性,仅属于某个特定通道。
IIO_SHARED_BY_TYPE, //按类型共享,相同类型的通道共享属性
IIO_SHARED_BY_DIR, //按方向(in 或 out)共享,相同方向的通道共享属性
IIO_SHARED_BY_ALL //全局共享,整个设备的所有通道共享属性
};
2)规范命名
1、后缀
static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_RAW] = "raw",
[IIO_CHAN_INFO_PROCESSED] = "input",
[IIO_CHAN_INFO_SCALE] = "scale",
[IIO_CHAN_INFO_OFFSET] = "offset",
...
}
2、type
static const char * const iio_chan_type_name_spec[] = {
[IIO_VOLTAGE] = "voltage",
[IIO_CURRENT] = "current",
[IIO_POWER] = "power",
[IIO_ACCEL] = "accel",
[IIO_ANGL_VEL] = "anglvel",
...
}
3、修饰符
static const char * const iio_modifier_names[] = {
[IIO_MOD_X] = "x",
[IIO_MOD_Y] = "y",
[IIO_MOD_Z] = "z",
3. cdev_device_add - 实施创建
cdev_device_add()
--cdev_add(cdev, dev->devt, 1)
--device_add(dev); // 注册设备对象 dev,使其在 sysfs 中可见,并创建 /dev 设备节点
----device_add_attrs(struct device *dev) //对属性文件进行了创建
5)trigger sysfs
1.概况
1)trigger暴露给用户空间接口
2)config需要配置SYSFS_trigger
3)源码
/kernel/drivers/iio/trigger/iio-trig-sysfs.c
2.iio_sysfs_trig_init
/kernel/drivers/iio/trigger/iio-trig-sysfs.c
__init iio_sysfs_trig_init()
--device_initialize(&iio_sysfs_trig_dev);
--dev_set_name(&iio_sysfs_trig_dev, "iio_sysfs_trigger");
--device_add(&iio_sysfs_trig_dev);
3.iio_sysfs_trigger_probe
/kernel/drivers/iio/trigger/iio-trig-sysfs.c
iio_sysfs_trigger_probe()
--iio_trigger_alloc("sysfstrig%d", id); //id name
//构造tirg
--t->trig->dev.groups = iio_sysfs_trigger_attr_groups;
--t->trig->ops = &iio_sysfs_trigger_ops;
--t->trig->dev.parent = &iio_sysfs_trig_dev;
//注册
--iio_trigger_register(t->trig);
4.用户空间接口
static struct attribute *iio_sysfs_trig_attrs[] = {
&dev_attr_add_trigger.attr, //对应iio_sysfs_trig_add
&dev_attr_remove_trigger.attr, //对应iio_sysfs_trig_remove
NULL,
};
5、light sensor IIO场景分析
1.IIC设备
/kernel/drivers/iio/light/tsl4531.c
static struct i2c_driver tsl4531_driver = {
.probe = tsl4531_probe,
}
2.tsl4531_probe
tsl4531_probe()
//分配IIO
--devm_iio_device_alloc(&client->dev, sizeof(*data));
--data = iio_priv(indio_dev);
--i2c_set_clientdata(client, indio_dev);
//配置光感传感器
--i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL,
TSL4531_MODE_NORMAL);
--i2c_smbus_write_byte_data(data->client, TSL4531_CONFIG,
TSL4531_TCNTRL_400MS);
//构造iio设备
--indio_dev->dev.parent = &client->dev;
indio_dev->info = &tsl4531_info;
indio_dev->channels = tsl4531_channels;
indio_dev->num_channels = ARRAY_SIZE(tsl4531_channels);
indio_dev->name = TSL4531_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
--iio_device_register(indio_dev);
3.iio info构造
/kernel/drivers/iio/light/tsl4531.c
static const struct iio_info tsl4531_info = {
.read_raw = tsl4531_read_raw,
.write_raw = tsl4531_write_raw,
.attrs = &tsl4531_attribute_group,
};
6、rockchip_adc_key场景分析
1.设备树
/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi
adc_keys: adc-keys {
compatible = "adc-keys";
io-channels = <&saradc 0>;
io-channel-names = "buttons";
keyup-threshold-microvolt = <1800000>;
poll-interval = <100>;
vol-up-key {
label = "volume up";
linux,code = <KEY_VOLUMEUP>;
press-threshold-microvolt = <1750>;
};
2.platform平台设备
/kernel/drivers/input/keyboard/adc-keys.c
platform_driver __refdata adc_keys_driver{}
3.adc_keys_probe
--struct adc_keys_state *st;
--enum iio_chan_type type; //adc类型(电压)
--st->channel = devm_iio_channel_get(dev, "buttons"); //获取设备树信息adc通道信息
--iio_get_channel_type(st->channel &type);
--struct input_polled_dev->poll = adc_keys_poll; //按键读取方法
1) adc_keys_state
struct adc_keys_state {
struct iio_channel *channel;
u32 num_keys;
u32 last_key;
u32 keyup_voltage;
u32 voltage;
u32 keycode;
};
2) adc_keys_poll - 读取接口
adc_keys_poll
/kernel/drivers/iio/inkern.c
--iio_read_channel_processed(st->channel, &value);
----iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
------chan->indio_dev->info->read_raw(chan->indio_dev,chan->channel, val, val2, info);
--input_report_key(dev->input, st->last_key, 0);
--input_sync(dev->input);