Merge branch 'pm-sleep'
[cascardo/linux.git] / drivers / extcon / extcon.c
index 4fef9ab..8682efc 100644 (file)
@@ -77,6 +77,26 @@ static const char *extcon_name[] =  {
        NULL,
 };
 
+/**
+ * struct extcon_cable - An internal data for each cable of extcon device.
+ * @edev:              The extcon device
+ * @cable_index:       Index of this cable in the edev
+ * @attr_g:            Attribute group for the cable
+ * @attr_name:         "name" sysfs entry
+ * @attr_state:                "state" sysfs entry
+ * @attrs:             Array pointing to attr_name and attr_state for attr_g
+ */
+struct extcon_cable {
+       struct extcon_dev *edev;
+       int cable_index;
+
+       struct attribute_group attr_g;
+       struct device_attribute attr_name;
+       struct device_attribute attr_state;
+
+       struct attribute *attrs[3]; /* to be fed to attr_g.attrs */
+};
+
 static struct class *extcon_class;
 #if defined(CONFIG_ANDROID)
 static struct class_compat *switch_class;
@@ -415,6 +435,8 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
 
        if (edev) {
                idx = find_cable_index_by_id(edev, id);
+               if (idx < 0)
+                       return idx;
 
                spin_lock_irqsave(&edev->lock, flags);
                ret = raw_notifier_chain_register(&edev->nh[idx], nb);
@@ -458,6 +480,8 @@ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
                return -EINVAL;
 
        idx = find_cable_index_by_id(edev, id);
+       if (idx < 0)
+               return idx;
 
        spin_lock_irqsave(&edev->lock, flags);
        ret = raw_notifier_chain_unregister(&edev->nh[idx], nb);
@@ -540,66 +564,6 @@ void extcon_dev_free(struct extcon_dev *edev)
 }
 EXPORT_SYMBOL_GPL(extcon_dev_free);
 
-static int devm_extcon_dev_match(struct device *dev, void *res, void *data)
-{
-       struct extcon_dev **r = res;
-
-       if (WARN_ON(!r || !*r))
-               return 0;
-
-       return *r == data;
-}
-
-static void devm_extcon_dev_release(struct device *dev, void *res)
-{
-       extcon_dev_free(*(struct extcon_dev **)res);
-}
-
-/**
- * devm_extcon_dev_allocate - Allocate managed extcon device
- * @dev:               device owning the extcon device being created
- * @supported_cable:   Array of supported extcon ending with EXTCON_NONE.
- *                     If supported_cable is NULL, cable name related APIs
- *                     are disabled.
- *
- * This function manages automatically the memory of extcon device using device
- * resource management and simplify the control of freeing the memory of extcon
- * device.
- *
- * Returns the pointer memory of allocated extcon_dev if success
- * or ERR_PTR(err) if fail
- */
-struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
-                                       const unsigned int *supported_cable)
-{
-       struct extcon_dev **ptr, *edev;
-
-       ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL);
-       if (!ptr)
-               return ERR_PTR(-ENOMEM);
-
-       edev = extcon_dev_allocate(supported_cable);
-       if (IS_ERR(edev)) {
-               devres_free(ptr);
-               return edev;
-       }
-
-       edev->dev.parent = dev;
-
-       *ptr = edev;
-       devres_add(dev, ptr);
-
-       return edev;
-}
-EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate);
-
-void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev)
-{
-       WARN_ON(devres_release(dev, devm_extcon_dev_release,
-                              devm_extcon_dev_match, edev));
-}
-EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
-
 /**
  * extcon_dev_register() - Register a new extcon device
  * @edev       : the new extcon device (should be allocated before calling)
@@ -865,63 +829,6 @@ void extcon_dev_unregister(struct extcon_dev *edev)
 }
 EXPORT_SYMBOL_GPL(extcon_dev_unregister);
 
-static void devm_extcon_dev_unreg(struct device *dev, void *res)
-{
-       extcon_dev_unregister(*(struct extcon_dev **)res);
-}
-
-/**
- * devm_extcon_dev_register() - Resource-managed extcon_dev_register()
- * @dev:       device to allocate extcon device
- * @edev:      the new extcon device to register
- *
- * Managed extcon_dev_register() function. If extcon device is attached with
- * this function, that extcon device is automatically unregistered on driver
- * detach. Internally this function calls extcon_dev_register() function.
- * To get more information, refer that function.
- *
- * If extcon device is registered with this function and the device needs to be
- * unregistered separately, devm_extcon_dev_unregister() should be used.
- *
- * Returns 0 if success or negaive error number if failure.
- */
-int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev)
-{
-       struct extcon_dev **ptr;
-       int ret;
-
-       ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL);
-       if (!ptr)
-               return -ENOMEM;
-
-       ret = extcon_dev_register(edev);
-       if (ret) {
-               devres_free(ptr);
-               return ret;
-       }
-
-       *ptr = edev;
-       devres_add(dev, ptr);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(devm_extcon_dev_register);
-
-/**
- * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister()
- * @dev:       device the extcon belongs to
- * @edev:      the extcon device to unregister
- *
- * Unregister extcon device that is registered with devm_extcon_dev_register()
- * function.
- */
-void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev)
-{
-       WARN_ON(devres_release(dev, devm_extcon_dev_unreg,
-                              devm_extcon_dev_match, edev));
-}
-EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister);
-
 #ifdef CONFIG_OF
 /*
  * extcon_get_edev_by_phandle - Get the extcon device from devicetree
@@ -954,10 +861,12 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
        list_for_each_entry(edev, &extcon_dev_list, entry) {
                if (edev->dev.parent && edev->dev.parent->of_node == node) {
                        mutex_unlock(&extcon_dev_list_lock);
+                       of_node_put(node);
                        return edev;
                }
        }
        mutex_unlock(&extcon_dev_list_lock);
+       of_node_put(node);
 
        return ERR_PTR(-EPROBE_DEFER);
 }