Triggered buffer support trigger buffer support for IIO subsystem of Linux device driver

Keywords: Linux Attribute

Triggered buffer support triggers buffer support

In many data analysis applications, it is useful to capture data based on some external signals (triggers). These triggers may be:

    • Data Readiness Signal
    • IRQ lines (GPIO or others) connected to an external system
    • Processor periodic interrupt
    • User Space Reads/Writes Specific Files in sysfs

IIO device drivers have nothing to do with triggers. Triggers can initialize data capture on one or more devices. These triggers are used to fill the buffer and then expose it to user space as character devices.

You can develop your own trigger driver, but that's beyond the scope of this book. We will try to focus only on the existing ones. These are:

  • Iio-trig-interrupt: This supports the use of any IRQ as an IIO trigger. In the old version of the kernel, it used to be iio-trig-gpio. The kernel option to enable this trigger mode is CONFIG_IIO_INTERRUPT_TRIGGER. If built as a module, the module will be called iio-trig-interrupt.
  • Iio-trig-hrtimer: This provides a frequency-based IIO trigger that uses HRT as an interrupt source (because the kernel v4.5). In older kernel versions, it used to be iio-trig-rtc. The kernel option responsible for this trigger mode is IIO_HRTIMER_TRIGGER. If built as a module, the module will be called iio-trig-hrtimer.
  • iio-trig-sysfs: This allows us to use sysfs entries to trigger data capture. CONFIG_IIO_SYSFS_TRIGGER is the kernel option to add support for this trigger mode.
  • iio-trig-bfin-timer: This allows us to use the blackfin timer as an IIO trigger (still in the staging folder).

Using IIO's open API, we can:

  • Declare any given number of triggers
  • Select the channel to push its data into the buffer

When your IIO device supports trigger buffer, you must set iio_dev.pollfunc, which executes when trigger triggers. This handler is responsible for finding enabled channels through indio_dev-> active_scan_mask, retrieving their data, and providing them to indio_dev-> buffer using the iio_push_to_buffers_with_timestamp function. Therefore, buffers and triggers need to be connected in the IIO subsystem.

The IIO core provides a set of auxiliary functions to set the trigger buffer, which can be found in drivers/iio/industrialio-triggered-buffer.c.

Following are the steps to support triggering buffers from the driver:

1. Fill in the iio_buffer_setup_ops structure if necessary:

1 const struct iio_buffer_setup_ops sensor_buffer_setup_ops = {
2   .preenable    = my_sensor_buffer_preenable,
3   .postenable   = my_sensor_buffer_postenable,
4   .postdisable  = my_sensor_buffer_postdisable,
5   .predisable   = my_sensor_buffer_predisable,
6 };

2. Write down the top half of the trigger. In 99% of cases, only the Capture-Related timestamps need to be provided:

1 irqreturn_t sensor_iio_pollfunc(int irq, void *p)
2 {
3     pf->timestamp = iio_get_time_ns((struct indio_dev *)p);
4     return IRQ_WAKE_THREAD;
5 }

3. Write to the lower half of the trigger, which will retrieve data from each enabled channel and provide them to the buffer:

 1 irqreturn_t sensor_trigger_handler(int irq, void *p)
 2 {
 3     u16 buf[8];
 4     int bit, i = 0;
 5     struct iio_poll_func *pf = p;
 6     struct iio_dev *indio_dev = pf->indio_dev;
 7 
 8     /* one can use lock here to protect the buffer */
 9     /* mutex_lock(&my_mutex); */ 
10     /* read data for each active channel */
11     for_each_set_bit(bit, indio_dev->active_scan_mask,
12                      indio_dev->masklength)
13         buf[i++] = sensor_get_data(bit) 
14 
15     /*
16      * If iio_dev.scan_timestamp = true, the capture timestamp
17      * will be pushed and stored too, as the last element in the
18      * sample data buffer before pushing it to the device buffers.
19      */
20     iio_push_to_buffers_with_timestamp(indio_dev, buf, timestamp);
21 
22     /* Please unlock any lock */
23 
24     /* mutex_unlock(&my_mutex); */
25 
26     /* Notify trigger */
27 
28     iio_trigger_notify_done(indio_dev->trig);
29     return IRQ_HANDLED;
30 }

