0001
0002
0003
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
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");