brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · 575d725 Raw
226 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright 2011 Analog Devices Inc.4 */5 6#include <linux/kernel.h>7#include <linux/module.h>8#include <linux/platform_device.h>9#include <linux/slab.h>10#include <linux/list.h>11#include <linux/irq_work.h>12 13#include <linux/iio/iio.h>14#include <linux/iio/trigger.h>15 16struct iio_sysfs_trig {17	struct iio_trigger *trig;18	struct irq_work work;19	int id;20	struct list_head l;21};22 23static LIST_HEAD(iio_sysfs_trig_list);24static DEFINE_MUTEX(iio_sysfs_trig_list_mut);25 26static int iio_sysfs_trigger_probe(int id);27static ssize_t iio_sysfs_trig_add(struct device *dev,28				  struct device_attribute *attr,29				  const char *buf,30				  size_t len)31{32	int ret;33	unsigned long input;34 35	ret = kstrtoul(buf, 10, &input);36	if (ret)37		return ret;38	ret = iio_sysfs_trigger_probe(input);39	if (ret)40		return ret;41	return len;42}43static DEVICE_ATTR(add_trigger, S_IWUSR, NULL, &iio_sysfs_trig_add);44 45static int iio_sysfs_trigger_remove(int id);46static ssize_t iio_sysfs_trig_remove(struct device *dev,47				     struct device_attribute *attr,48				     const char *buf,49				     size_t len)50{51	int ret;52	unsigned long input;53 54	ret = kstrtoul(buf, 10, &input);55	if (ret)56		return ret;57	ret = iio_sysfs_trigger_remove(input);58	if (ret)59		return ret;60	return len;61}62 63static DEVICE_ATTR(remove_trigger, S_IWUSR, NULL, &iio_sysfs_trig_remove);64 65static struct attribute *iio_sysfs_trig_attrs[] = {66	&dev_attr_add_trigger.attr,67	&dev_attr_remove_trigger.attr,68	NULL,69};70 71static const struct attribute_group iio_sysfs_trig_group = {72	.attrs = iio_sysfs_trig_attrs,73};74 75static const struct attribute_group *iio_sysfs_trig_groups[] = {76	&iio_sysfs_trig_group,77	NULL78};79 80 81/* Nothing to actually do upon release */82static void iio_trigger_sysfs_release(struct device *dev)83{84}85 86static struct device iio_sysfs_trig_dev = {87	.bus = &iio_bus_type,88	.groups = iio_sysfs_trig_groups,89	.release = &iio_trigger_sysfs_release,90};91 92static void iio_sysfs_trigger_work(struct irq_work *work)93{94	struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig,95							work);96 97	iio_trigger_poll(trig->trig);98}99 100static ssize_t iio_sysfs_trigger_poll(struct device *dev,101		struct device_attribute *attr, const char *buf, size_t count)102{103	struct iio_trigger *trig = to_iio_trigger(dev);104	struct iio_sysfs_trig *sysfs_trig = iio_trigger_get_drvdata(trig);105 106	irq_work_queue(&sysfs_trig->work);107 108	return count;109}110 111static DEVICE_ATTR(trigger_now, S_IWUSR, NULL, iio_sysfs_trigger_poll);112 113static struct attribute *iio_sysfs_trigger_attrs[] = {114	&dev_attr_trigger_now.attr,115	NULL,116};117 118static const struct attribute_group iio_sysfs_trigger_attr_group = {119	.attrs = iio_sysfs_trigger_attrs,120};121 122static const struct attribute_group *iio_sysfs_trigger_attr_groups[] = {123	&iio_sysfs_trigger_attr_group,124	NULL125};126 127static int iio_sysfs_trigger_probe(int id)128{129	struct iio_sysfs_trig *t;130	int ret;131	bool foundit = false;132 133	mutex_lock(&iio_sysfs_trig_list_mut);134	list_for_each_entry(t, &iio_sysfs_trig_list, l)135		if (id == t->id) {136			foundit = true;137			break;138		}139	if (foundit) {140		ret = -EINVAL;141		goto err_unlock;142	}143	t = kmalloc(sizeof(*t), GFP_KERNEL);144	if (t == NULL) {145		ret = -ENOMEM;146		goto err_unlock;147	}148	t->id = id;149	t->trig = iio_trigger_alloc(&iio_sysfs_trig_dev, "sysfstrig%d", id);150	if (!t->trig) {151		ret = -ENOMEM;152		goto err_free_sys_trig;153	}154 155	t->trig->dev.groups = iio_sysfs_trigger_attr_groups;156	iio_trigger_set_drvdata(t->trig, t);157 158	t->work = IRQ_WORK_INIT_HARD(iio_sysfs_trigger_work);159 160	ret = iio_trigger_register(t->trig);161	if (ret)162		goto err_free_trig;163	list_add(&t->l, &iio_sysfs_trig_list);164	__module_get(THIS_MODULE);165	mutex_unlock(&iio_sysfs_trig_list_mut);166	return 0;167 168err_free_trig:169	iio_trigger_free(t->trig);170err_free_sys_trig:171	kfree(t);172err_unlock:173	mutex_unlock(&iio_sysfs_trig_list_mut);174	return ret;175}176 177static int iio_sysfs_trigger_remove(int id)178{179	struct iio_sysfs_trig *t = NULL, *iter;180 181	mutex_lock(&iio_sysfs_trig_list_mut);182	list_for_each_entry(iter, &iio_sysfs_trig_list, l)183		if (id == iter->id) {184			t = iter;185			break;186		}187	if (!t) {188		mutex_unlock(&iio_sysfs_trig_list_mut);189		return -EINVAL;190	}191 192	iio_trigger_unregister(t->trig);193	irq_work_sync(&t->work);194	iio_trigger_free(t->trig);195 196	list_del(&t->l);197	kfree(t);198	module_put(THIS_MODULE);199	mutex_unlock(&iio_sysfs_trig_list_mut);200	return 0;201}202 203 204static int __init iio_sysfs_trig_init(void)205{206	int ret;207	device_initialize(&iio_sysfs_trig_dev);208	dev_set_name(&iio_sysfs_trig_dev, "iio_sysfs_trigger");209	ret = device_add(&iio_sysfs_trig_dev);210	if (ret)211		put_device(&iio_sysfs_trig_dev);212	return ret;213}214module_init(iio_sysfs_trig_init);215 216static void __exit iio_sysfs_trig_exit(void)217{218	device_unregister(&iio_sysfs_trig_dev);219}220module_exit(iio_sysfs_trig_exit);221 222MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");223MODULE_DESCRIPTION("Sysfs based trigger for the iio subsystem");224MODULE_LICENSE("GPL v2");225MODULE_ALIAS("platform:iio-trig-sysfs");226