Merge tag 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford...
[cascardo/linux.git] / drivers / iio / industrialio-trigger.c
index 7ad82fd..e1e1048 100644 (file)
@@ -119,6 +119,22 @@ void iio_trigger_unregister(struct iio_trigger *trig_info)
 }
 EXPORT_SYMBOL(iio_trigger_unregister);
 
+int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *trig)
+{
+       if (!indio_dev || !trig)
+               return -EINVAL;
+
+       mutex_lock(&indio_dev->mlock);
+       WARN_ON(indio_dev->trig_readonly);
+
+       indio_dev->trig = iio_trigger_get(trig);
+       indio_dev->trig_readonly = true;
+       mutex_unlock(&indio_dev->mlock);
+
+       return 0;
+}
+EXPORT_SYMBOL(iio_trigger_set_immutable);
+
 /* Search for trigger by name, assuming iio_trigger_list_lock held */
 static struct iio_trigger *__iio_trigger_find_by_name(const char *name)
 {
@@ -255,6 +271,14 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
                        goto out_free_irq;
        }
 
+       /*
+        * Check if we just registered to our own trigger: we determine that
+        * this is the case if the IIO device and the trigger device share the
+        * same parent device.
+        */
+       if (pf->indio_dev->dev.parent == trig->dev.parent)
+               trig->attached_own_device = true;
+
        return ret;
 
 out_free_irq:
@@ -279,6 +303,8 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
                if (ret)
                        return ret;
        }
+       if (pf->indio_dev->dev.parent == trig->dev.parent)
+               trig->attached_own_device = false;
        iio_trigger_put_irq(trig, pf->irq);
        free_irq(pf->irq, pf);
        module_put(pf->indio_dev->info->driver_module);
@@ -384,6 +410,10 @@ static ssize_t iio_trigger_write_current(struct device *dev,
                mutex_unlock(&indio_dev->mlock);
                return -EBUSY;
        }
+       if (indio_dev->trig_readonly) {
+               mutex_unlock(&indio_dev->mlock);
+               return -EPERM;
+       }
        mutex_unlock(&indio_dev->mlock);
 
        trig = iio_trigger_find_by_name(buf, len);
@@ -622,6 +652,71 @@ void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig)
 }
 EXPORT_SYMBOL_GPL(devm_iio_trigger_free);
 
+static void devm_iio_trigger_unreg(struct device *dev, void *res)
+{
+       iio_trigger_unregister(*(struct iio_trigger **)res);
+}
+
+/**
+ * devm_iio_trigger_register - Resource-managed iio_trigger_register()
+ * @dev:       device this trigger was allocated for
+ * @trig_info: trigger to register
+ *
+ * Managed iio_trigger_register().  The IIO trigger registered with this
+ * function is automatically unregistered on driver detach. This function
+ * calls iio_trigger_register() internally. Refer to that function for more
+ * information.
+ *
+ * If an iio_trigger registered with this function needs to be unregistered
+ * separately, devm_iio_trigger_unregister() must be used.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int devm_iio_trigger_register(struct device *dev, struct iio_trigger *trig_info)
+{
+       struct iio_trigger **ptr;
+       int ret;
+
+       ptr = devres_alloc(devm_iio_trigger_unreg, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       *ptr = trig_info;
+       ret = iio_trigger_register(trig_info);
+       if (!ret)
+               devres_add(dev, ptr);
+       else
+               devres_free(ptr);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(devm_iio_trigger_register);
+
+/**
+ * devm_iio_trigger_unregister - Resource-managed iio_trigger_unregister()
+ * @dev:       device this iio_trigger belongs to
+ * @trig_info: the trigger associated with the device
+ *
+ * Unregister trigger registered with devm_iio_trigger_register().
+ */
+void devm_iio_trigger_unregister(struct device *dev,
+                                struct iio_trigger *trig_info)
+{
+       int rc;
+
+       rc = devres_release(dev, devm_iio_trigger_unreg, devm_iio_trigger_match,
+                           trig_info);
+       WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_iio_trigger_unregister);
+
+bool iio_trigger_using_own(struct iio_dev *indio_dev)
+{
+       return indio_dev->trig->attached_own_device;
+}
+EXPORT_SYMBOL(iio_trigger_using_own);
+
 void iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
 {
        indio_dev->groups[indio_dev->groupcounter++] =