【推荐阅读】

一文剖析Linux内核中内存管理

分析linux启动内核源码

关于如何快速学好,学懂Linux内核。内含学习路线

工业场合里面也有大量的模拟量和数字量之间的转换,也就是我们常说的 ADC 和 DAC。而且随着手机、物联网、工业物联网和可穿戴设备的爆发,传感器的需求只持续增强。比如手机或者手环里面的加速度计、光传感器、陀螺仪、气压计、磁力计等,这些传感器本质上都是ADC,大家注意查看这些传感器的手册,会发现他们内部都会有个 ADC,传感器对外提供 IIC或者 SPI 接口,SOC 可以通过 IIC 或者 SPI 接口来获取到传感器内部的 ADC 数值,从而得到想要测量的结果。Linux 内核为了管理这些日益增多的 ADC 类传感器,特地推出了 IIO 子系统,我们学习如何使用 IIO 子系统来编写 ADC 类传感器驱动。

1、IIO 子系统简介

IIO 全称是 Industrial I/O,翻译过来就是工业 I/O大家不要看到“工业”两个字就觉得 IIO 是只用于工业领域的。大家一般在搜索 IIO 子系统的时候,会发现大多数讲的都是 ADC,这是因为 IIO 就是为 ADC 类传感器准备的,当然了 DAC 也是可以的。大家常用的陀螺仪、加速度计、电压/电流测量芯片、光照传感器、压力传感器等内部都是有个 ADC,内部 ADC 将原始的模拟数据转换为数字量,然后通过其他的通信接口,比如 IIC、SPI 等传输给 SOC。

因此,当你使用的传感器本质是 ADC 或 DAC 器件的时候,可以优先考虑使用 IIO 驱动框架。

1、iio_dev 结构体

IIO 子系统使用结构体 iio_dev 来描述一个具体 IIO 设备,此设备结构体定义在include/linux/iio/iio.h 文件中

2、iio_dev 申请与释放

在使用之前要先申请 iio_dev,申请函数为 iio_device_alloc,函数原型如下:

struct iio_dev *iio_device_alloc(int sizeof_priv)

sizeof_priv:私有数据内存空间大小,一般我们会将自己定义的设备结构体变量作为 iio_dev 的私有数据,这样可以直接通过 iio_device_alloc 函数同时完成 iio_dev 和设备结构体变量的内存申请。申请成功以后使用 iio_priv 函数来得到自定义的设备结构体变量首地址。

返回值:如果申请成功就返回 iio_dev 首地址,如果失败就返回 NULL。

3、iio_dev 注册与注销

前面分配好 iio_dev 以后就要初始化各种成员变量,初始化完成以后就需要将 iio_dev 注册 到内核中,需要用到 iio_device_register 函数

4、iio_info

iio_dev 有个成员变量:info,为 iio_info 结构体指针变量,这个是我们在编写 IIO 驱动的时候需要着重去实现的,因为用户空间对设备的具体操作最终都会反映到 iio_info 里面。iio_info结构体定义在 include/linux/iio/iio.h 中

5、iio_chan_spec

IIO 的核心就是通道,一个传感器可能有多路数据,比如一个 ADC 芯片支持 8 路采集,那么这个 ADC 就有 8 个通道。Linux 内核使用 iio_chan_spec 结构体来描述通道,定义在 include/linux/iio/iio.h 文件中。

2、IIO 驱动框架创建

分析 IIO 子系统的时候大家应该看出了,IIO 框架主要用于 ADC 类的传感器,比如陀螺仪、加速度计、磁力计、光强度计等,这些传感器基本都是 IIC 或者 SPI 接口的。因此 IIO 驱动的基础框架就是 IIC 或者 SPI,我们可以在 IIC 或 SPI 驱动里面在加上 regmap。当然了,有些 SOC 内部的 ADC 也会使用 IIO 框架,那么这个时候驱动的基础框架就是 platfrom。

IIO 设备的申请、初始化以及注册在 probe 函数中完成,在注销驱动的时候还需要在 remove 函数中注销掉 IIO 设备、释放掉申请的一些内存。

以 SPI 接口为例,demo 如下