4. Finally, in the probe function, flip-flops and buffers must be connected before the device is registered using iio_device_register():

iio_triggered_buffer_setup(indio_dev, sensor_iio_polfunc,
                           sensor_trigger_handler,
                           sensor_buffer_setup_ops);

 

The magic function here is iio_triggered_buffer_setup. This will also provide INDIO_DIRECT_MODE functionality for your device. When a trigger (from user space) connects to your device, you cannot know when to trigger the capture.

When continuous buffer capture is active, sysfs data capture per channel (performed by read_raw() hook) should be prevented by the driver (by returning errors) to avoid undetermined behavior, because trigger handlers and read_raw() hooks attempt to access the device simultaneously. The function used to check whether the buffer mode is actually used is iio_buffer_enabled(). The hook looks like this:

       

static int my_read_raw(struct iio_dev *indio_dev,
                     const struct iio_chan_spec *chan,
                     int *val, int *val2, long mask)
{
      [...]
      switch (mask) {
     case IIO_CHAN_INFO_RAW:
            if (iio_buffer_enabled(indio_dev))
                  return -EBUSY;
      [...]       
}

The iio_buffer_enabled() function simply determines whether a buffer is enabled for a given IIO device.

Some important matters in use:

iio_buffer_setup_ops provides a buffer setup function to be invoked in a fixed step (before/after enabling/disabling) of the buffer configuration sequence. If not specified, the IIO kernel will provide default iio_triggered_buffer_setup_ops for your device.

sensor_iio_pollfunc is the upper half of the trigger. Like each first half, it runs in the interrupt context and must be handled as little as possible. In 99% of cases, you only need to provide time stamps related to capture. Again, you can use the default IIO iio_pollfunc_store_time function.

sensor_trigger_handler is the second half, which runs in the kernel thread, allowing us to do anything, including even get mutex or sleep. The reprocessing should be done here. It usually reads data from the device and stores it in the internal buffer with the timestamp recorded in the first half and pushes it to the IIO device buffer.

Note: Trigger buffers must be used. It tells the driver when to read the sample from the device and put it in the buffer. Trigger buffering is not necessary for writing IIO device drivers. By reading the original properties of the channel, you can also use a single capture through sysf, which only performs a single conversion (for the channel properties being read). Buffer mode allows continuous conversion to capture multiple channels at a single time.

      

IIO trigger and sysfs (user space) user space triggers and sysfs

There are two trigger-related locations in sysfs:

    • / sys/bus/iio/devices/triggerY/: Once an IIO trigger is registered with the IIO core and corresponds to a trigger indexed to Y, the directory is created. There is at least one attribute in the directory:
      • Name: This is the name of the trigger that can be used later to associate with the device
      • Another possibility is sampling frequency or something, which is related to the type of trigger.
    • / sys/bus/iio/devices/iio:deviceX/trigger/* If your device supports trigger buffers, directories will be created automatically. By writing the name of the trigger in the current_trigger file, we can associate the trigger with our device.

Sysfs trigger interface Sysfs trigger interface

By enabling sysfs trigger in the kernel with the CONFIG_IIO_SYSFS_TRIGGER = y config option, the / sys/bus/iio/devices/iio_sysfs_trigger/folder will be automatically created and can be used for sysfs trigger management. There will be two files in the directory, add_trigger and remove_trigger. Its driver is in drivers/iio/trigger/iio-trig-sysfs.c.

 add_trigger file

This is used to create a new sysfs trigger. You can create a new trigger by writing a positive value (which will be used as a trigger ID) to the file. It will create a new sysfs trigger that can be accessed in / sys / bus / iio / devices / triggerX, where X is the trigger number.

For example: echo 2 > add_trigger

This will create a new sysfs trigger that can be accessed in / sys / bus / iio / devices / trigger2. If a trigger with a specified ID already exists in the system, an invalid parameter message will be returned. The name mode of sysfs trigger is sysfstrig {ID}. The command echo 2 > add_trigger creates trigger / sys / bus / iio / devices / trigger2 named sysfstrig 2:

$ cat /sys/bus/iio/devices/trigger2/name
 sysfstrig2

 

Each sysfs trigger contains at least one file: trigger_now. Writing 1 to this file will indicate that all devices with the corresponding trigger name in their current_trigger start capturing and push the data into their respective buffers. Each device buffer must be sized and enabled (echo 1 >/ sys / bus / IIO / devices / iio: deviceX / buffer / enable).

remove_trigger file

To delete triggers, use the following commands:

  # echo 2 > remove_trigger

 

Binding devices with triggers

Associating a device with a given trigger includes writing the name of the trigger to the current_trigger file available in the device trigger directory. For example, suppose we need to bind the device to a trigger with index 2:

# set trigger2 as current trigger for device0

# echo sysfstrig2 >    /sys/bus/iio/devices/iio:device0/trigger/current_trigger

To separate triggers from devices, an empty string should be written to the current_trigger file in the device trigger directory, as follows:

# echo "" > iio:device0/trigger/current_trigger

In the next section, we'll see a more practical example of a sysfs trigger that handles data capture.

 

The interrupt trigger interface interrupt trigger interface

Consider the following code examples

static struct resource iio_irq_trigger_resources[] = {
    [0] = {
        .start = IRQ_NR_FOR_YOUR_IRQ,
        .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
           },
};

static struct platform_device iio_irq_trigger = {
    .name = "iio_interrupt_trigger",
    .num_resources = ARRAY_SIZE(iio_irq_trigger_resources),
    .resource = iio_irq_trigger_resources,
};

platform_device_register(&iio_irq_trigger);

Declare our IRQ trigger, which will load the IRQ trigger independent module. If its detection function is successful, there will be a directory corresponding to the trigger. The IRQ trigger name is in the form of irqtrigX, where X corresponds to the virtual IRQ just passed, as you will see in / proc / interrupt:

$ cd /sys/bus/iio/devices/trigger0/
 $ cat name

As we have done with other triggers, you can assign the trigger to your device simply by assigning the trigger to the device current_trigger file.

# echo "irqtrig85" > /sys/bus/iio/devices/iio:device0/trigger/current_trigger

Now, device data is captured every time an interrupt is triggered.

Note: IRQ trigger driver does not support DT yet, which is why we use board init file. But that doesn't matter; because the driver needs resources, we can use DT without changing any code.

The following is an example of a device tree node that declares an IRQ trigger interface:

  mylabel: my_trigger@0{
           compatible = "iio_interrupt_trigger";
           interrupt-parent = <&gpio4>;
           interrupts = <30 0x0>;
};

This example assumes that the IRQ line is GPIO #30 belonging to GPIO controller node gpio4. This includes using GPIO as an interrupt source so that whenever GPIO becomes a given state, interrupts are triggered, triggering capture.

 

 

hrtimer trigger interface (may not be supported below 4.5 kernel)

The hrtimer trigger relies on the configfs file system (see Documentation/iio/iio_configfs.txt in the kernel source code) and can be enabled through the CONFIG_IIO_CONFIGFS configuration option and mounted on our system (usually in the / config directory):

# mkdir /config
# mount -t configfs none /config

Now, the loading module iio-trig-hrtimer will create an accessible IIO group under / config / iio, allowing users to create hrtimer triggers under / config / iio / triggers / hrtimer. Such as:

# create a hrtimer trigger
$ mkdir /config/iio/triggers/hrtimer/my_trigger_name
# remove the trigger
$ rmdir /config/iio/triggers/hrtimer/my_trigger_name

Each hrtimer trigger contains a single sampling_frequency attribute in the trigger directory (/ sys/bus/iio/devices/triggerY/folder). A complete and effective example is further provided in the section on data capture using hrtimer triggers.

 

IIO buffers IIO buffer

IIO buffer provides continuous data capture and can read multiple data channels at the same time. Buffers can be accessed from user space through / dev / iio:device character device nodes. In the trigger handler, the function used to fill the buffer is iio_push_to_buffers_with_timestamp. The function responsible for assigning trigger buffers to your device is iio_triggered_buffer_setup().

 

IIO buffer sysfs interface

The IIO buffer has an associated property directory under / sys / bus / iio / iio: deviceX / buffer *. The following are some existing attributes:

  • length: The total number of data samples (capacity) that the buffer can store. This is the number of scans contained in the buffer.
  • enable: This will activate buffer capture and start buffer capture.
  • watermark: This property has been available since the kernel version v4.2. It is a positive number that specifies the number of scan elements to wait for blocking reads. For example, if polling is used, it will block until the watermarking is reached. It only makes sense if the watermarking is larger than the amount of read requested. It does not affect non-blocking reads. Polling can be blocked when the timeout expires and available samples can be read after the timeout expires, thus guaranteeing maximum latency.

IIO Buffer Settings

The channel where data is to be read and pushed into the buffer is called scan element. Their configuration can be accessed from user space through the / sys / bus / iio / iio: deviceX / scan_elements / * directory, which contains the following attributes:

  • EN (actually the suffix of the attribute name) is used to enable channels. If and only if its attribute is non-zero, trigger capture will contain the data sample of this channel. For example, in_voltage 0_en, in_voltage 1_en, etc.
  • Type describes the scan element data store in the buffer, so it describes the form of reading it from user space. For example, in_voltage 0_type. The format is [be | le]:

    [s|u]bits/storagebitsXrepeat[>>shift].

    • be or le specifies byte order (large or small)
    • s or u specifies symbols (signed (complement of 2) or unsigned).
    • Bits are the number of valid data bits.
    • storagebits: The number of digits occupied by this channel in the buffer. That is to say, a value can be really encoded with 12 bits, but it occupies 16 bits (storage bits) in the buffer. Therefore, the data must be moved four times to the right to get the actual value. This parameter depends on the device and should refer to its data sheet.
    • Shift: Represents the number of times data values should be shifted before masking unused bits. This parameter is not always required. If the number of valid bits equals the number of storage bits, the shift will be 0. This parameter can also be found in the device data manual.
    • Repeat specifies the number of bit/memory repeats. When the repeat element is 0 or 1, duplicate values are omitted.

The best way to explain this part is through excerpts from the kernel document, which can be found here: https://www.kernel.org/doc/html/latest/driver-api/iio/buffers.html. For example, the driver for a 3-axis accelerometer has a 12-bit resolution in which data is stored in two 8-bit registers, as follows:

      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)

    +---+---+---+---+---+---+---+---+

Each axis will have the following scanning element types:

$ cat /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_y_type
     le:s12/16>>4

It should be interpreted as 16-bit small-end symbolic data, which needs to be shifted 4 bits to the right before masking 12 valid data bits.

In struct iio_chan_spec, the element responsible for determining how to store the value of the channel into the buffer is scant_type.

struct iio_chan_spec {
        [...]
        struct {
            char sign; /* Should be 'u' or 's' as explained above */
            u8 realbits;
            u8 storagebits;
            u8 shift;
            u8 repeat;
            enum iio_endian endianness;
        } scan_type;
        [...]
};

