162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2016 Jonathan Cameron <jic23@kernel.org>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Based on a mashup of the hrtimer trigger and continuous sampling proposal of
662306a36Sopenharmony_ci * Gregor Boirie <gregor.boirie@parrot.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Note this is still rather experimental and may eat babies.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Todo
1162306a36Sopenharmony_ci * * Protect against connection of devices that 'need' the top half
1262306a36Sopenharmony_ci *   handler.
1362306a36Sopenharmony_ci * * Work out how to run top half handlers in this context if it is
1462306a36Sopenharmony_ci *   safe to do so (timestamp grabbing for example)
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Tested against a max1363. Used about 33% cpu for the thread and 20%
1762306a36Sopenharmony_ci * for generic_buffer piping to /dev/null. Watermark set at 64 on a 128
1862306a36Sopenharmony_ci * element kfifo buffer.
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/kernel.h>
2262306a36Sopenharmony_ci#include <linux/module.h>
2362306a36Sopenharmony_ci#include <linux/platform_device.h>
2462306a36Sopenharmony_ci#include <linux/slab.h>
2562306a36Sopenharmony_ci#include <linux/irq_work.h>
2662306a36Sopenharmony_ci#include <linux/kthread.h>
2762306a36Sopenharmony_ci#include <linux/freezer.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <linux/iio/iio.h>
3062306a36Sopenharmony_ci#include <linux/iio/trigger.h>
3162306a36Sopenharmony_ci#include <linux/iio/sw_trigger.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistruct iio_loop_info {
3462306a36Sopenharmony_ci	struct iio_sw_trigger swt;
3562306a36Sopenharmony_ci	struct task_struct *task;
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic const struct config_item_type iio_loop_type = {
3962306a36Sopenharmony_ci	.ct_owner = THIS_MODULE,
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic int iio_loop_thread(void *data)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct iio_trigger *trig = data;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	set_freezable();
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	do {
4962306a36Sopenharmony_ci		iio_trigger_poll_nested(trig);
5062306a36Sopenharmony_ci	} while (likely(!kthread_freezable_should_stop(NULL)));
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	return 0;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic int iio_loop_trigger_set_state(struct iio_trigger *trig, bool state)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct iio_loop_info *loop_trig = iio_trigger_get_drvdata(trig);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (state) {
6062306a36Sopenharmony_ci		loop_trig->task = kthread_run(iio_loop_thread,
6162306a36Sopenharmony_ci					      trig, trig->name);
6262306a36Sopenharmony_ci		if (IS_ERR(loop_trig->task)) {
6362306a36Sopenharmony_ci			dev_err(&trig->dev,
6462306a36Sopenharmony_ci				"failed to create trigger loop thread\n");
6562306a36Sopenharmony_ci			return PTR_ERR(loop_trig->task);
6662306a36Sopenharmony_ci		}
6762306a36Sopenharmony_ci	} else {
6862306a36Sopenharmony_ci		kthread_stop(loop_trig->task);
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return 0;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic const struct iio_trigger_ops iio_loop_trigger_ops = {
7562306a36Sopenharmony_ci	.set_trigger_state = iio_loop_trigger_set_state,
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic struct iio_sw_trigger *iio_trig_loop_probe(const char *name)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	struct iio_loop_info *trig_info;
8162306a36Sopenharmony_ci	int ret;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
8462306a36Sopenharmony_ci	if (!trig_info)
8562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	trig_info->swt.trigger = iio_trigger_alloc(NULL, "%s", name);
8862306a36Sopenharmony_ci	if (!trig_info->swt.trigger) {
8962306a36Sopenharmony_ci		ret = -ENOMEM;
9062306a36Sopenharmony_ci		goto err_free_trig_info;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	iio_trigger_set_drvdata(trig_info->swt.trigger, trig_info);
9462306a36Sopenharmony_ci	trig_info->swt.trigger->ops = &iio_loop_trigger_ops;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	ret = iio_trigger_register(trig_info->swt.trigger);
9762306a36Sopenharmony_ci	if (ret)
9862306a36Sopenharmony_ci		goto err_free_trigger;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	iio_swt_group_init_type_name(&trig_info->swt, name, &iio_loop_type);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return &trig_info->swt;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cierr_free_trigger:
10562306a36Sopenharmony_ci	iio_trigger_free(trig_info->swt.trigger);
10662306a36Sopenharmony_cierr_free_trig_info:
10762306a36Sopenharmony_ci	kfree(trig_info);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return ERR_PTR(ret);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic int iio_trig_loop_remove(struct iio_sw_trigger *swt)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct iio_loop_info *trig_info;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	trig_info = iio_trigger_get_drvdata(swt->trigger);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	iio_trigger_unregister(swt->trigger);
11962306a36Sopenharmony_ci	iio_trigger_free(swt->trigger);
12062306a36Sopenharmony_ci	kfree(trig_info);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return 0;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic const struct iio_sw_trigger_ops iio_trig_loop_ops = {
12662306a36Sopenharmony_ci	.probe = iio_trig_loop_probe,
12762306a36Sopenharmony_ci	.remove = iio_trig_loop_remove,
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic struct iio_sw_trigger_type iio_trig_loop = {
13162306a36Sopenharmony_ci	.name = "loop",
13262306a36Sopenharmony_ci	.owner = THIS_MODULE,
13362306a36Sopenharmony_ci	.ops = &iio_trig_loop_ops,
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cimodule_iio_sw_trigger_driver(iio_trig_loop);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ciMODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
13962306a36Sopenharmony_ciMODULE_DESCRIPTION("Loop based trigger for the iio subsystem");
14062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
14162306a36Sopenharmony_ciMODULE_ALIAS("platform:iio-trig-loop");
142