/* 自定义设备结构体 */
struct xxx_dev { struct spi_device *spi; /* spi 设备 */struct regmap *regmap; /* regmap */struct regmap_config regmap_config;struct mutex lock;
};/*
* 通道数组
*/
static const struct iio_chan_spec xxx_channels[] = {};/*
* @description : 读函数,当读取 sysfs 中的文件的时候最终此函数会执行,
* :此函数里面会从传感器里面读取各种数据,然后上传给应用。
* @param - indio_dev : IIO 设备
* @param - chan : 通道
* @param - val : 读取的值,如果是小数值的话,val 是整数部分。
* @param - val2 : 读取的值,如果是小数值的话,val2 是小数部分。
* @param - mask : 掩码。
* @return : 0,成功;其他值,错误
*/
static int xxx_read_raw(struct iio_dev *indio_dev,struct iio_chan_spec const *chan,int *val, int *val2, long mask)
{return 0;
} /*
* @description : 写函数,当向 sysfs 中的文件写数据的时候最终此函数
* :会执行,一般在此函数里面设置传感器,比如量程等。
* @param - indio_dev : IIO 设备
* @param - chan : 通道
* @param - val : 应用程序写入值,如果是小数的话,val 是整数部分。
* @param - val2 : 应用程序写入值,如果是小数的话,val2 是小数部分。
* @return : 0,成功;其他值,错误
*/
static int xxx_write_raw(struct iio_dev *indio_dev,struct iio_chan_spec const *chan,int val, int val2, long mask)
{return 0;
}/*
* @description : 用户空间写数据格式,比如我们在用户空间操作 sysfs 来设
* :置传感器的分辨率,如果分辨率带小数,那么这个小数传递到
* : 内核空间应该扩大多少倍,此函数就是用来设置这个的。
* @param - indio_dev : iio_dev
* @param - chan : 通道
* @param - mask : 掩码
* @return : 0,成功;其他值,错误
*/
static int xxx_write_raw_get_fmt(struct iio_dev *indio_dev,struct iio_chan_spec const *chan, long mask)
{return 0;
}/*
* iio_info 结构体变量
*/
static const struct iio_info xxx_info = {.read_raw = xxx_read_raw,.write_raw = xxx_write_raw,.write_raw_get_fmt = &xxx_write_raw_get_fmt,
};/*
* @description : spi 驱动的 probe 函数,当驱动与
* 设备匹配以后此函数就会执行
* @param - spi : spi 设备
*
*/
static int xxx_probe(struct spi_device *spi)
{int ret;struct xxx_dev *data;struct iio_dev *indio_dev;/* 1、申请 iio_dev 内存 */indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));if (!indio_dev)return -ENOMEM;/* 2、获取 xxx_dev 结构体地址 */data = iio_priv(indio_dev);data->spi = spi;spi_set_drvdata(spi, indio_dev);mutex_init(&data->lock);/* 3、初始化 iio_dev 成员变量 */indio_dev->dev.parent = &spi->dev;indio_dev->info = &xxx_info;indio_dev->name = "xxx";indio_dev->modes = INDIO_DIRECT_MODE; /* 直接模式 /indio_dev->channels = xxx_channels;indio_dev->num_channels = ARRAY_SIZE(xxx_channels);iio_device_register(indio_dev);/* 4、regmap 相关设置 *//* 5、SPI 相关设置*//* 6、芯片初始化 */return 0;}/*
* @description : spi 驱动的 remove 函数,移除 spi 驱动的时候此函数会执行
* @param - spi : spi 设备
* @return : 0,成功;其他负值,失败
*/
static int xxx_remove(struct spi_device *spi)
{struct iio_dev *indio_dev = spi_get_drvdata(spi);struct xxx_dev *data;data = iio_priv(indio_dev); ;/* 1、其他资源的注销以及释放 *//* 2、注销 IIO */iio_device_unregister(indio_dev);return 0;
}

3、使能内核 IIO 相关配置

Linux 内核默认使能了 IIO 子系统,但是有一些 IIO 模块没有选择上,这样会导致我们编译 驱动的时候会提示某些 API 函数不存在,需要使能的项目如下:

-> Device Drivers -> Industrial I/O support (IIO [=y])-> [*]Enable buffer support within IIO //选中-> <*>Industrial I/O buffering based on kfifo //选中

IIO 驱动框架提供了 sysfs 接口,因此加载成功以后我们可以在用户空间访问对应的 sysfs 目录项,进入目录“/sys/bus/iio/devices/”目录里面,此目录下都是 IIO 框架设备。