This structure absolutely matches [be | le]: [s | u] bits / storage bits Xrepeat [> shift], which is the pattern described in the previous section. Let's look at each member of the structure:

    • sign represents the symbols of the data and matches [s | u] in the pattern
    • realbits correspond to bits in the pattern
    • storagebits match the same name in the schema
    • Shift corresponds to the shift of the pattern and repeats the same
    • iio_indian denotes byte order and matches [be | le] in the pattern

At this point, IIO channel structures corresponding to the types explained above can be written:

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,
                        .storagebits = 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
       */
}

 

Putting it all together

Let's take a closer look at the digital three-axis accelerometer BMA220 of BOSH. This is a SPI/I2C compatible device with 8-bit registers and on-chip motion trigger interrupt controller, which can actually induce tilt, motion and shock vibration. Its data sheet can be obtained from the following websites: http://www.mouser.fr/pdfdocs/BSTBMA220DS00308.PDF, and its driver has been introduced from the kernel v4.8 (CONFIG_BMA200). Let's take a look at:

First, we declare our IIO channel using struct iio_chan_spec. Once the trigger buffer is used, we need to fill in the. scan_index and. scan_type fields:

#define BMA220_DATA_SHIFT 2
#define BMA220_DEVICE_NAME "bma220"
#define BMA220_SCALE_AVAILABLE "0.623 1.248 2.491 4.983"

