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

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

一、 虚拟IIO DEVICE的说明

 

二、虚拟IIO DEVICE DRIVER实现所需的知识点

 

三、虚拟IIO DEVICE DRIVER的数据结构及实现说明

 

四、虚拟IIO DEVICE DRIVER的测试验证

 

 

一、 虚拟IIO DEVICE的说明

本次我们将实现一个虚拟的温度传感器芯片(芯片型号为virt0824),该设备提供2个channel,并且提

供7个寄存器,定义如下:

Channel0_current_temp(0x00,表示通道0的当前温度)

Channel1_current_temp(0x01,表示通道1的当前温度)

Channel0_high_alarm_temp(0x02,表示通道0的温度过高告警阈值)

Channel1_high_alarm_temp(0x03,表示通道1的温度过高告警阈值)

Channel0_low_alarm_temp(0x04,表示通道0的温度过低告警阈值)

Channel1_low_alarm_temp(0x05,表示通道0的温度过低告警阈值)

Channel_fault_mask//4个bit;(0x06,表示温度告警fault bit,bit0-bit1表示温度过高告警标志、bit2-bit3表示温度过低告警标志)

该温度传感器为iic device,并且支持温度告警中断,同时该温度传感器支持温度数据ready中断(此中断主要用于支持iio buffer对应的数据连续采集功能,实际的芯片可能并不提供该中断)

二、虚拟IIO DEVICE DRIVER实现所需的知识点

为了让本次实现的IIO DEVICE能够尽量实现数据单次采集、iio buffer、iio event等功能,本次虚拟iio

device driver主要涉及如下几个知识点:

  1. 提供虚拟iio adapter controller,并完成一个虚拟的温度传感器芯片,并提供sysfs下的属性文件,可以修改温度传感器芯片中的各寄存器的值,可以置位温度告警位等等;
  2. 提供虚拟的irq chip,用于触发温度传感器温度告警中断、温度数据可读中断;
  3. 提供iio device driver,实现温度传感器对应iio device的创建及注册。

 

 

三、虚拟IIO DEVICE DRIVER的数据结构及实现说明

数据结构定义 

    定义数据结构virt0824_temp,该结构体中包含iic client对应的regmap对象(用于读取virt0824设备的寄存器值)、该iio device对应的iio trigger,用于处理温度传感器温度告警中断信息,

struct virt0824_temp

{        

char name[32];

struct regmap *regmap;

struct virt0824_temp_info *temp_info;

struct iio_trigger *trig;

spinlock_t lock;

unsigned short        data[2] ____cacheline_aligned;

};

 

实现说明

iio event实现(温度告警)

      基于温度告警,我们通过在温度告警中断处理函数中读取告警信息,并event信息发送给iio event的kfifo中,接口调度过程如下所示,通过该调度过程,应用程序即可监控到温度传感器上报的告警。

 

温度告警中断处理函数的实现如下所示

 

static         irqreturn_t virt0824_event_handler(int irq, void * data)

{

struct iio_dev *indio_dev = (struct iio_dev *)data;

struct virt0824_temp *devp = iio_priv(indio_dev);

unsigned long flags = 0;

unsigned int val = 0;

int ret = 0;



spin_lock_irqsave(&devp->lock, flags);

ret = regmap_read(devp->regmap, CHANNEL_FAULT_MASK, &val);

if(ret)

goto unlock;



if (val & BIT(CHANNEL0_HIGH_ALARM_TEMP_BIT))

{

iio_push_event(indio_dev,

IIO_UNMOD_EVENT_CODE(IIO_TEMP,

CHANNEL0_HIGH_ALARM_TEMP_BIT,

IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), iio_get_time_ns());

printk("%s:%d \n", __FUNCTION__, __LINE__);

}



if (val & BIT(CHANNEL1_HIGH_ALARM_TEMP_BIT))

{

iio_push_event(indio_dev,

IIO_UNMOD_EVENT_CODE(IIO_TEMP,

CHANNEL1_HIGH_ALARM_TEMP_BIT,

IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), iio_get_time_ns());

printk("%s:%d\n", __FUNCTION__, __LINE__);

}



if (val & BIT(CHANNEL0_LOW_ALARM_TEMP_BIT))

{

iio_push_event(indio_dev,

IIO_UNMOD_EVENT_CODE(IIO_TEMP,

CHANNEL0_HIGH_ALARM_TEMP_BIT,

IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), iio_get_time_ns());

printk("%s:%d\n", __FUNCTION__, __LINE__);

}



if (val & BIT(CHANNEL1_LOW_ALARM_TEMP_BIT))

{

iio_push_event(indio_dev,

IIO_UNMOD_EVENT_CODE(IIO_TEMP,

CHANNEL1_HIGH_ALARM_TEMP_BIT,

IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), iio_get_time_ns());

printk("%s:%d\n", __FUNCTION__, __LINE__);

}



unlock:

spin_unlock_irqrestore(&devp->lock, flags);

return IRQ_HANDLED;

}

 

