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