一文带你深入了解Linux IIO 子系统相关推荐

  1. 【转】 linux iio子系统

    原文网址:http://blog.csdn.net/tsy20100200/article/details/47101661 最近由于工作的需要,接触了Linux iio子系统,对于这个目录其实以前是 ...

  2. Linux的iio数据流程,linux iio子系统

    转自http://blog.csdn.net/tsy20100200/article/details/47101661 最近由于工作的需要,接触了Linux iio子系统,对于这个目录其实以前是很少接 ...

  3. LINUX IIO子系统分析之一 IIO子系统概述

    从本章开始,我们进行IIO子系统专栏的分析文档,本次IIO子系统专栏分析文档大概包含如下几章: 一. IIO子系统概述 二.IIO子系统相关数据结构分析 三.iio trigger 介绍 四.iio ...

  4. LINUX IIO子系统分析之五IIO BUFFER子模块实现分析

    上一章我们介绍了iio子系统中的iio event模块,本章我们将介绍iio buffer模块,iio buffer主要用于连续数据采集与缓存功能.IIO buffer模块借助IIO DEVICE字符 ...

  5. LINUX IIO子系统分析之二 IIO子系统相关数据结构分析

    上一章我们简要说明了IIO子系统的架构,本章我们通过数据结构的定义,分析IIO子系统的设计实现,本章的主要内容如下: 一.IIO子系统各数据结构说明 二.数据结构间的关联说明 一.IIO子系统各数据结 ...

  6. LINUX IIO子系统分析之七 虚拟iio device驱动实现

    前面几章我们基本完成了IIO子系统的所有内容,而该章即为本专栏的结束篇,主要用来实现一个虚拟的IIO DEVICE DRIVER,本章的内容主要包括如下几部分: 一. 虚拟IIO DEVICE的说明 ...

  7. LINUX IIO子系统分析之四 IIO EVENT介绍

    上一章我们介绍了iio子系统中的iio trigger模块,本章我们将介绍iio event模块,iio event主要用于阈值监测.自由落体监测等监测功能.因为IIO EVENT涉及IIO DEVI ...

  8. LINUX IIO子系统分析之六 iio device的驱动开发流程说明

    前面五章我们基本上把IIO 子系统的内部设计实现均作了说明,本章我们将说明iio device的驱动开发流程,本章的主要内容大致安排如下: 一.IIO子系统的关键技术点总结 二.IIO DEVICE的 ...

  9. linux IIO子系统使用说明

    新的内核将ADC/DAC/G_sensor这样的设备统一成IIO子系统,用户层通过访问IIO的接口来实现如ADC的触发.采样等操作. 下面给出IIO接口用户层的接口使用实例(以ADC的采样为例) 1. ...

最新文章

  1. 职中计算机应用教学方法,职中《计算机应用基础》教学心得体会
  2. oralce中级OCP考试时间和题量以及通过率
  3. 物理光学8 多波束干涉
  4. 成功解决NameError: name ‘norm‘ is not defined
  5. Busy Dialog init - hashchange will call BusyDialog.open - flower
  6. 69 session和cookie的区别
  7. java 并发 set_高并发下的Java数据结构(List、Set、Map、Queue)
  8. 2016 Multi-University Training Contest 1 T4
  9. apache自定义虚拟主机日志格式
  10. 【面经】关于逻辑回归,面试官们都怎么问
  11. 安利一款倒计时插件---雨滴桌面
  12. 《人月神话》7(The Mythical Man-Month)为什么巴比伦塔会失败?
  13. Windows11 正式版 iso镜像下载
  14. 大数据时代网络舆情与社会治理研究
  15. 【js】判断时间段之间是否有重叠
  16. win10移动桌面图标字体发虚
  17. EasyPlayerPro RTMP播放器助力远程娃娃机直播抓娃娃技术方案
  18. 基于Redission实现分布式锁
  19. 【全套资料.zip下载】数电课设-数字频率计Multisim仿真设计【Multisim仿真+报告+讲解视频.zip下载】
  20. 面向儿童的简易编程工具---Scratch

热门文章

  1. Kaggle 注册问题
  2. 一种更简单的求最小平方均值函数(MSE)的方法 -- 梯度下降法。
  3. 半小时读懂互联网广告新生态
  4. 使用动态规划求解算法问题的五大特点总结(附基于Python的参考代码)
  5. 抖音怎么知道自己上热门 手机视频md5值修改
  6. handsontable 给单元格设置下拉 菜单
  7. 天冷服务器自动关机,天冷iphone自动关机怎么办 天冷iphone自动关机解决办法【详解】...
  8. 阿卡迪亚大学计算机专业好考吗,普通高中学生如何考取阿卡迪亚大学?
  9. SEM竞价推广创意快速撰写的方法,智能创意制作
  10. uploadify html5 java_工作中碰到uploadify插件两个版本:HTML5和Flash