#define BMA220_ACCEL_CHANNEL(index, reg, axis) {           \
   .type = IIO_ACCEL,                                      \
   .address = reg,                                         \
   .modified = 1,                                          \
   .channel2 = IIO_MOD_##axis,                             \
   .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
   .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
   .scan_index = index,                                    \
   .scan_type = {                                          \
         .sign = 's',                                      \
         .realbits = 6,                                    \
         .storagebits = 8,                                 \
         .shift = BMA220_DATA_SHIFT,                       \
         .endianness = IIO_CPU,                            \
   },                                                      \
}

static const struct iio_chan_spec bma220_channels[] = {
   BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X),
   BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y),
   BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z),
};

info_mask_separate = BIT (IIO_CHAN_INFO_RAW) means that each channel has a *_raw sysfs entry (attribute), while. info_mask_shared_by_type = BIT (IIO_CHAN_INFO_SCALE) means that all channels of the same type have only one *_scale_sysfs entry:

jma@jma:~$ ls -l /sys/bus/iio/devices/iio:device0/
(...)
# without modifier, a channel name would have in_accel_raw (bad)
-rw-r--r-- 1 root root 4096 jul 20 14:13 in_accel_scale
-rw-r--r-- 1 root root 4096 jul 20 14:13 in_accel_x_raw
-rw-r--r-- 1 root root 4096 jul 20 14:13 in_accel_y_raw
-rw-r--r-- 1 root root 4096 jul 20 14:13 in_accel_z_raw
(...)

