linux/drivers/extcon/devres.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * drivers/extcon/devres.c - EXTCON device's resource management
   4 *
   5 * Copyright (C) 2016 Samsung Electronics
   6 * Author: Chanwoo Choi <cw00.choi@samsung.com>
   7 */
   8
   9#include "extcon.h"
  10
  11static int devm_extcon_dev_match(struct device *dev, void *res, void *data)
  12{
  13        struct extcon_dev **r = res;
  14
  15        if (WARN_ON(!r || !*r))
  16                return 0;
  17
  18        return *r == data;
  19}
  20
  21static void devm_extcon_dev_release(struct device *dev, void *res)
  22{
  23        extcon_dev_free(*(struct extcon_dev **)res);
  24}
  25
  26
  27static void devm_extcon_dev_unreg(struct device *dev, void *res)
  28{
  29        extcon_dev_unregister(*(struct extcon_dev **)res);
  30}
  31
  32struct extcon_dev_notifier_devres {
  33        struct extcon_dev *edev;
  34        unsigned int id;
  35        struct notifier_block *nb;
  36};
  37
  38static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res)
  39{
  40        struct extcon_dev_notifier_devres *this = res;
  41
  42        extcon_unregister_notifier(this->edev, this->id, this->nb);
  43}
  44
  45static void devm_extcon_dev_notifier_all_unreg(struct device *dev, void *res)
  46{
  47        struct extcon_dev_notifier_devres *this = res;
  48
  49        extcon_unregister_notifier_all(this->edev, this->nb);
  50}
  51
  52/**
  53 * devm_extcon_dev_allocate - Allocate managed extcon device
  54 * @dev:                the device owning the extcon device being created
  55 * @supported_cable:    the array of the supported external connectors
  56 *                      ending with EXTCON_NONE.
  57 *
  58 * This function manages automatically the memory of extcon device using device
  59 * resource management and simplify the control of freeing the memory of extcon
  60 * device.
  61 *
  62 * Returns the pointer memory of allocated extcon_dev if success
  63 * or ERR_PTR(err) if fail
  64 */
  65struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
  66                                        const unsigned int *supported_cable)
  67{
  68        struct extcon_dev **ptr, *edev;
  69
  70        ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL);
  71        if (!ptr)
  72                return ERR_PTR(-ENOMEM);
  73
  74        edev = extcon_dev_allocate(supported_cable);
  75        if (IS_ERR(edev)) {
  76                devres_free(ptr);
  77                return edev;
  78        }
  79
  80        edev->dev.parent = dev;
  81
  82        *ptr = edev;
  83        devres_add(dev, ptr);
  84
  85        return edev;
  86}
  87EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate);
  88
  89/**
  90 * devm_extcon_dev_free() - Resource-managed extcon_dev_unregister()
  91 * @dev:        the device owning the extcon device being created
  92 * @edev:       the extcon device to be freed
  93 *
  94 * Free the memory that is allocated with devm_extcon_dev_allocate()
  95 * function.
  96 */
  97void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev)
  98{
  99        WARN_ON(devres_release(dev, devm_extcon_dev_release,
 100                               devm_extcon_dev_match, edev));
 101}
 102EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
 103
 104/**
 105 * devm_extcon_dev_register() - Resource-managed extcon_dev_register()
 106 * @dev:        the device owning the extcon device being created
 107 * @edev:       the extcon device to be registered
 108 *
 109 * this function, that extcon device is automatically unregistered on driver
 110 * detach. Internally this function calls extcon_dev_register() function.
 111 * To get more information, refer that function.
 112 *
 113 * If extcon device is registered with this function and the device needs to be
 114 * unregistered separately, devm_extcon_dev_unregister() should be used.
 115 *
 116 * Returns 0 if success or negaive error number if failure.
 117 */
 118int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev)
 119{
 120        struct extcon_dev **ptr;
 121        int ret;
 122
 123        ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL);
 124        if (!ptr)
 125                return -ENOMEM;
 126
 127        ret = extcon_dev_register(edev);
 128        if (ret) {
 129                devres_free(ptr);
 130                return ret;
 131        }
 132
 133        *ptr = edev;
 134        devres_add(dev, ptr);
 135
 136        return 0;
 137}
 138EXPORT_SYMBOL_GPL(devm_extcon_dev_register);
 139
 140/**
 141 * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister()
 142 * @dev:        the device owning the extcon device being created
 143 * @edev:       the extcon device to unregistered
 144 *
 145 * Unregister extcon device that is registered with devm_extcon_dev_register()
 146 * function.
 147 */
 148void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev)
 149{
 150        WARN_ON(devres_release(dev, devm_extcon_dev_unreg,
 151                               devm_extcon_dev_match, edev));
 152}
 153EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister);
 154
 155/**
 156 * devm_extcon_register_notifier() - Resource-managed extcon_register_notifier()
 157 * @dev:        the device owning the extcon device being created
 158 * @edev:       the extcon device
 159 * @id:         the unique id among the extcon enumeration
 160 * @nb:         a notifier block to be registered
 161 *
 162 * This function manages automatically the notifier of extcon device using
 163 * device resource management and simplify the control of unregistering
 164 * the notifier of extcon device.
 165 *
 166 * Note that the second parameter given to the callback of nb (val) is
 167 * "old_state", not the current state. The current state can be retrieved
 168 * by looking at the third pameter (edev pointer)'s state value.
 169 *
 170 * Returns 0 if success or negaive error number if failure.
 171 */
 172int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev,
 173                                unsigned int id, struct notifier_block *nb)
 174{
 175        struct extcon_dev_notifier_devres *ptr;
 176        int ret;
 177
 178        ptr = devres_alloc(devm_extcon_dev_notifier_unreg, sizeof(*ptr),
 179                                GFP_KERNEL);
 180        if (!ptr)
 181                return -ENOMEM;
 182
 183        ret = extcon_register_notifier(edev, id, nb);
 184        if (ret) {
 185                devres_free(ptr);
 186                return ret;
 187        }
 188
 189        ptr->edev = edev;
 190        ptr->id = id;
 191        ptr->nb = nb;
 192        devres_add(dev, ptr);
 193
 194        return 0;
 195}
 196EXPORT_SYMBOL(devm_extcon_register_notifier);
 197
 198/**
 199 * devm_extcon_unregister_notifier()
 200 *                      - Resource-managed extcon_unregister_notifier()
 201 * @dev:        the device owning the extcon device being created
 202 * @edev:       the extcon device
 203 * @id:         the unique id among the extcon enumeration
 204 * @nb:         a notifier block to be registered
 205 */
 206void devm_extcon_unregister_notifier(struct device *dev,
 207                                struct extcon_dev *edev, unsigned int id,
 208                                struct notifier_block *nb)
 209{
 210        WARN_ON(devres_release(dev, devm_extcon_dev_notifier_unreg,
 211                               devm_extcon_dev_match, edev));
 212}
 213EXPORT_SYMBOL(devm_extcon_unregister_notifier);
 214
 215/**
 216 * devm_extcon_register_notifier_all()
 217 *              - Resource-managed extcon_register_notifier_all()
 218 * @dev:        the device owning the extcon device being created
 219 * @edev:       the extcon device
 220 * @nb:         a notifier block to be registered
 221 *
 222 * This function manages automatically the notifier of extcon device using
 223 * device resource management and simplify the control of unregistering
 224 * the notifier of extcon device. To get more information, refer that function.
 225 *
 226 * Returns 0 if success or negaive error number if failure.
 227 */
 228int devm_extcon_register_notifier_all(struct device *dev, struct extcon_dev *edev,
 229                                struct notifier_block *nb)
 230{
 231        struct extcon_dev_notifier_devres *ptr;
 232        int ret;
 233
 234        ptr = devres_alloc(devm_extcon_dev_notifier_all_unreg, sizeof(*ptr),
 235                                GFP_KERNEL);
 236        if (!ptr)
 237                return -ENOMEM;
 238
 239        ret = extcon_register_notifier_all(edev, nb);
 240        if (ret) {
 241                devres_free(ptr);
 242                return ret;
 243        }
 244
 245        ptr->edev = edev;
 246        ptr->nb = nb;
 247        devres_add(dev, ptr);
 248
 249        return 0;
 250}
 251EXPORT_SYMBOL(devm_extcon_register_notifier_all);
 252
 253/**
 254 * devm_extcon_unregister_notifier_all()
 255 *              - Resource-managed extcon_unregister_notifier_all()
 256 * @dev:        the device owning the extcon device being created
 257 * @edev:       the extcon device
 258 * @nb:         a notifier block to be registered
 259 */
 260void devm_extcon_unregister_notifier_all(struct device *dev,
 261                                struct extcon_dev *edev,
 262                                struct notifier_block *nb)
 263{
 264        WARN_ON(devres_release(dev, devm_extcon_dev_notifier_all_unreg,
 265                               devm_extcon_dev_match, edev));
 266}
 267EXPORT_SYMBOL(devm_extcon_unregister_notifier_all);
 268