Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2011 Analog Devices Inc.
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/module.h>
0008 #include <linux/platform_device.h>
0009 #include <linux/slab.h>
0010 #include <linux/list.h>
0011 #include <linux/irq_work.h>
0012 
0013 #include <linux/iio/iio.h>
0014 #include <linux/iio/trigger.h>
0015 
0016 struct iio_sysfs_trig {
0017     struct iio_trigger *trig;
0018     struct irq_work work;
0019     int id;
0020     struct list_head l;
0021 };
0022 
0023 static LIST_HEAD(iio_sysfs_trig_list);
0024 static DEFINE_MUTEX(iio_sysfs_trig_list_mut);
0025 
0026 static int iio_sysfs_trigger_probe(int id);
0027 static ssize_t iio_sysfs_trig_add(struct device *dev,
0028                   struct device_attribute *attr,
0029                   const char *buf,
0030                   size_t len)
0031 {
0032     int ret;
0033     unsigned long input;
0034 
0035     ret = kstrtoul(buf, 10, &input);
0036     if (ret)
0037         return ret;
0038     ret = iio_sysfs_trigger_probe(input);
0039     if (ret)
0040         return ret;
0041     return len;
0042 }
0043 static DEVICE_ATTR(add_trigger, S_IWUSR, NULL, &iio_sysfs_trig_add);
0044 
0045 static int iio_sysfs_trigger_remove(int id);
0046 static ssize_t iio_sysfs_trig_remove(struct device *dev,
0047                      struct device_attribute *attr,
0048                      const char *buf,
0049                      size_t len)
0050 {
0051     int ret;
0052     unsigned long input;
0053 
0054     ret = kstrtoul(buf, 10, &input);
0055     if (ret)
0056         return ret;
0057     ret = iio_sysfs_trigger_remove(input);
0058     if (ret)
0059         return ret;
0060     return len;
0061 }
0062 
0063 static DEVICE_ATTR(remove_trigger, S_IWUSR, NULL, &iio_sysfs_trig_remove);
0064 
0065 static struct attribute *iio_sysfs_trig_attrs[] = {
0066     &dev_attr_add_trigger.attr,
0067     &dev_attr_remove_trigger.attr,
0068     NULL,
0069 };
0070 
0071 static const struct attribute_group iio_sysfs_trig_group = {
0072     .attrs = iio_sysfs_trig_attrs,
0073 };
0074 
0075 static const struct attribute_group *iio_sysfs_trig_groups[] = {
0076     &iio_sysfs_trig_group,
0077     NULL
0078 };
0079 
0080 
0081 /* Nothing to actually do upon release */
0082 static void iio_trigger_sysfs_release(struct device *dev)
0083 {
0084 }
0085 
0086 static struct device iio_sysfs_trig_dev = {
0087     .bus = &iio_bus_type,
0088     .groups = iio_sysfs_trig_groups,
0089     .release = &iio_trigger_sysfs_release,
0090 };
0091 
0092 static void iio_sysfs_trigger_work(struct irq_work *work)
0093 {
0094     struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig,
0095                             work);
0096 
0097     iio_trigger_poll(trig->trig);
0098 }
0099 
0100 static ssize_t iio_sysfs_trigger_poll(struct device *dev,
0101         struct device_attribute *attr, const char *buf, size_t count)
0102 {
0103     struct iio_trigger *trig = to_iio_trigger(dev);
0104     struct iio_sysfs_trig *sysfs_trig = iio_trigger_get_drvdata(trig);
0105 
0106     irq_work_queue(&sysfs_trig->work);
0107 
0108     return count;
0109 }
0110 
0111 static DEVICE_ATTR(trigger_now, S_IWUSR, NULL, iio_sysfs_trigger_poll);
0112 
0113 static struct attribute *iio_sysfs_trigger_attrs[] = {
0114     &dev_attr_trigger_now.attr,
0115     NULL,
0116 };
0117 
0118 static const struct attribute_group iio_sysfs_trigger_attr_group = {
0119     .attrs = iio_sysfs_trigger_attrs,
0120 };
0121 
0122 static const struct attribute_group *iio_sysfs_trigger_attr_groups[] = {
0123     &iio_sysfs_trigger_attr_group,
0124     NULL
0125 };
0126 
0127 static int iio_sysfs_trigger_probe(int id)
0128 {
0129     struct iio_sysfs_trig *t;
0130     int ret;
0131     bool foundit = false;
0132 
0133     mutex_lock(&iio_sysfs_trig_list_mut);
0134     list_for_each_entry(t, &iio_sysfs_trig_list, l)
0135         if (id == t->id) {
0136             foundit = true;
0137             break;
0138         }
0139     if (foundit) {
0140         ret = -EINVAL;
0141         goto out1;
0142     }
0143     t = kmalloc(sizeof(*t), GFP_KERNEL);
0144     if (t == NULL) {
0145         ret = -ENOMEM;
0146         goto out1;
0147     }
0148     t->id = id;
0149     t->trig = iio_trigger_alloc(&iio_sysfs_trig_dev, "sysfstrig%d", id);
0150     if (!t->trig) {
0151         ret = -ENOMEM;
0152         goto free_t;
0153     }
0154 
0155     t->trig->dev.groups = iio_sysfs_trigger_attr_groups;
0156     iio_trigger_set_drvdata(t->trig, t);
0157 
0158     t->work = IRQ_WORK_INIT_HARD(iio_sysfs_trigger_work);
0159 
0160     ret = iio_trigger_register(t->trig);
0161     if (ret)
0162         goto out2;
0163     list_add(&t->l, &iio_sysfs_trig_list);
0164     __module_get(THIS_MODULE);
0165     mutex_unlock(&iio_sysfs_trig_list_mut);
0166     return 0;
0167 
0168 out2:
0169     iio_trigger_free(t->trig);
0170 free_t:
0171     kfree(t);
0172 out1:
0173     mutex_unlock(&iio_sysfs_trig_list_mut);
0174     return ret;
0175 }
0176 
0177 static int iio_sysfs_trigger_remove(int id)
0178 {
0179     struct iio_sysfs_trig *t = NULL, *iter;
0180 
0181     mutex_lock(&iio_sysfs_trig_list_mut);
0182     list_for_each_entry(iter, &iio_sysfs_trig_list, l)
0183         if (id == iter->id) {
0184             t = iter;
0185             break;
0186         }
0187     if (!t) {
0188         mutex_unlock(&iio_sysfs_trig_list_mut);
0189         return -EINVAL;
0190     }
0191 
0192     iio_trigger_unregister(t->trig);
0193     irq_work_sync(&t->work);
0194     iio_trigger_free(t->trig);
0195 
0196     list_del(&t->l);
0197     kfree(t);
0198     module_put(THIS_MODULE);
0199     mutex_unlock(&iio_sysfs_trig_list_mut);
0200     return 0;
0201 }
0202 
0203 
0204 static int __init iio_sysfs_trig_init(void)
0205 {
0206     device_initialize(&iio_sysfs_trig_dev);
0207     dev_set_name(&iio_sysfs_trig_dev, "iio_sysfs_trigger");
0208     return device_add(&iio_sysfs_trig_dev);
0209 }
0210 module_init(iio_sysfs_trig_init);
0211 
0212 static void __exit iio_sysfs_trig_exit(void)
0213 {
0214     device_unregister(&iio_sysfs_trig_dev);
0215 }
0216 module_exit(iio_sysfs_trig_exit);
0217 
0218 MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
0219 MODULE_DESCRIPTION("Sysfs based trigger for the iio subsystem");
0220 MODULE_LICENSE("GPL v2");
0221 MODULE_ALIAS("platform:iio-trig-sysfs");