| <?xml version="1.0" encoding="UTF-8"?> | |
| <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" | |
| "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []> | |
| <book id="iioid"> | |
| <bookinfo> | |
| <title>Industrial I/O driver developer's guide </title> | |
| <authorgroup> | |
| <author> | |
| <firstname>Daniel</firstname> | |
| <surname>Baluta</surname> | |
| <affiliation> | |
| <address> | |
| <email>[email protected]</email> | |
| </address> | |
| </affiliation> | |
| </author> | |
| </authorgroup> | |
| <copyright> | |
| <year>2015</year> | |
| <holder>Intel Corporation</holder> | |
| </copyright> | |
| <legalnotice> | |
| <para> | |
| This documentation is free software; you can redistribute | |
| it and/or modify it under the terms of the GNU General Public | |
| License version 2. | |
| </para> | |
| </legalnotice> | |
| </bookinfo> | |
| <toc></toc> | |
| <chapter id="intro"> | |
| <title>Introduction</title> | |
| <para> | |
| The main purpose of the Industrial I/O subsystem (IIO) is to provide | |
| support for devices that in some sense perform either analog-to-digital | |
| conversion (ADC) or digital-to-analog conversion (DAC) or both. The aim | |
| is to fill the gap between the somewhat similar hwmon and input | |
| subsystems. | |
| Hwmon is directed at low sample rate sensors used to monitor and | |
| control the system itself, like fan speed control or temperature | |
| measurement. Input is, as its name suggests, focused on human interaction | |
| input devices (keyboard, mouse, touchscreen). In some cases there is | |
| considerable overlap between these and IIO. | |
| </para> | |
| <para> | |
| Devices that fall into this category include: | |
| <itemizedlist> | |
| <listitem> | |
| analog to digital converters (ADCs) | |
| </listitem> | |
| <listitem> | |
| accelerometers | |
| </listitem> | |
| <listitem> | |
| capacitance to digital converters (CDCs) | |
| </listitem> | |
| <listitem> | |
| digital to analog converters (DACs) | |
| </listitem> | |
| <listitem> | |
| gyroscopes | |
| </listitem> | |
| <listitem> | |
| inertial measurement units (IMUs) | |
| </listitem> | |
| <listitem> | |
| color and light sensors | |
| </listitem> | |
| <listitem> | |
| magnetometers | |
| </listitem> | |
| <listitem> | |
| pressure sensors | |
| </listitem> | |
| <listitem> | |
| proximity sensors | |
| </listitem> | |
| <listitem> | |
| temperature sensors | |
| </listitem> | |
| </itemizedlist> | |
| Usually these sensors are connected via SPI or I2C. A common use case of the | |
| sensors devices is to have combined functionality (e.g. light plus proximity | |
| sensor). | |
| </para> | |
| </chapter> | |
| <chapter id='iiosubsys'> | |
| <title>Industrial I/O core</title> | |
| <para> | |
| The Industrial I/O core offers: | |
| <itemizedlist> | |
| <listitem> | |
| a unified framework for writing drivers for many different types of | |
| embedded sensors. | |
| </listitem> | |
| <listitem> | |
| a standard interface to user space applications manipulating sensors. | |
| </listitem> | |
| </itemizedlist> | |
| The implementation can be found under <filename> | |
| drivers/iio/industrialio-*</filename> | |
| </para> | |
| <sect1 id="iiodevice"> | |
| <title> Industrial I/O devices </title> | |
| !Finclude/linux/iio/iio.h iio_dev | |
| !Fdrivers/iio/industrialio-core.c iio_device_alloc | |
| !Fdrivers/iio/industrialio-core.c iio_device_free | |
| !Fdrivers/iio/industrialio-core.c iio_device_register | |
| !Fdrivers/iio/industrialio-core.c iio_device_unregister | |
| <para> | |
| An IIO device usually corresponds to a single hardware sensor and it | |
| provides all the information needed by a driver handling a device. | |
| Let's first have a look at the functionality embedded in an IIO | |
| device then we will show how a device driver makes use of an IIO | |
| device. | |
| </para> | |
| <para> | |
| There are two ways for a user space application to interact | |
| with an IIO driver. | |
| <itemizedlist> | |
| <listitem> | |
| <filename>/sys/bus/iio/iio:deviceX/</filename>, this | |
| represents a hardware sensor and groups together the data | |
| channels of the same chip. | |
| </listitem> | |
| <listitem> | |
| <filename>/dev/iio:deviceX</filename>, character device node | |
| interface used for buffered data transfer and for events information | |
| retrieval. | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| A typical IIO driver will register itself as an I2C or SPI driver and will | |
| create two routines, <function> probe </function> and <function> remove | |
| </function>. At <function>probe</function>: | |
| <itemizedlist> | |
| <listitem>call <function>iio_device_alloc</function>, which allocates memory | |
| for an IIO device. | |
| </listitem> | |
| <listitem> initialize IIO device fields with driver specific information | |
| (e.g. device name, device channels). | |
| </listitem> | |
| <listitem>call <function> iio_device_register</function>, this registers the | |
| device with the IIO core. After this call the device is ready to accept | |
| requests from user space applications. | |
| </listitem> | |
| </itemizedlist> | |
| At <function>remove</function>, we free the resources allocated in | |
| <function>probe</function> in reverse order: | |
| <itemizedlist> | |
| <listitem><function>iio_device_unregister</function>, unregister the device | |
| from the IIO core. | |
| </listitem> | |
| <listitem><function>iio_device_free</function>, free the memory allocated | |
| for the IIO device. | |
| </listitem> | |
| </itemizedlist> | |
| <sect2 id="iioattr"> <title> IIO device sysfs interface </title> | |
| <para> | |
| Attributes are sysfs files used to expose chip info and also allowing | |
| applications to set various configuration parameters. For device | |
| with index X, attributes can be found under | |
| <filename>/sys/bus/iio/iio:deviceX/ </filename> directory. | |
| Common attributes are: | |
| <itemizedlist> | |
| <listitem><filename>name</filename>, description of the physical | |
| chip. | |
| </listitem> | |
| <listitem><filename>dev</filename>, shows the major:minor pair | |
| associated with <filename>/dev/iio:deviceX</filename> node. | |
| </listitem> | |
| <listitem><filename>sampling_frequency_available</filename>, | |
| available discrete set of sampling frequency values for | |
| device. | |
| </listitem> | |
| </itemizedlist> | |
| Available standard attributes for IIO devices are described in the | |
| <filename>Documentation/ABI/testing/sysfs-bus-iio </filename> file | |
| in the Linux kernel sources. | |
| </para> | |
| </sect2> | |
| <sect2 id="iiochannel"> <title> IIO device channels </title> | |
| !Finclude/linux/iio/iio.h iio_chan_spec structure. | |
| <para> | |
| An IIO device channel is a representation of a data channel. An | |
| IIO device can have one or multiple channels. For example: | |
| <itemizedlist> | |
| <listitem> | |
| a thermometer sensor has one channel representing the | |
| temperature measurement. | |
| </listitem> | |
| <listitem> | |
| a light sensor with two channels indicating the measurements in | |
| the visible and infrared spectrum. | |
| </listitem> | |
| <listitem> | |
| an accelerometer can have up to 3 channels representing | |
| acceleration on X, Y and Z axes. | |
| </listitem> | |
| </itemizedlist> | |
| An IIO channel is described by the <type> struct iio_chan_spec | |
| </type>. A thermometer driver for the temperature sensor in the | |
| example above would have to describe its channel as follows: | |
| <programlisting> | |
| static const struct iio_chan_spec temp_channel[] = { | |
| { | |
| .type = IIO_TEMP, | |
| .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), | |
| }, | |
| }; | |
| </programlisting> | |
| Channel sysfs attributes exposed to userspace are specified in | |
| the form of <emphasis>bitmasks</emphasis>. Depending on their | |
| shared info, attributes can be set in one of the following masks: | |
| <itemizedlist> | |
| <listitem><emphasis>info_mask_separate</emphasis>, attributes will | |
| be specific to this channel</listitem> | |
| <listitem><emphasis>info_mask_shared_by_type</emphasis>, | |
| attributes are shared by all channels of the same type</listitem> | |
| <listitem><emphasis>info_mask_shared_by_dir</emphasis>, attributes | |
| are shared by all channels of the same direction </listitem> | |
| <listitem><emphasis>info_mask_shared_by_all</emphasis>, | |
| attributes are shared by all channels</listitem> | |
| </itemizedlist> | |
| When there are multiple data channels per channel type we have two | |
| ways to distinguish between them: | |
| <itemizedlist> | |
| <listitem> set <emphasis> .modified</emphasis> field of <type> | |
| iio_chan_spec</type> to 1. Modifiers are specified using | |
| <emphasis>.channel2</emphasis> field of the same | |
| <type>iio_chan_spec</type> structure and are used to indicate a | |
| physically unique characteristic of the channel such as its direction | |
| or spectral response. For example, a light sensor can have two channels, | |
| one for infrared light and one for both infrared and visible light. | |
| </listitem> | |
| <listitem> set <emphasis>.indexed </emphasis> field of | |
| <type>iio_chan_spec</type> to 1. In this case the channel is | |
| simply another instance with an index specified by the | |
| <emphasis>.channel</emphasis> field. | |
| </listitem> | |
| </itemizedlist> | |
| Here is how we can make use of the channel's modifiers: | |
| <programlisting> | |
| static const struct iio_chan_spec light_channels[] = { | |
| { | |
| .type = IIO_INTENSITY, | |
| .modified = 1, | |
| .channel2 = IIO_MOD_LIGHT_IR, | |
| .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
| .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ), | |
| }, | |
| { | |
| .type = IIO_INTENSITY, | |
| .modified = 1, | |
| .channel2 = IIO_MOD_LIGHT_BOTH, | |
| .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
| .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ), | |
| }, | |
| { | |
| .type = IIO_LIGHT, | |
| .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), | |
| .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ), | |
| }, | |
| } | |
| </programlisting> | |
| This channel's definition will generate two separate sysfs files | |
| for raw data retrieval: | |
| <itemizedlist> | |
| <listitem> | |
| <filename>/sys/bus/iio/iio:deviceX/in_intensity_ir_raw</filename> | |
| </listitem> | |
| <listitem> | |
| <filename>/sys/bus/iio/iio:deviceX/in_intensity_both_raw</filename> | |
| </listitem> | |
| </itemizedlist> | |
| one file for processed data: | |
| <itemizedlist> | |
| <listitem> | |
| <filename>/sys/bus/iio/iio:deviceX/in_illuminance_input | |
| </filename> | |
| </listitem> | |
| </itemizedlist> | |
| and one shared sysfs file for sampling frequency: | |
| <itemizedlist> | |
| <listitem> | |
| <filename>/sys/bus/iio/iio:deviceX/sampling_frequency. | |
| </filename> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| Here is how we can make use of the channel's indexing: | |
| <programlisting> | |
| static const struct iio_chan_spec light_channels[] = { | |
| { | |
| .type = IIO_VOLTAGE, | |
| .indexed = 1, | |
| .channel = 0, | |
| .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
| }, | |
| { | |
| .type = IIO_VOLTAGE, | |
| .indexed = 1, | |
| .channel = 1, | |
| .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
| }, | |
| } | |
| </programlisting> | |
| This will generate two separate attributes files for raw data | |
| retrieval: | |
| <itemizedlist> | |
| <listitem> | |
| <filename>/sys/bus/iio/devices/iio:deviceX/in_voltage0_raw</filename>, | |
| representing voltage measurement for channel 0. | |
| </listitem> | |
| <listitem> | |
| <filename>/sys/bus/iio/devices/iio:deviceX/in_voltage1_raw</filename>, | |
| representing voltage measurement for channel 1. | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="iiobuffer"> <title> Industrial I/O buffers </title> | |
| !Finclude/linux/iio/buffer.h iio_buffer | |
| !Edrivers/iio/industrialio-buffer.c | |
| <para> | |
| The Industrial I/O core offers a way for continuous data capture | |
| based on a trigger source. Multiple data channels can be read at once | |
| from <filename>/dev/iio:deviceX</filename> character device node, | |
| thus reducing the CPU load. | |
| </para> | |
| <sect2 id="iiobuffersysfs"> | |
| <title>IIO buffer sysfs interface </title> | |
| <para> | |
| An IIO buffer has an associated attributes directory under <filename> | |
| /sys/bus/iio/iio:deviceX/buffer/</filename>. Here are the existing | |
| attributes: | |
| <itemizedlist> | |
| <listitem> | |
| <emphasis>length</emphasis>, the total number of data samples | |
| (capacity) that can be stored by the buffer. | |
| </listitem> | |
| <listitem> | |
| <emphasis>enable</emphasis>, activate buffer capture. | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| </sect2> | |
| <sect2 id="iiobuffersetup"> <title> IIO buffer setup </title> | |
| <para>The meta information associated with a channel reading | |
| placed in a buffer is called a <emphasis> scan element </emphasis>. | |
| The important bits configuring scan elements are exposed to | |
| userspace applications via the <filename> | |
| /sys/bus/iio/iio:deviceX/scan_elements/</filename> directory. This | |
| file contains attributes of the following form: | |
| <itemizedlist> | |
| <listitem><emphasis>enable</emphasis>, used for enabling a channel. | |
| If and only if its attribute is non zero, then a triggered capture | |
| will contain data samples for this channel. | |
| </listitem> | |
| <listitem><emphasis>type</emphasis>, description of the scan element | |
| data storage within the buffer and hence the form in which it is | |
| read from user space. Format is <emphasis> | |
| [be|le]:[s|u]bits/storagebitsXrepeat[>>shift] </emphasis>. | |
| <itemizedlist> | |
| <listitem> <emphasis>be</emphasis> or <emphasis>le</emphasis>, specifies | |
| big or little endian. | |
| </listitem> | |
| <listitem> | |
| <emphasis>s </emphasis>or <emphasis>u</emphasis>, specifies if | |
| signed (2's complement) or unsigned. | |
| </listitem> | |
| <listitem><emphasis>bits</emphasis>, is the number of valid data | |
| bits. | |
| </listitem> | |
| <listitem><emphasis>storagebits</emphasis>, is the number of bits | |
| (after padding) that it occupies in the buffer. | |
| </listitem> | |
| <listitem> | |
| <emphasis>shift</emphasis>, if specified, is the shift that needs | |
| to be applied prior to masking out unused bits. | |
| </listitem> | |
| <listitem> | |
| <emphasis>repeat</emphasis>, specifies the number of bits/storagebits | |
| repetitions. When the repeat element is 0 or 1, then the repeat | |
| value is omitted. | |
| </listitem> | |
| </itemizedlist> | |
| </listitem> | |
| </itemizedlist> | |
| For example, a driver for a 3-axis accelerometer with 12 bit | |
| resolution where data is stored in two 8-bits registers as | |
| follows: | |
| <programlisting> | |
| 7 6 5 4 3 2 1 0 | |
| +---+---+---+---+---+---+---+---+ | |
| |D3 |D2 |D1 |D0 | X | X | X | X | (LOW byte, address 0x06) | |
| +---+---+---+---+---+---+---+---+ | |
| 7 6 5 4 3 2 1 0 | |
| +---+---+---+---+---+---+---+---+ | |
| |D11|D10|D9 |D8 |D7 |D6 |D5 |D4 | (HIGH byte, address 0x07) | |
| +---+---+---+---+---+---+---+---+ | |
| </programlisting> | |
| will have the following scan element type for each axis: | |
| <programlisting> | |
| $ cat /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_y_type | |
| le:s12/16>>4 | |
| </programlisting> | |
| A user space application will interpret data samples read from the | |
| buffer as two byte little endian signed data, that needs a 4 bits | |
| right shift before masking out the 12 valid bits of data. | |
| </para> | |
| <para> | |
| For implementing buffer support a driver should initialize the following | |
| fields in <type>iio_chan_spec</type> definition: | |
| <programlisting> | |
| struct iio_chan_spec { | |
| /* other members */ | |
| int scan_index | |
| struct { | |
| char sign; | |
| u8 realbits; | |
| u8 storagebits; | |
| u8 shift; | |
| u8 repeat; | |
| enum iio_endian endianness; | |
| } scan_type; | |
| }; | |
| </programlisting> | |
| The driver implementing the accelerometer described above will | |
| have the following channel definition: | |
| <programlisting> | |
| struct struct iio_chan_spec accel_channels[] = { | |
| { | |
| .type = IIO_ACCEL, | |
| .modified = 1, | |
| .channel2 = IIO_MOD_X, | |
| /* other stuff here */ | |
| .scan_index = 0, | |
| .scan_type = { | |
| .sign = 's', | |
| .realbits = 12, | |
| .storgebits = 16, | |
| .shift = 4, | |
| .endianness = IIO_LE, | |
| }, | |
| } | |
| /* similar for Y (with channel2 = IIO_MOD_Y, scan_index = 1) | |
| * and Z (with channel2 = IIO_MOD_Z, scan_index = 2) axis | |
| */ | |
| } | |
| </programlisting> | |
| </para> | |
| <para> | |
| Here <emphasis> scan_index </emphasis> defines the order in which | |
| the enabled channels are placed inside the buffer. Channels with a lower | |
| scan_index will be placed before channels with a higher index. Each | |
| channel needs to have a unique scan_index. | |
| </para> | |
| <para> | |
| Setting scan_index to -1 can be used to indicate that the specific | |
| channel does not support buffered capture. In this case no entries will | |
| be created for the channel in the scan_elements directory. | |
| </para> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="iiotrigger"> <title> Industrial I/O triggers </title> | |
| !Finclude/linux/iio/trigger.h iio_trigger | |
| !Edrivers/iio/industrialio-trigger.c | |
| <para> | |
| In many situations it is useful for a driver to be able to | |
| capture data based on some external event (trigger) as opposed | |
| to periodically polling for data. An IIO trigger can be provided | |
| by a device driver that also has an IIO device based on hardware | |
| generated events (e.g. data ready or threshold exceeded) or | |
| provided by a separate driver from an independent interrupt | |
| source (e.g. GPIO line connected to some external system, timer | |
| interrupt or user space writing a specific file in sysfs). A | |
| trigger may initiate data capture for a number of sensors and | |
| also it may be completely unrelated to the sensor itself. | |
| </para> | |
| <sect2 id="iiotrigsysfs"> <title> IIO trigger sysfs interface </title> | |
| There are two locations in sysfs related to triggers: | |
| <itemizedlist> | |
| <listitem><filename>/sys/bus/iio/devices/triggerY</filename>, | |
| this file is created once an IIO trigger is registered with | |
| the IIO core and corresponds to trigger with index Y. Because | |
| triggers can be very different depending on type there are few | |
| standard attributes that we can describe here: | |
| <itemizedlist> | |
| <listitem> | |
| <emphasis>name</emphasis>, trigger name that can be later | |
| used for association with a device. | |
| </listitem> | |
| <listitem> | |
| <emphasis>sampling_frequency</emphasis>, some timer based | |
| triggers use this attribute to specify the frequency for | |
| trigger calls. | |
| </listitem> | |
| </itemizedlist> | |
| </listitem> | |
| <listitem> | |
| <filename>/sys/bus/iio/devices/iio:deviceX/trigger/</filename>, this | |
| directory is created once the device supports a triggered | |
| buffer. We can associate a trigger with our device by writing | |
| the trigger's name in the <filename>current_trigger</filename> file. | |
| </listitem> | |
| </itemizedlist> | |
| </sect2> | |
| <sect2 id="iiotrigattr"> <title> IIO trigger setup</title> | |
| <para> | |
| Let's see a simple example of how to setup a trigger to be used | |
| by a driver. | |
| <programlisting> | |
| struct iio_trigger_ops trigger_ops = { | |
| .set_trigger_state = sample_trigger_state, | |
| .validate_device = sample_validate_device, | |
| } | |
| struct iio_trigger *trig; | |
| /* first, allocate memory for our trigger */ | |
| trig = iio_trigger_alloc(dev, "trig-%s-%d", name, idx); | |
| /* setup trigger operations field */ | |
| trig->ops = &trigger_ops; | |
| /* now register the trigger with the IIO core */ | |
| iio_trigger_register(trig); | |
| </programlisting> | |
| </para> | |
| </sect2> | |
| <sect2 id="iiotrigsetup"> <title> IIO trigger ops</title> | |
| !Finclude/linux/iio/trigger.h iio_trigger_ops | |
| <para> | |
| Notice that a trigger has a set of operations attached: | |
| <itemizedlist> | |
| <listitem> | |
| <function>set_trigger_state</function>, switch the trigger on/off | |
| on demand. | |
| </listitem> | |
| <listitem> | |
| <function>validate_device</function>, function to validate the | |
| device when the current trigger gets changed. | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="iiotriggered_buffer"> | |
| <title> Industrial I/O triggered buffers </title> | |
| <para> | |
| Now that we know what buffers and triggers are let's see how they | |
| work together. | |
| </para> | |
| <sect2 id="iiotrigbufsetup"> <title> IIO triggered buffer setup</title> | |
| !Edrivers/iio/industrialio-triggered-buffer.c | |
| !Finclude/linux/iio/iio.h iio_buffer_setup_ops | |
| <para> | |
| A typical triggered buffer setup looks like this: | |
| <programlisting> | |
| const struct iio_buffer_setup_ops sensor_buffer_setup_ops = { | |
| .preenable = sensor_buffer_preenable, | |
| .postenable = sensor_buffer_postenable, | |
| .postdisable = sensor_buffer_postdisable, | |
| .predisable = sensor_buffer_predisable, | |
| }; | |
| irqreturn_t sensor_iio_pollfunc(int irq, void *p) | |
| { | |
| pf->timestamp = iio_get_time_ns(); | |
| return IRQ_WAKE_THREAD; | |
| } | |
| irqreturn_t sensor_trigger_handler(int irq, void *p) | |
| { | |
| u16 buf[8]; | |
| int i = 0; | |
| /* read data for each active channel */ | |
| for_each_set_bit(bit, active_scan_mask, masklength) | |
| buf[i++] = sensor_get_data(bit) | |
| iio_push_to_buffers_with_timestamp(indio_dev, buf, timestamp); | |
| iio_trigger_notify_done(trigger); | |
| return IRQ_HANDLED; | |
| } | |
| /* setup triggered buffer, usually in probe function */ | |
| iio_triggered_buffer_setup(indio_dev, sensor_iio_polfunc, | |
| sensor_trigger_handler, | |
| sensor_buffer_setup_ops); | |
| </programlisting> | |
| </para> | |
| The important things to notice here are: | |
| <itemizedlist> | |
| <listitem><function> iio_buffer_setup_ops</function>, the buffer setup | |
| functions to be called at predefined points in the buffer configuration | |
| sequence (e.g. before enable, after disable). If not specified, the | |
| IIO core uses the default <type>iio_triggered_buffer_setup_ops</type>. | |
| </listitem> | |
| <listitem><function>sensor_iio_pollfunc</function>, the function that | |
| will be used as top half of poll function. It should do as little | |
| processing as possible, because it runs in interrupt context. The most | |
| common operation is recording of the current timestamp and for this reason | |
| one can use the IIO core defined <function>iio_pollfunc_store_time | |
| </function> function. | |
| </listitem> | |
| <listitem><function>sensor_trigger_handler</function>, the function that | |
| will be used as bottom half of the poll function. This runs in the | |
| context of a kernel thread and all the processing takes place here. | |
| It usually reads data from the device and stores it in the internal | |
| buffer together with the timestamp recorded in the top half. | |
| </listitem> | |
| </itemizedlist> | |
| </sect2> | |
| </sect1> | |
| </chapter> | |
| <chapter id='iioresources'> | |
| <title> Resources </title> | |
| IIO core may change during time so the best documentation to read is the | |
| source code. There are several locations where you should look: | |
| <itemizedlist> | |
| <listitem> | |
| <filename>drivers/iio/</filename>, contains the IIO core plus | |
| and directories for each sensor type (e.g. accel, magnetometer, | |
| etc.) | |
| </listitem> | |
| <listitem> | |
| <filename>include/linux/iio/</filename>, contains the header | |
| files, nice to read for the internal kernel interfaces. | |
| </listitem> | |
| <listitem> | |
| <filename>include/uapi/linux/iio/</filename>, contains files to be | |
| used by user space applications. | |
| </listitem> | |
| <listitem> | |
| <filename>tools/iio/</filename>, contains tools for rapidly | |
| testing buffers, events and device creation. | |
| </listitem> | |
| <listitem> | |
| <filename>drivers/staging/iio/</filename>, contains code for some | |
| drivers or experimental features that are not yet mature enough | |
| to be moved out. | |
| </listitem> | |
| </itemizedlist> | |
| <para> | |
| Besides the code, there are some good online documentation sources: | |
| <itemizedlist> | |
| <listitem> | |
| <ulink url="http://marc.info/?l=linux-iio"> Industrial I/O mailing | |
| list </ulink> | |
| </listitem> | |
| <listitem> | |
| <ulink url="http://wiki.analog.com/software/linux/docs/iio/iio"> | |
| Analog Device IIO wiki page </ulink> | |
| </listitem> | |
| <listitem> | |
| <ulink url="https://fosdem.org/2015/schedule/event/iiosdr/"> | |
| Using the Linux IIO framework for SDR, Lars-Peter Clausen's | |
| presentation at FOSDEM </ulink> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| </chapter> | |
| </book> | |
| <!-- | |
| vim: softtabstop=2:shiftwidth=2:expandtab:textwidth=72 | |
| --> |