iio buffer实现

    主要是连续采集各通道的当前温度,接口调度过程如下所示,通过该调度过程,应用程序即连续可读取温度传感器的当前温度。

 

      在本次的测试中,温度传感器通过温度数据可读中断从而将数据push到iio buffer中,用于连续数据采集的iio trigger,iio trigger-buffer的中断处理函数的实现如下

static        irqreturn_t virt0824_trigger_handler(int irq, void * data)

{

struct iio_dev *indio_dev = (struct iio_dev *)data;

struct virt0824_temp *devp = iio_priv(indio_dev);

disable_irq_nosync(irq);

printk("%s:%d\n", __FUNCTION__, __LINE__);



iio_trigger_poll(devp->trig);

printk("%s:%d\n", __FUNCTION__, __LINE__);



return IRQ_HANDLED;

}

 

该虚拟温度传感器的iio device相关的参数设置如下所示

static const struct iio_event_spec virt0824_temp_event[] = {

 {

 .type = IIO_EV_TYPE_THRESH,

 .dir = IIO_EV_DIR_RISING,

 .mask_separate = BIT(IIO_EV_INFO_VALUE) |

 BIT(IIO_EV_INFO_ENABLE),

 },

 {

 .type = IIO_EV_TYPE_THRESH,

 .dir = IIO_EV_DIR_FALLING,

 .mask_separate = BIT(IIO_EV_INFO_VALUE) |

 BIT(IIO_EV_INFO_ENABLE),

 },



};



static const struct iio_chan_spec virt0824_channels[] = {

{

.type = IIO_TEMP,

.indexed = 1,

.channel = 0,

.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),

.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),

.event_spec =virt0824_temp_event,

.num_event_specs = ARRAY_SIZE(virt0824_temp_event),

.scan_index = 0,

.scan_type = {

.sign = 's',

.realbits = 16,

.storagebits = 16,

.endianness = IIO_CPU,

},        

},

{

.type = IIO_TEMP,

.indexed = 1,

.channel = 1,

.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) ,

.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),

.event_spec = virt0824_temp_event,

.num_event_specs = ARRAY_SIZE(virt0824_temp_event),

.scan_index = 1,

.scan_type = {

.sign = 's',

.realbits = 16,

.storagebits = 16,

.endianness = IIO_CPU,

},        

}



};

 

另外针对虚拟中断控制器、虚拟iic device已经在其他专栏中说明,此处直接调用不再细说。

四、虚拟IIO DEVICE DRIVER的测试验证

        本驱动已经在ubuntu16.04上测试验证,由于ubuntu16.04内核默认没有将iio 子系统 编译进内核,但是已编译成驱动模块,可以在路径/lib/modules/4.4.0-66-generic/kernel/drivers/iio下找到对应的驱动模块,我们需要这些驱动模块: industrialio.ko、industrialio-triggered-event.ko、kfifo_buf.ko、industrialio-triggered-buffer.ko即可,先将这些驱动insmod 系统中;

 

然后按照本次虚拟驱动主要涉及如下内容:

insmod virt_i2c_controller.ko

insmod virt0808_dev.ko

insmod virt0808_irq.ko

insmod virt0824_temp_driver.ko

 

测试温度告警阈值

主要测试iio event功能,我们的虚拟程序中已经实现了iio event的应用测试程序。

  • 首先运行该测试程序;
  • 修改虚拟温度传感器的两个通道的当前温度、通道0的温度过高告警阈值、并设置温度0过高温度告警fault bit为1,执行的命令如下:

  • 寄存器值修改好后,我们手动触发一个温度过高告警中断,执行命令如下

 

  • 查看测试程序已经收到iio event事件,如下图所示

 

测试连续数据采集(iio buffer功能)

  • 首先使能通道0的温度采集功能,设置iio buffer的缓存为16,watermark为1

 

  • 开始监控/dev/iio:device,进行数据采集,命令如下

cat /dev/iio:device0 |xxd -c 2

  • 触发数据可读中断,如下图所示

              

  • 查看读取的数据,如下图所示,可正常进行数据采集

测试单次数据采集

执行如下命令即可对两个通道当前的数据进行温度采集工作。

 

 

 

 

      至此完成了IIO子系统专栏的分析,即完成了IIO子系统内部的设计说明,也完成了一个虚拟的IIO DEVICE DIRVER,希望对大家有所帮助。 本次测试代码的路径为https://gitee.com/jerry_chg/virt_iio_device_driver

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值