| ============= | |
| Core elements | |
| ============= | |
| The Industrial I/O core offers a unified framework for writing drivers for | |
| many different types of embedded sensors. a standard interface to user space | |
| applications manipulating sensors. The implementation can be found under | |
| :file:`drivers/iio/industrialio-*` | |
| Industrial I/O Devices | |
| ---------------------- | |
| * struct :c:type:`iio_dev` - industrial I/O device | |
| * :c:func:`iio_device_alloc()` - alocate an :c:type:`iio_dev` from a driver | |
| * :c:func:`iio_device_free()` - free an :c:type:`iio_dev` from a driver | |
| * :c:func:`iio_device_register()` - register a device with the IIO subsystem | |
| * :c:func:`iio_device_unregister()` - unregister a device from the IIO | |
| subsystem | |
| 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. | |
| There are two ways for a user space application to interact with an IIO driver. | |
| 1. :file:`/sys/bus/iio/iio:device{X}/`, this represents a hardware sensor | |
| and groups together the data channels of the same chip. | |
| 2. :file:`/dev/iio:device{X}`, character device node interface used for | |
| buffered data transfer and for events information retrieval. | |
| A typical IIO driver will register itself as an :doc:`I2C <../i2c>` or | |
| :doc:`SPI <../spi>` driver and will create two routines, probe and remove. | |
| At probe: | |
| 1. Call :c:func:`iio_device_alloc()`, which allocates memory for an IIO device. | |
| 2. Initialize IIO device fields with driver specific information (e.g. | |
| device name, device channels). | |
| 3. Call :c:func:`iio_device_register()`, this registers the device with the | |
| IIO core. After this call the device is ready to accept requests from user | |
| space applications. | |
| At remove, we free the resources allocated in probe in reverse order: | |
| 1. :c:func:`iio_device_unregister()`, unregister the device from the IIO core. | |
| 2. :c:func:`iio_device_free()`, free the memory allocated for the IIO device. | |
| IIO device sysfs interface | |
| ========================== | |
| 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 /sys/bus/iio/iio:deviceX/ directory. | |
| Common attributes are: | |
| * :file:`name`, description of the physical chip. | |
| * :file:`dev`, shows the major:minor pair associated with | |
| :file:`/dev/iio:deviceX` node. | |
| * :file:`sampling_frequency_available`, available discrete set of sampling | |
| frequency values for device. | |
| * Available standard attributes for IIO devices are described in the | |
| :file:`Documentation/ABI/testing/sysfs-bus-iio` file in the Linux kernel | |
| sources. | |
| IIO device channels | |
| =================== | |
| struct :c:type:`iio_chan_spec` - specification of a single channel | |
| An IIO device channel is a representation of a data channel. An IIO device can | |
| have one or multiple channels. For example: | |
| * a thermometer sensor has one channel representing the temperature measurement. | |
| * a light sensor with two channels indicating the measurements in the visible | |
| and infrared spectrum. | |
| * an accelerometer can have up to 3 channels representing acceleration on X, Y | |
| and Z axes. | |
| An IIO channel is described by the struct :c:type:`iio_chan_spec`. | |
| A thermometer driver for the temperature sensor in the example above would | |
| have to describe its channel as follows:: | |
| static const struct iio_chan_spec temp_channel[] = { | |
| { | |
| .type = IIO_TEMP, | |
| .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), | |
| }, | |
| }; | |
| Channel sysfs attributes exposed to userspace are specified in the form of | |
| bitmasks. Depending on their shared info, attributes can be set in one of the | |
| following masks: | |
| * **info_mask_separate**, attributes will be specific to | |
| this channel | |
| * **info_mask_shared_by_type**, attributes are shared by all channels of the | |
| same type | |
| * **info_mask_shared_by_dir**, attributes are shared by all channels of the same | |
| direction | |
| * **info_mask_shared_by_all**, attributes are shared by all channels | |
| When there are multiple data channels per channel type we have two ways to | |
| distinguish between them: | |
| * set **.modified** field of :c:type:`iio_chan_spec` to 1. Modifiers are | |
| specified using **.channel2** field of the same :c:type:`iio_chan_spec` | |
| 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. | |
| * set **.indexed** field of :c:type:`iio_chan_spec` to 1. In this case the | |
| channel is simply another instance with an index specified by the **.channel** | |
| field. | |
| Here is how we can make use of the channel's modifiers:: | |
| 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), | |
| }, | |
| } | |
| This channel's definition will generate two separate sysfs files for raw data | |
| retrieval: | |
| * :file:`/sys/bus/iio/iio:device{X}/in_intensity_ir_raw` | |
| * :file:`/sys/bus/iio/iio:device{X}/in_intensity_both_raw` | |
| one file for processed data: | |
| * :file:`/sys/bus/iio/iio:device{X}/in_illuminance_input` | |
| and one shared sysfs file for sampling frequency: | |
| * :file:`/sys/bus/iio/iio:device{X}/sampling_frequency`. | |
| Here is how we can make use of the channel's indexing:: | |
| 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), | |
| }, | |
| } | |
| This will generate two separate attributes files for raw data retrieval: | |
| * :file:`/sys/bus/iio/devices/iio:device{X}/in_voltage0_raw`, representing | |
| voltage measurement for channel 0. | |
| * :file:`/sys/bus/iio/devices/iio:device{X}/in_voltage1_raw`, representing | |
| voltage measurement for channel 1. | |
| More details | |
| ============ | |
| .. kernel-doc:: include/linux/iio/iio.h | |
| .. kernel-doc:: drivers/iio/industrialio-core.c | |
| :export: |