Hardware is here!

As discussed with my mentors, an important part of my project implies changing the driver for Intersil ISL29018 digital ambient light and proximity sensor to use proper IIO ABI and adapt the code to follow the kernel coding style.

Since the driver also has support for ISL29023 and ISL29035 (with some small differences between them), we got the ISL29035 sensor. A few days ago I received all the hardware I need and now I’m ready to start working on it.

Since the device only has an I2C interface, I needed an adapter to easily connect it to my laptop. For that we got DLN-2, an USB-I2C/SPI/GPIO Interface Adapter from Diolan.

The next step was putting them all together and start getting familiar with the driver.

These been said, armed with lots of determination, documentation and a detailed datasheet (hopefully :D), I’m looking forward to getting this driver out of staging!

What is IIO?

Probably everybody knows about I/O Subsystem, but what is Industrial I/O Subsystem?

IIO is a kernel subsystem for analog to digital or digital to analog converters and related hardware. It has been developed since 2009 by Jonathan Cameron and linux-iio community. Examples of devices that fall in this category are: gyroscopes, accelerometers, light sensors, magnetometers, etc.

IIO is organized on two levels, devices and channels:

  • device is the top level of the hierarchy and it represents the acquisition chip. A device is described by the structures iio_info and iio_dev.
  • channel represents a single acquisition source of the device. A channel is described by the iio_chan_spec structure.

IIO communicates with user space via sysfs and a character device. We will have a look at how users can read information from devices.

Lets have a 3-axis accelerometer, mma8452 for example. After compiling and loading the module, if we look under /sys/bus/iio/devices/iio:device0/ we should have the following entries:

roberta@bazinga:~$ ls -l /sys/bus/iio/devices/iio:device0/
-rw-r--r-- 1 root root 4096 ian 21 17:01 in_accel_sampling_frequency
-rw-r--r-- 1 root root 4096 ian 21 17:01 in_accel_scale
-rw-r--r-- 1 root root 4096 ian 21 17:01 in_accel_x_calibbias
-rw-r--r-- 1 root root 4096 ian 21 17:01 in_accel_x_raw
-rw-r--r-- 1 root root 4096 ian 21 17:01 in_accel_y_calibbias
-rw-r--r-- 1 root root 4096 ian 21 17:01 in_accel_y_raw
-rw-r--r-- 1 root root 4096 ian 21 17:01 in_accel_z_calibbias
-rw-r--r-- 1 root root 4096 ian 21 17:01 in_accel_z_raw

The channel definition which gives this entry looks something like this:

#define MMA8452_CHANNEL(axis, idx) { \
    .type = IIO_ACCEL, \
    .modified = 1, \
    .channel2 = IIO_MOD_##axis, \
    .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
    .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
    .scan_index = idx, \
    .scan_type = { \
        .sign = 's', \
        .realbits = 12, \
        .storagebits = 16, \
        .shift = 4, \
        .endianness = IIO_BE, \
    }, \
static const struct iio_chan_spec mma8452_channels[] = {
    MMA8452_CHANNEL(X, 0),
    MMA8452_CHANNEL(Y, 1),
    MMA8452_CHANNEL(Z, 2),

So what are all these fields from  iio_chan_spec structure and what are their roles?

  • .type specifies the type of measurement that the channel is making. In our case (accelerometer), this is set to IIO_ACCEL, but it can have different values, such as: IIO_LIGHT, IIO_VOLTAGE, etc.
  • .modifier specifies if a modifier applies to this channel and in that case modifier is set in .channel2 (IIO_MOD_X, IIO_MOD_Y, IIO_MOD_Z for axial-sensors about the xyz axis)
  • .scan_index and .scan_type fields are used to identify elements from a buffer, when using buffer triggers, but we will discuss more about this in a future post.
  • .info_mask_separate and .info_mask_shared_by_type indicate what information is to be exported that is specific to this channel, respectively that is shared by all channels of the same type. In the example above IIO_CHAN_INFO_RAW, IIO_CHAN_INFO_CALIBBIAS, IIO_CHAN_INFO_SCALE, IIO_CHAN_INFO_SAMP_FREQ were used, but there are also others that can be used according to the driver specifications.

So what is the connection between the entries from /sys/bus/iio/devices/iio:device0/ stated before and these masks?

For instance, reading in_accel_scale calls the read_raw hook with the mask set to IIO_CHAN_INFO_SCALE. Reading in_accel_x_raw calls the read_raw hook with the mask set to IIO_CHAN_INFO_RAW (which is actually 0 since the data should be unscaled) and the channel argument set to the structure corresponding to channel X. More information about all these can be found in documentation.

Next posts will provide a brief overview of IIO triggered buffers (used to limit the amount of reads done by an application) and IIO events (used to receive a notification from the kernel when some event related to IIO happens).

A very nice description of IIO can be found in this presentation.

Additional information:

First round of accepted patches

I started the work at my project by doing some cleanup and small fixes. The patches I sent were accepted and are part of the first round of new IIO drivers, features and cleanups for the 3.20 cycle.

Thanks to some of these patches some Kconfig entries gain annotation with the resulting module name. Other fixes were removing pointless ‘out of memory’ message and unnecessary braces, fix char unsigned order in ad8366, increase the sleep time in ad9523 to make it predictable since that operation isn’t timing critical. Besides all that, there were some patches doing trivial space before comma fixups and white space cleanups.

All these patches are now part of Industrial Input/Output Subsytem tree.