Reading in_accel_scale calls the read_raw() hook and sets the mask to IIO_CHAN_INFO_SCALE. Reading in_accel_x_ray calls the read_raw() hook and sets the mask to IIO_CHAN_INFO_RAW. Therefore, the actual value is raw_value* scale.

scan_type means that the value returned by each channel is 8 bits in size (8 bits in the buffer will be occupied), but the useful payload only occupies 6 bits, and the data must be moved right twice before masking. Any scan element type will be as follows:

$ cat /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_x_type
le:s6/8>>2

Here's our pollfunc (actually the second half), which reads samples from the device and pushes the read values to the buffer (iio_push_to_buffers_with_timestamp()). Upon completion, we notify the core (iio_trigger_notify_done()):

static irqreturn_t bma220_trigger_handler(int irq, void *p)
{
   int ret;
   struct iio_poll_func *pf = p;
   struct iio_dev *indio_dev = pf->indio_dev;
   struct bma220_data *data = iio_priv(indio_dev);
   struct spi_device *spi = data->spi_device;

   mutex_lock(&data->lock);
   data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK;
   ret = spi_write_then_read(spi, data->tx_buf, 1, data->buffer,
                       ARRAY_SIZE(bma220_channels) - 1);
   if (ret < 0)
         goto err;

   iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
                              pf->timestamp);
err:
   mutex_unlock(&data->lock);
   iio_trigger_notify_done(indio_dev->trig);
   return IRQ_HANDLED;
}

The following is the reading function. It is a hook that is called every time a device's sysfs entry is read:

static int bma220_read_raw(struct iio_dev *indio_dev,
                  struct iio_chan_spec const *chan,
                  int *val, int *val2, long mask)
{
   int ret;
   u8 range_idx
   struct bma220_data *data = iio_priv(indio_dev);

   switch (mask) {
   case IIO_CHAN_INFO_RAW:
           /* If buffer mode enabled, do not process single-channel read */
           if (iio_buffer_enabled(indio_dev))
                   return -EBUSY;
           /* Else we read the channel */
           ret = bma220_read_reg(data->spi_device, chan->address);
           if (ret < 0)
                   return -EINVAL;
           *val = sign_extend32(ret >> BMA220_DATA_SHIFT, 5);

           return IIO_VAL_INT;
   case IIO_CHAN_INFO_SCALE:
           ret = bma220_read_reg(data->spi_device, BMA220_REG_RANGE);
           if (ret < 0)
                   return ret;
           range_idx = ret & BMA220_RANGE_MASK;

           *val = bma220_scale_table[range_idx][0];
           *val2 = bma220_scale_table[range_idx][1];

           return IIO_VAL_INT_PLUS_MICRO;
   }

   return -EINVAL;

}

