Reader small image

You're reading from  Linux Device Driver Development - Second Edition

Product typeBook
Published inApr 2022
PublisherPackt
ISBN-139781803240060
Edition2nd Edition
Right arrow
Author (1)
John Madieu
John Madieu
author image
John Madieu

John Madieu is an embedded Linux and kernel engineer living in Paris, France. His main activities consist of developing device drivers and Board Support Packages (BSPs) for companies in domains such as IoT, automation, transport, healthcare, energy, and the military. John is the founder and chief consultant at LABCSMART, a company that provides training and services for embedded Linux and Linux kernel engineering. He is an open source and embedded systems enthusiast, convinced that it is only by sharing knowledge that we can learn more. He is passionate about boxing, which he practiced for 6 years professionally, and continues to channel this passion through training sessions that he provides voluntarily.
Read more about John Madieu

Right arrow

Chapter 15: Digging into the IIO Framework

Industrial input/output (IIO) is a kernel subsystem dedicated to analog-to-digital converters (ADCs) and digital-to-analog converters (DACs). With the growing numbers of sensors (measurement devices with analog-to-digital or digital-to-analog capabilities) with different code implementations, scattered across kernel sources, gathering them became necessary. That is what the IIO framework does, in a generic way. Jonathan Cameron and the Linux IIO community have been developing it since 2009. Accelerometers, gyroscopes, current/voltage measurement chips, light sensors, and pressure sensors all fall into the IIO family of devices.

The IIO model is based on device and channel architecture:

  • The device represents the chip itself, the top level of the hierarchy.
  • The channel represents a single acquisition line of the device. A device may have one or more channels. For example, an accelerometer is a device with three channels, one for...

Introduction to IIO data structures

The IIO framework is made of a few data structures among which is one representing the IIO device, another one describing this device, and the last one enumerating the channels exposed by the device. An IIO device is represented in the kernel as an instance of struct iio_dev and described by a struct iio_info structure. All the important IIO structures are defined in include/linux/iio/iio.h.

Understanding the struct iio_dev structure

The struct iio_dev structure represents the IIO device, describing the device and its driver. It tells us how many channels are available on the device and what modes the device can operate in (one-shot or triggered buffer, for example). Moreover, this data structure exposes some hooks to be provided by the driver.

This data structure has the following definition:

struct iio_dev {
    [...]
    int            ...

Integrating IIO triggered buffer support

It might be useful to be able to capture data based on some external signals or events (triggers) in data acquisition applications. These triggers might be the following:

  • A data ready signal
  • An IRQ line connected to some external system (GPIO or whatever)
  • On processor periodic interrupt (a timer, for example)
  • User space reading/writing a specific file in sysfs

IIO device drivers are completely decorrelated from the triggers, whose drivers are implemented in drivers/iio/trigger/. A trigger may initialize data capture on one or many devices. These triggers are used to fill buffers, exposed to user space through the character device created during the registration of the IIO device.

You can develop your own trigger driver, but it is out of the scope of this book. We will try to focus on existing ones only. These are as follows:

  • iio-trig-interrupt: This allows using IRQs as IIO triggers. In old kernel versions...

Accessing IIO data

You may have guessed, there are only two ways to access data with the IIO framework: one-shot capture through sysfs channels or continuous mode (triggered buffer) via an IIO character device.

Single-shot capture

Single-shot data capture is done through the sysfs interface. By reading the sysfs entry that corresponds to a channel, you'll capture only the data specific to that channel. Say we have a temperature sensor with two channels: one for the ambient temperature and the other for the thermocouple temperature:

# cd /sys/bus/iio/devices/iio:device0
# cat in_voltage3_raw
6646 
# cat in_voltage_scale
0.305175781

The processed value is obtained by multiplying the scale by the raw value:

Voltage value: 6646 * 0.305175781 = 2028.19824053

The device datasheet says the process value is given in mV. In our case, it corresponds to 2.02819 V.

Accessing the data buffer

To get a triggered acquisition working, trigger support must have been implemented...

Dealing with the in-kernel IIO consumer interface

So far, we have dealt with the user-space consumer interface since data was consumed in user space. There are situations where a driver will require a dedicated IIO channel. An example is a battery charger that needs to measure the battery voltage as well. This measurement can be achieved using a dedicated IIO channel.

IIO channel attribution is done in the device tree. From the producer side, only one thing must be done: specifying the #io-channel-cells property according to the number of channels of the IIO device. Typically, it is 0 for nodes with a single IIO output and 1 for nodes with multiple IIO outputs. The following is an example:

adc: max1139@35 {
    compatible = "maxim,max1139";
    reg = <0x35>;
    #io-channel-cells = <1>;
};

On the consumer side, there are a few properties to provide. These are the following:

  • io-channels...

Writing user-space IIO applications

After the long journey through the kernel-side implementation, it might be interesting to have a look at the other side, the user space. IIO support in user space can be handled through sysfs or using libiio, a library that has been specially developed for this purpose and follows the kernel-side evolutions. This library abstracts the hardware's low-level details and provides an easy and comprehensive programming interface that can also be used for complex projects.

In this section, we will be using version 0.21 of the library, whose documentation can be found here: https://analogdevicesinc.github.io/libiio/v0.21/libiio/index.html.

libiio can run on the following:

  • A target, that is, the embedded system running Linux that includes IIO drivers for devices that are physically connected to the system, such as ADCs and DACs.
  • A remote computer connected to the embedded system through a network, USB, or serial connection. This remote...

Walking through user-space IIO tools

Though we have already gone through the steps required to capture IIO data, it might be tedious and confusing since each step must be performed manually. There are some useful tools you can use to ease and speed up your app development dealing with IIO devices. These are all from the libiio package, developed by Analog Devices, Inc. to interface IIO devices, available here: https://github.com/analogdevicesinc/libiio.

User-space applications can easily use the libiio library, which under the hood is a wrapper that relies on the following interfaces:

  • /sys/bus/iio/devices, the IIO sysfs interface, which is mainly used for configuration/settings
  • The /dev/iio/deviceX character device, for data/acquisitions

The preceding are exactly what we have manually dealt with so far. The tool's source code can be found under the library's tests directory: https://github.com/analogdevicesinc/libiio/tree/master/tests offers tools such...

Summary

After reading this chapter, you are familiar with the IIO framework and vocabulary. You know what channels, devices, and triggers are. You can even play with your IIO device from the user space, through sysfs or a character device. The time to write your own IIO driver has come. There are a lot of available existing drivers that don't support trigger buffers. You can try to add this feature to one of them.

In the next chapter, we will play with the GPIO subsystem, which is a basic concept that has been introduced in this chapter as well.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Linux Device Driver Development - Second Edition
Published in: Apr 2022Publisher: PacktISBN-13: 9781803240060
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
John Madieu

John Madieu is an embedded Linux and kernel engineer living in Paris, France. His main activities consist of developing device drivers and Board Support Packages (BSPs) for companies in domains such as IoT, automation, transport, healthcare, energy, and the military. John is the founder and chief consultant at LABCSMART, a company that provides training and services for embedded Linux and Linux kernel engineering. He is an open source and embedded systems enthusiast, convinced that it is only by sharing knowledge that we can learn more. He is passionate about boxing, which he practiced for 6 years professionally, and continues to channel this passion through training sessions that he provides voluntarily.
Read more about John Madieu