Merge branch 'spi/next' of git://git.secretlab.ca/git/linux-2.6
[pandora-kernel.git] / drivers / staging / iio / industrialio-trigger.c
index 57dd923..6159023 100644 (file)
@@ -38,6 +38,19 @@ static DEFINE_SPINLOCK(iio_trigger_idr_lock);
 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