When reading the * raw sysfs file, call the hook program, give IIO_CHAN_INFO_RAW in the mask parameter, and call the corresponding channel in the * chan parameter. * Val and val2 are actually output parameters. They must be set using the raw value (read from the device). Any reading performed on the * scale sysfs file will use IIO_CHAN_INFO_SCALE call hooks in the mask parameters, and so on for each attribute mask.

The same is true of the write function, which is used to write values to the device. Your driver has an 80% chance of not requiring write functionality. This write hook allows users to change the proportion of devices:

static int bma220_write_raw(struct iio_dev *indio_dev,
                   struct iio_chan_spec const *chan,
                   int val, int val2, long mask)
{
   int i;
   int ret;
   int index = -1;
   struct bma220_data *data = iio_priv(indio_dev);

   switch (mask) {
   case IIO_CHAN_INFO_SCALE:
         for (i = 0; i < ARRAY_SIZE(bma220_scale_table); i++)
               if (val == bma220_scale_table[i][0] &&
                   val2 == bma220_scale_table[i][1]) {
                     index = i;
                     break;
               }
         if (index < 0)
               return -EINVAL;

         mutex_lock(&data->lock);
         data->tx_buf[0] = BMA220_REG_RANGE;
         data->tx_buf[1] = index;
         ret = spi_write(data->spi_device, data->tx_buf,
                     sizeof(data->tx_buf));
         if (ret < 0)
               dev_err(&data->spi_device->dev,
                     "failed to set measurement range\n");
         mutex_unlock(&data->lock);

         return 0;
   }

   return -EINVAL;

}

This function is called as long as the value is written to the device. Frequently changed parameters are proportions. One example might be:

echo <desired-scale> > /sys/bus/iio/devices/iio;devices0/in_accel_scale.

Now, it fills in a structure iio_info, giving our iio_device:

static const struct iio_info bma220_info = {
   .driver_module    = THIS_MODULE,
   .read_raw         = bma220_read_raw,
   .write_raw        = bma220_write_raw, /* Only if your driver need it */
};

In the probe function, we assign and set up a struct iio_dev IIO device. The memory of private data is also retained:

/*
 * We provide only two mask possibility, allowing to select none or every
 * channels.
 */
static const unsigned long bma220_accel_scan_masks[] = {
   BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
   0
};

static int bma220_probe(struct spi_device *spi)

{
   int ret;
   struct iio_dev *indio_dev;
   struct bma220_data *data;

   indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
   if (!indio_dev) {
         dev_err(&spi->dev, "iio allocation failed!\n");
         return -ENOMEM;
   }

   data = iio_priv(indio_dev);
   data->spi_device = spi;
   spi_set_drvdata(spi, indio_dev);
   mutex_init(&data->lock);

   indio_dev->dev.parent = &spi->dev;
   indio_dev->info = &bma220_info;
   indio_dev->name = BMA220_DEVICE_NAME;
   indio_dev->modes = INDIO_DIRECT_MODE;
   indio_dev->channels = bma220_channels;
   indio_dev->num_channels = ARRAY_SIZE(bma220_channels);
   indio_dev->available_scan_masks = bma220_accel_scan_masks;

   ret = bma220_init(data->spi_device);
   if (ret < 0)
         return ret;

   /* this call will enable trigger buffer support for the device */
   ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
                            bma220_trigger_handler, NULL);
   if (ret < 0) {
         dev_err(&spi->dev, "iio triggered buffer setup failed\n");
         goto err_suspend;
   }

   ret = iio_device_register(indio_dev);
   if (ret < 0) {
         dev_err(&spi->dev, "iio_device_register failed\n");
         iio_triggered_buffer_cleanup(indio_dev);
         goto err_suspend;
   }

   return 0;

err_suspend:
   return bma220_deinit(spi);

}

This driver can be enabled through the CONFIG_BMA220 kernel option. That is to say, this can only be provided from v4.8 in the kernel. The closest device that can be used on older kernel versions is BMA180, which can be enabled using the CONFIG_BMA180 option.

Posted by ThunderLee on Tue, 23 Apr 2019 12:30:35 -0700