Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * drivers/extcon/devres.c - EXTCON device's resource management
0004  *
0005  * Copyright (C) 2016 Samsung Electronics
0006  * Author: Chanwoo Choi <cw00.choi@samsung.com>
0007  */
0008 
0009 #include "extcon.h"
0010 
0011 static int devm_extcon_dev_match(struct device *dev, void *res, void *data)
0012 {
0013     struct extcon_dev **r = res;
0014 
0015     if (WARN_ON(!r || !*r))
0016         return 0;
0017 
0018     return *r == data;
0019 }
0020 
0021 static void devm_extcon_dev_release(struct device *dev, void *res)
0022 {
0023     extcon_dev_free(*(struct extcon_dev **)res);
0024 }
0025 
0026 
0027 static void devm_extcon_dev_unreg(struct device *dev, void *res)
0028 {
0029     extcon_dev_unregister(*(struct extcon_dev **)res);
0030 }
0031 
0032 struct extcon_dev_notifier_devres {
0033     struct extcon_dev *edev;
0034     unsigned int id;
0035     struct notifier_block *nb;
0036 };
0037 
0038 static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res)
0039 {
0040     struct extcon_dev_notifier_devres *this = res;
0041 
0042     extcon_unregister_notifier(this->edev, this->id, this->nb);
0043 }
0044 
0045 static void devm_extcon_dev_notifier_all_unreg(struct device *dev, void *res)
0046 {
0047     struct extcon_dev_notifier_devres *this = res;
0048 
0049     extcon_unregister_notifier_all(this->edev, this->nb);
0050 }
0051 
0052 /**
0053  * devm_extcon_dev_allocate - Allocate managed extcon device
0054  * @dev:        the device owning the extcon device being created
0055  * @supported_cable:    the array of the supported external connectors
0056  *          ending with EXTCON_NONE.
0057  *
0058  * This function manages automatically the memory of extcon device using device
0059  * resource management and simplify the control of freeing the memory of extcon
0060  * device.
0061  *
0062  * Returns the pointer memory of allocated extcon_dev if success
0063  * or ERR_PTR(err) if fail
0064  */
0065 struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
0066                     const unsigned int *supported_cable)
0067 {
0068     struct extcon_dev **ptr, *edev;
0069 
0070     ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL);
0071     if (!ptr)
0072         return ERR_PTR(-ENOMEM);
0073 
0074     edev = extcon_dev_allocate(supported_cable);
0075     if (IS_ERR(edev)) {
0076         devres_free(ptr);
0077         return edev;
0078     }
0079 
0080     edev->dev.parent = dev;
0081 
0082     *ptr = edev;
0083     devres_add(dev, ptr);
0084 
0085     return edev;
0086 }
0087 EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate);
0088 
0089 /**
0090  * devm_extcon_dev_free() - Resource-managed extcon_dev_unregister()
0091  * @dev:    the device owning the extcon device being created
0092  * @edev:   the extcon device to be freed
0093  *
0094  * Free the memory that is allocated with devm_extcon_dev_allocate()
0095  * function.
0096  */
0097 void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev)
0098 {
0099     WARN_ON(devres_release(dev, devm_extcon_dev_release,
0100                    devm_extcon_dev_match, edev));
0101 }
0102 EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
0103 
0104 /**
0105  * devm_extcon_dev_register() - Resource-managed extcon_dev_register()
0106  * @dev:    the device owning the extcon device being created
0107  * @edev:   the extcon device to be registered
0108  *
0109  * this function, that extcon device is automatically unregistered on driver
0110  * detach. Internally this function calls extcon_dev_register() function.
0111  * To get more information, refer that function.
0112  *
0113  * If extcon device is registered with this function and the device needs to be
0114  * unregistered separately, devm_extcon_dev_unregister() should be used.
0115  *
0116  * Returns 0 if success or negaive error number if failure.
0117  */
0118 int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev)
0119 {
0120     struct extcon_dev **ptr;
0121     int ret;
0122 
0123     ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL);
0124     if (!ptr)
0125         return -ENOMEM;
0126 
0127     ret = extcon_dev_register(edev);
0128     if (ret) {
0129         devres_free(ptr);
0130         return ret;
0131     }
0132 
0133     *ptr = edev;
0134     devres_add(dev, ptr);
0135 
0136     return 0;
0137 }
0138 EXPORT_SYMBOL_GPL(devm_extcon_dev_register);
0139 
0140 /**
0141  * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister()
0142  * @dev:    the device owning the extcon device being created
0143  * @edev:   the extcon device to unregistered
0144  *
0145  * Unregister extcon device that is registered with devm_extcon_dev_register()
0146  * function.
0147  */
0148 void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev)
0149 {
0150     WARN_ON(devres_release(dev, devm_extcon_dev_unreg,
0151                    devm_extcon_dev_match, edev));
0152 }
0153 EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister);
0154 
0155 /**
0156  * devm_extcon_register_notifier() - Resource-managed extcon_register_notifier()
0157  * @dev:    the device owning the extcon device being created
0158  * @edev:   the extcon device
0159  * @id:     the unique id among the extcon enumeration
0160  * @nb:     a notifier block to be registered
0161  *
0162  * This function manages automatically the notifier of extcon device using
0163  * device resource management and simplify the control of unregistering
0164  * the notifier of extcon device.
0165  *
0166  * Note that the second parameter given to the callback of nb (val) is
0167  * "old_state", not the current state. The current state can be retrieved
0168  * by looking at the third pameter (edev pointer)'s state value.
0169  *
0170  * Returns 0 if success or negaive error number if failure.
0171  */
0172 int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev,
0173                 unsigned int id, struct notifier_block *nb)
0174 {
0175     struct extcon_dev_notifier_devres *ptr;
0176     int ret;
0177 
0178     ptr = devres_alloc(devm_extcon_dev_notifier_unreg, sizeof(*ptr),
0179                 GFP_KERNEL);
0180     if (!ptr)
0181         return -ENOMEM;
0182 
0183     ret = extcon_register_notifier(edev, id, nb);
0184     if (ret) {
0185         devres_free(ptr);
0186         return ret;
0187     }
0188 
0189     ptr->edev = edev;
0190     ptr->id = id;
0191     ptr->nb = nb;
0192     devres_add(dev, ptr);
0193 
0194     return 0;
0195 }
0196 EXPORT_SYMBOL(devm_extcon_register_notifier);
0197 
0198 /**
0199  * devm_extcon_unregister_notifier()
0200  *          - Resource-managed extcon_unregister_notifier()
0201  * @dev:    the device owning the extcon device being created
0202  * @edev:   the extcon device
0203  * @id:     the unique id among the extcon enumeration
0204  * @nb:     a notifier block to be registered
0205  */
0206 void devm_extcon_unregister_notifier(struct device *dev,
0207                 struct extcon_dev *edev, unsigned int id,
0208                 struct notifier_block *nb)
0209 {
0210     WARN_ON(devres_release(dev, devm_extcon_dev_notifier_unreg,
0211                    devm_extcon_dev_match, edev));
0212 }
0213 EXPORT_SYMBOL(devm_extcon_unregister_notifier);
0214 
0215 /**
0216  * devm_extcon_register_notifier_all()
0217  *      - Resource-managed extcon_register_notifier_all()
0218  * @dev:    the device owning the extcon device being created
0219  * @edev:   the extcon device
0220  * @nb:     a notifier block to be registered
0221  *
0222  * This function manages automatically the notifier of extcon device using
0223  * device resource management and simplify the control of unregistering
0224  * the notifier of extcon device. To get more information, refer that function.
0225  *
0226  * Returns 0 if success or negaive error number if failure.
0227  */
0228 int devm_extcon_register_notifier_all(struct device *dev, struct extcon_dev *edev,
0229                 struct notifier_block *nb)
0230 {
0231     struct extcon_dev_notifier_devres *ptr;
0232     int ret;
0233 
0234     ptr = devres_alloc(devm_extcon_dev_notifier_all_unreg, sizeof(*ptr),
0235                 GFP_KERNEL);
0236     if (!ptr)
0237         return -ENOMEM;
0238 
0239     ret = extcon_register_notifier_all(edev, nb);
0240     if (ret) {
0241         devres_free(ptr);
0242         return ret;
0243     }
0244 
0245     ptr->edev = edev;
0246     ptr->nb = nb;
0247     devres_add(dev, ptr);
0248 
0249     return 0;
0250 }
0251 EXPORT_SYMBOL(devm_extcon_register_notifier_all);
0252 
0253 /**
0254  * devm_extcon_unregister_notifier_all()
0255  *      - Resource-managed extcon_unregister_notifier_all()
0256  * @dev:    the device owning the extcon device being created
0257  * @edev:   the extcon device
0258  * @nb:     a notifier block to be registered
0259  */
0260 void devm_extcon_unregister_notifier_all(struct device *dev,
0261                 struct extcon_dev *edev,
0262                 struct notifier_block *nb)
0263 {
0264     WARN_ON(devres_release(dev, devm_extcon_dev_notifier_all_unreg,
0265                    devm_extcon_dev_match, edev));
0266 }
0267 EXPORT_SYMBOL(devm_extcon_unregister_notifier_all);