summaryrefslogtreecommitdiff
path: root/drivers/staging/iio/industrialio-trigger.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/iio/industrialio-trigger.c')
-rw-r--r--drivers/staging/iio/industrialio-trigger.c299
1 files changed, 187 insertions, 112 deletions
diff --git a/drivers/staging/iio/industrialio-trigger.c b/drivers/staging/iio/industrialio-trigger.c
index 57dd9232cf0d..615902333fb0 100644
--- a/drivers/staging/iio/industrialio-trigger.c
+++ b/drivers/staging/iio/industrialio-trigger.c
@@ -39,6 +39,19 @@ static LIST_HEAD(iio_trigger_list);
static DEFINE_MUTEX(iio_trigger_list_lock);
/**
+ * iio_trigger_read_name() - retrieve useful identifying name
+ **/
+static ssize_t iio_trigger_read_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_trigger *trig = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", trig->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
+
+/**
* iio_trigger_register_sysfs() - create a device for this trigger
* @trig_info: the trigger
*
@@ -46,20 +59,16 @@ static DEFINE_MUTEX(iio_trigger_list_lock);
**/
static int iio_trigger_register_sysfs(struct iio_trigger *trig_info)
{
- int ret = 0;
-
- if (trig_info->control_attrs)
- ret = sysfs_create_group(&trig_info->dev.kobj,
- trig_info->control_attrs);
-
- return ret;
+ return sysfs_add_file_to_group(&trig_info->dev.kobj,
+ &dev_attr_name.attr,
+ NULL);
}
static void iio_trigger_unregister_sysfs(struct iio_trigger *trig_info)
{
- if (trig_info->control_attrs)
- sysfs_remove_group(&trig_info->dev.kobj,
- trig_info->control_attrs);
+ sysfs_remove_file_from_group(&trig_info->dev.kobj,
+ &dev_attr_name.attr,
+ NULL);
}
@@ -134,14 +143,8 @@ EXPORT_SYMBOL(iio_trigger_register);
void iio_trigger_unregister(struct iio_trigger *trig_info)
{
- struct iio_trigger *cursor;
-
mutex_lock(&iio_trigger_list_lock);
- list_for_each_entry(cursor, &iio_trigger_list, list)
- if (cursor == trig_info) {
- list_del(&cursor->list);
- break;
- }
+ list_del(&trig_info->list);
mutex_unlock(&iio_trigger_list_lock);
iio_trigger_unregister_sysfs(trig_info);
@@ -151,47 +154,55 @@ void iio_trigger_unregister(struct iio_trigger *trig_info)
}
EXPORT_SYMBOL(iio_trigger_unregister);
-struct iio_trigger *iio_trigger_find_by_name(const char *name, size_t len)
+static struct iio_trigger *iio_trigger_find_by_name(const char *name,
+ size_t len)
{
- struct iio_trigger *trig;
- bool found = false;
-
- if (len && name[len - 1] == '\n')
- len--;
+ struct iio_trigger *trig = NULL, *iter;
mutex_lock(&iio_trigger_list_lock);
- list_for_each_entry(trig, &iio_trigger_list, list) {
- if (strncmp(trig->name, name, len) == 0) {
- found = true;
+ list_for_each_entry(iter, &iio_trigger_list, list)
+ if (sysfs_streq(iter->name, name)) {
+ trig = iter;
break;
}
- }
mutex_unlock(&iio_trigger_list_lock);
- return found ? trig : NULL;
+ return trig;
}
-EXPORT_SYMBOL(iio_trigger_find_by_name);
void iio_trigger_poll(struct iio_trigger *trig, s64 time)
{
- struct iio_poll_func *pf_cursor;
-
- list_for_each_entry(pf_cursor, &trig->pollfunc_list, list) {
- if (pf_cursor->poll_func_immediate) {
- pf_cursor->poll_func_immediate(pf_cursor->private_data);
- trig->use_count++;
- }
- }
- list_for_each_entry(pf_cursor, &trig->pollfunc_list, list) {
- if (pf_cursor->poll_func_main) {
- pf_cursor->poll_func_main(pf_cursor->private_data,
- time);
- trig->use_count++;
- }
+ int i;
+ if (!trig->use_count) {
+ for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++)
+ if (trig->subirqs[i].enabled) {
+ trig->use_count++;
+ generic_handle_irq(trig->subirq_base + i);
+ }
}
}
EXPORT_SYMBOL(iio_trigger_poll);
+irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private)
+{
+ iio_trigger_poll(private, iio_get_time_ns());
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll);
+
+void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time)
+{
+ int i;
+ if (!trig->use_count) {
+ for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++)
+ if (trig->subirqs[i].enabled) {
+ trig->use_count++;
+ handle_nested_irq(trig->subirq_base + i);
+ }
+ }
+}
+EXPORT_SYMBOL(iio_trigger_poll_chained);
+
void iio_trigger_notify_done(struct iio_trigger *trig)
{
trig->use_count--;
@@ -203,18 +214,6 @@ void iio_trigger_notify_done(struct iio_trigger *trig)
}
EXPORT_SYMBOL(iio_trigger_notify_done);
-/**
- * iio_trigger_read_name() - retrieve useful identifying name
- **/
-ssize_t iio_trigger_read_name(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_trigger *trig = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", trig->name);
-}
-EXPORT_SYMBOL(iio_trigger_read_name);
-
/* Trigger Consumer related functions */
/* Complexity in here. With certain triggers (datardy) an acknowledgement
@@ -228,18 +227,16 @@ int iio_trigger_attach_poll_func(struct iio_trigger *trig,
struct iio_poll_func *pf)
{
int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&trig->pollfunc_list_lock, flags);
- list_add_tail(&pf->list, &trig->pollfunc_list);
- spin_unlock_irqrestore(&trig->pollfunc_list_lock, flags);
-
- if (trig->set_trigger_state)
+ bool notinuse
+ = bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
+
+ pf->irq = iio_trigger_get_irq(trig);
+ ret = request_threaded_irq(pf->irq, pf->h, pf->thread,
+ pf->type, pf->name,
+ pf);
+ if (trig->set_trigger_state && notinuse)
ret = trig->set_trigger_state(trig, true);
- if (ret) {
- printk(KERN_ERR "set trigger state failed\n");
- list_del(&pf->list);
- }
+
return ret;
}
EXPORT_SYMBOL(iio_trigger_attach_poll_func);
@@ -247,41 +244,68 @@ EXPORT_SYMBOL(iio_trigger_attach_poll_func);
int iio_trigger_dettach_poll_func(struct iio_trigger *trig,
struct iio_poll_func *pf)
{
- struct iio_poll_func *pf_cursor;
- unsigned long flags;
- int ret = -EINVAL;
-
- spin_lock_irqsave(&trig->pollfunc_list_lock, flags);
- list_for_each_entry(pf_cursor, &trig->pollfunc_list, list)
- if (pf_cursor == pf) {
- ret = 0;
- break;
- }
- if (!ret) {
- if (list_is_singular(&trig->pollfunc_list)
- && trig->set_trigger_state) {
- spin_unlock_irqrestore(&trig->pollfunc_list_lock,
- flags);
- /* May sleep hence cannot hold the spin lock */
- ret = trig->set_trigger_state(trig, false);
- if (ret)
- goto error_ret;
- spin_lock_irqsave(&trig->pollfunc_list_lock, flags);
- }
- /*
- * Now we can delete safe in the knowledge that, if this is
- * the last pollfunc then we have disabled the trigger anyway
- * and so nothing should be able to call the pollfunc.
- */
- list_del(&pf_cursor->list);
+ int ret = 0;
+ bool no_other_users
+ = (bitmap_weight(trig->pool,
+ CONFIG_IIO_CONSUMERS_PER_TRIGGER)
+ == 1);
+ if (trig->set_trigger_state && no_other_users) {
+ ret = trig->set_trigger_state(trig, false);
+ if (ret)
+ goto error_ret;
}
- spin_unlock_irqrestore(&trig->pollfunc_list_lock, flags);
+ iio_trigger_put_irq(trig, pf->irq);
+ free_irq(pf->irq, pf);
error_ret:
return ret;
}
EXPORT_SYMBOL(iio_trigger_dettach_poll_func);
+irqreturn_t iio_pollfunc_store_time(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ pf->timestamp = iio_get_time_ns();
+ return IRQ_WAKE_THREAD;
+}
+EXPORT_SYMBOL(iio_pollfunc_store_time);
+
+struct iio_poll_func
+*iio_alloc_pollfunc(irqreturn_t (*h)(int irq, void *p),
+ irqreturn_t (*thread)(int irq, void *p),
+ int type,
+ void *private,
+ const char *fmt,
+ ...)
+{
+ va_list vargs;
+ struct iio_poll_func *pf;
+
+ pf = kmalloc(sizeof *pf, GFP_KERNEL);
+ if (pf == NULL)
+ return NULL;
+ va_start(vargs, fmt);
+ pf->name = kvasprintf(GFP_KERNEL, fmt, vargs);
+ va_end(vargs);
+ if (pf->name == NULL) {
+ kfree(pf);
+ return NULL;
+ }
+ pf->h = h;
+ pf->thread = thread;
+ pf->type = type;
+
+ return pf;
+}
+EXPORT_SYMBOL_GPL(iio_alloc_pollfunc);
+
+void iio_dealloc_pollfunc(struct iio_poll_func *pf)
+{
+ kfree(pf->name);
+ kfree(pf);
+}
+EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc);
+
/**
* iio_trigger_read_currrent() - trigger consumer sysfs query which trigger
*
@@ -348,6 +372,23 @@ static const struct attribute_group iio_trigger_consumer_attr_group = {
static void iio_trig_release(struct device *device)
{
struct iio_trigger *trig = to_iio_trigger(device);
+ int i;
+
+ if (trig->subirq_base) {
+ for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
+ irq_modify_status(trig->subirq_base + i,
+ IRQ_NOAUTOEN,
+ IRQ_NOREQUEST | IRQ_NOPROBE);
+ irq_set_chip(trig->subirq_base + i,
+ NULL);
+ irq_set_handler(trig->subirq_base + i,
+ NULL);
+ }
+
+ irq_free_descs(trig->subirq_base,
+ CONFIG_IIO_CONSUMERS_PER_TRIGGER);
+ }
+ kfree(trig->name);
kfree(trig);
iio_put();
}
@@ -356,18 +397,66 @@ static struct device_type iio_trig_type = {
.release = iio_trig_release,
};
-struct iio_trigger *iio_allocate_trigger(void)
+static void iio_trig_subirqmask(struct irq_data *d)
+{
+ struct irq_chip *chip = irq_data_get_irq_chip(d);
+ struct iio_trigger *trig
+ = container_of(chip,
+ struct iio_trigger, subirq_chip);
+ trig->subirqs[d->irq - trig->subirq_base].enabled = false;
+}
+
+static void iio_trig_subirqunmask(struct irq_data *d)
+{
+ struct irq_chip *chip = irq_data_get_irq_chip(d);
+ struct iio_trigger *trig
+ = container_of(chip,
+ struct iio_trigger, subirq_chip);
+ trig->subirqs[d->irq - trig->subirq_base].enabled = true;
+}
+
+struct iio_trigger *iio_allocate_trigger(const char *fmt, ...)
{
+ va_list vargs;
struct iio_trigger *trig;
trig = kzalloc(sizeof *trig, GFP_KERNEL);
if (trig) {
+ int i;
trig->dev.type = &iio_trig_type;
trig->dev.bus = &iio_bus_type;
device_initialize(&trig->dev);
dev_set_drvdata(&trig->dev, (void *)trig);
- spin_lock_init(&trig->pollfunc_list_lock);
- INIT_LIST_HEAD(&trig->list);
- INIT_LIST_HEAD(&trig->pollfunc_list);
+
+ mutex_init(&trig->pool_lock);
+ trig->subirq_base
+ = irq_alloc_descs(-1, 0,
+ CONFIG_IIO_CONSUMERS_PER_TRIGGER,
+ 0);
+ if (trig->subirq_base < 0) {
+ kfree(trig);
+ return NULL;
+ }
+ va_start(vargs, fmt);
+ trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
+ va_end(vargs);
+ if (trig->name == NULL) {
+ irq_free_descs(trig->subirq_base,
+ CONFIG_IIO_CONSUMERS_PER_TRIGGER);
+ kfree(trig);
+ return NULL;
+ }
+ trig->subirq_chip.name = trig->name;
+ trig->subirq_chip.irq_mask = &iio_trig_subirqmask;
+ trig->subirq_chip.irq_unmask = &iio_trig_subirqunmask;
+ for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
+ irq_set_chip(trig->subirq_base + i,
+ &trig->subirq_chip);
+ irq_set_handler(trig->subirq_base + i,
+ &handle_simple_irq);
+ irq_modify_status(trig->subirq_base + i,
+ IRQ_NOREQUEST | IRQ_NOAUTOEN,
+ IRQ_NOPROBE);
+ }
iio_get();
}
return trig;
@@ -398,20 +487,6 @@ int iio_device_unregister_trigger_consumer(struct iio_dev *dev_info)
}
EXPORT_SYMBOL(iio_device_unregister_trigger_consumer);
-int iio_alloc_pollfunc(struct iio_dev *indio_dev,
- void (*immediate)(struct iio_dev *indio_dev),
- void (*main)(struct iio_dev *private_data, s64 time))
-{
- indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
- if (indio_dev->pollfunc == NULL)
- return -ENOMEM;
- indio_dev->pollfunc->poll_func_immediate = immediate;
- indio_dev->pollfunc->poll_func_main = main;
- indio_dev->pollfunc->private_data = indio_dev;
- return 0;
-}
-EXPORT_SYMBOL(iio_alloc_pollfunc);
-
int iio_triggered_ring_postenable(struct iio_dev *indio_dev)
{
return indio_dev->trig