linux/drivers/iio/trigger/iio-trig-loop.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright 2016 Jonathan Cameron <jic23@kernel.org>
   4 *
   5 * Based on a mashup of the hrtimer trigger and continuous sampling proposal of
   6 * Gregor Boirie <gregor.boirie@parrot.com>
   7 *
   8 * Note this is still rather experimental and may eat babies.
   9 *
  10 * Todo
  11 * * Protect against connection of devices that 'need' the top half
  12 *   handler.
  13 * * Work out how to run top half handlers in this context if it is
  14 *   safe to do so (timestamp grabbing for example)
  15 *
  16 * Tested against a max1363. Used about 33% cpu for the thread and 20%
  17 * for generic_buffer piping to /dev/null. Watermark set at 64 on a 128
  18 * element kfifo buffer.
  19 */
  20
  21#include <linux/kernel.h>
  22#include <linux/module.h>
  23#include <linux/platform_device.h>
  24#include <linux/slab.h>
  25#include <linux/irq_work.h>
  26#include <linux/kthread.h>
  27#include <linux/freezer.h>
  28
  29#include <linux/iio/iio.h>
  30#include <linux/iio/trigger.h>
  31#include <linux/iio/sw_trigger.h>
  32
  33struct iio_loop_info {
  34        struct iio_sw_trigger swt;
  35        struct task_struct *task;
  36};
  37
  38static const struct config_item_type iio_loop_type = {
  39        .ct_owner = THIS_MODULE,
  40};
  41
  42static int iio_loop_thread(void *data)
  43{
  44        struct iio_trigger *trig = data;
  45
  46        set_freezable();
  47
  48        do {
  49                iio_trigger_poll_chained(trig);
  50        } while (likely(!kthread_freezable_should_stop(NULL)));
  51
  52        return 0;
  53}
  54
  55static int iio_loop_trigger_set_state(struct iio_trigger *trig, bool state)
  56{
  57        struct iio_loop_info *loop_trig = iio_trigger_get_drvdata(trig);
  58
  59        if (state) {
  60                loop_trig->task = kthread_run(iio_loop_thread,
  61                                              trig, trig->name);
  62                if (IS_ERR(loop_trig->task)) {
  63                        dev_err(&trig->dev,
  64                                "failed to create trigger loop thread\n");
  65                        return PTR_ERR(loop_trig->task);
  66                }
  67        } else {
  68                kthread_stop(loop_trig->task);
  69        }
  70
  71        return 0;
  72}
  73
  74static const struct iio_trigger_ops iio_loop_trigger_ops = {
  75        .set_trigger_state = iio_loop_trigger_set_state,
  76};
  77
  78static struct iio_sw_trigger *iio_trig_loop_probe(const char *name)
  79{
  80        struct iio_loop_info *trig_info;
  81        int ret;
  82
  83        trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
  84        if (!trig_info)
  85                return ERR_PTR(-ENOMEM);
  86
  87        trig_info->swt.trigger = iio_trigger_alloc(NULL, "%s", name);
  88        if (!trig_info->swt.trigger) {
  89                ret = -ENOMEM;
  90                goto err_free_trig_info;
  91        }
  92
  93        iio_trigger_set_drvdata(trig_info->swt.trigger, trig_info);
  94        trig_info->swt.trigger->ops = &iio_loop_trigger_ops;
  95
  96        ret = iio_trigger_register(trig_info->swt.trigger);
  97        if (ret)
  98                goto err_free_trigger;
  99
 100        iio_swt_group_init_type_name(&trig_info->swt, name, &iio_loop_type);
 101
 102        return &trig_info->swt;
 103
 104err_free_trigger:
 105        iio_trigger_free(trig_info->swt.trigger);
 106err_free_trig_info:
 107        kfree(trig_info);
 108
 109        return ERR_PTR(ret);
 110}
 111
 112static int iio_trig_loop_remove(struct iio_sw_trigger *swt)
 113{
 114        struct iio_loop_info *trig_info;
 115
 116        trig_info = iio_trigger_get_drvdata(swt->trigger);
 117
 118        iio_trigger_unregister(swt->trigger);
 119        iio_trigger_free(swt->trigger);
 120        kfree(trig_info);
 121
 122        return 0;
 123}
 124
 125static const struct iio_sw_trigger_ops iio_trig_loop_ops = {
 126        .probe = iio_trig_loop_probe,
 127        .remove = iio_trig_loop_remove,
 128};
 129
 130static struct iio_sw_trigger_type iio_trig_loop = {
 131        .name = "loop",
 132        .owner = THIS_MODULE,
 133        .ops = &iio_trig_loop_ops,
 134};
 135
 136module_iio_sw_trigger_driver(iio_trig_loop);
 137
 138MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 139MODULE_DESCRIPTION("Loop based trigger for the iio subsystem");
 140MODULE_LICENSE("GPL v2");
 141MODULE_ALIAS("platform:iio-trig-loop");
 142