1*9c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b225d00fSChanwoo Choi /*
3b225d00fSChanwoo Choi * drivers/extcon/devres.c - EXTCON device's resource management
4b225d00fSChanwoo Choi *
5b225d00fSChanwoo Choi * Copyright (C) 2016 Samsung Electronics
6b225d00fSChanwoo Choi * Author: Chanwoo Choi <cw00.choi@samsung.com>
7b225d00fSChanwoo Choi */
8b225d00fSChanwoo Choi
9e6cf0465SChanwoo Choi #include "extcon.h"
10b225d00fSChanwoo Choi
devm_extcon_dev_match(struct device * dev,void * res,void * data)11b225d00fSChanwoo Choi static int devm_extcon_dev_match(struct device *dev, void *res, void *data)
12b225d00fSChanwoo Choi {
13b225d00fSChanwoo Choi struct extcon_dev **r = res;
14b225d00fSChanwoo Choi
15b225d00fSChanwoo Choi if (WARN_ON(!r || !*r))
16b225d00fSChanwoo Choi return 0;
17b225d00fSChanwoo Choi
18b225d00fSChanwoo Choi return *r == data;
19b225d00fSChanwoo Choi }
20b225d00fSChanwoo Choi
devm_extcon_dev_release(struct device * dev,void * res)21b225d00fSChanwoo Choi static void devm_extcon_dev_release(struct device *dev, void *res)
22b225d00fSChanwoo Choi {
23b225d00fSChanwoo Choi extcon_dev_free(*(struct extcon_dev **)res);
24b225d00fSChanwoo Choi }
25b225d00fSChanwoo Choi
26b225d00fSChanwoo Choi
devm_extcon_dev_unreg(struct device * dev,void * res)27b225d00fSChanwoo Choi static void devm_extcon_dev_unreg(struct device *dev, void *res)
28b225d00fSChanwoo Choi {
29b225d00fSChanwoo Choi extcon_dev_unregister(*(struct extcon_dev **)res);
30b225d00fSChanwoo Choi }
31b225d00fSChanwoo Choi
3258f38656SChanwoo Choi struct extcon_dev_notifier_devres {
3358f38656SChanwoo Choi struct extcon_dev *edev;
3458f38656SChanwoo Choi unsigned int id;
3558f38656SChanwoo Choi struct notifier_block *nb;
3658f38656SChanwoo Choi };
3758f38656SChanwoo Choi
devm_extcon_dev_notifier_unreg(struct device * dev,void * res)3858f38656SChanwoo Choi static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res)
3958f38656SChanwoo Choi {
4058f38656SChanwoo Choi struct extcon_dev_notifier_devres *this = res;
4158f38656SChanwoo Choi
4258f38656SChanwoo Choi extcon_unregister_notifier(this->edev, this->id, this->nb);
4358f38656SChanwoo Choi }
4458f38656SChanwoo Choi
devm_extcon_dev_notifier_all_unreg(struct device * dev,void * res)45815429b3SChanwoo Choi static void devm_extcon_dev_notifier_all_unreg(struct device *dev, void *res)
46815429b3SChanwoo Choi {
47815429b3SChanwoo Choi struct extcon_dev_notifier_devres *this = res;
48815429b3SChanwoo Choi
49815429b3SChanwoo Choi extcon_unregister_notifier_all(this->edev, this->nb);
50815429b3SChanwoo Choi }
51815429b3SChanwoo Choi
52b225d00fSChanwoo Choi /**
53b225d00fSChanwoo Choi * devm_extcon_dev_allocate - Allocate managed extcon device
546ab6094fSChanwoo Choi * @dev: the device owning the extcon device being created
556ab6094fSChanwoo Choi * @supported_cable: the array of the supported external connectors
566ab6094fSChanwoo Choi * ending with EXTCON_NONE.
57b225d00fSChanwoo Choi *
58b225d00fSChanwoo Choi * This function manages automatically the memory of extcon device using device
59b225d00fSChanwoo Choi * resource management and simplify the control of freeing the memory of extcon
60b225d00fSChanwoo Choi * device.
61b225d00fSChanwoo Choi *
62b225d00fSChanwoo Choi * Returns the pointer memory of allocated extcon_dev if success
63b225d00fSChanwoo Choi * or ERR_PTR(err) if fail
64b225d00fSChanwoo Choi */
devm_extcon_dev_allocate(struct device * dev,const unsigned int * supported_cable)65b225d00fSChanwoo Choi struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
66b225d00fSChanwoo Choi const unsigned int *supported_cable)
67b225d00fSChanwoo Choi {
68b225d00fSChanwoo Choi struct extcon_dev **ptr, *edev;
69b225d00fSChanwoo Choi
70b225d00fSChanwoo Choi ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL);
71b225d00fSChanwoo Choi if (!ptr)
72b225d00fSChanwoo Choi return ERR_PTR(-ENOMEM);
73b225d00fSChanwoo Choi
74b225d00fSChanwoo Choi edev = extcon_dev_allocate(supported_cable);
75b225d00fSChanwoo Choi if (IS_ERR(edev)) {
76b225d00fSChanwoo Choi devres_free(ptr);
77b225d00fSChanwoo Choi return edev;
78b225d00fSChanwoo Choi }
79b225d00fSChanwoo Choi
80b225d00fSChanwoo Choi edev->dev.parent = dev;
81b225d00fSChanwoo Choi
82b225d00fSChanwoo Choi *ptr = edev;
83b225d00fSChanwoo Choi devres_add(dev, ptr);
84b225d00fSChanwoo Choi
85b225d00fSChanwoo Choi return edev;
86b225d00fSChanwoo Choi }
87b225d00fSChanwoo Choi EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate);
88b225d00fSChanwoo Choi
89b225d00fSChanwoo Choi /**
90b225d00fSChanwoo Choi * devm_extcon_dev_free() - Resource-managed extcon_dev_unregister()
916ab6094fSChanwoo Choi * @dev: the device owning the extcon device being created
926ab6094fSChanwoo Choi * @edev: the extcon device to be freed
93b225d00fSChanwoo Choi *
94b225d00fSChanwoo Choi * Free the memory that is allocated with devm_extcon_dev_allocate()
95b225d00fSChanwoo Choi * function.
96b225d00fSChanwoo Choi */
devm_extcon_dev_free(struct device * dev,struct extcon_dev * edev)97b225d00fSChanwoo Choi void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev)
98b225d00fSChanwoo Choi {
99b225d00fSChanwoo Choi WARN_ON(devres_release(dev, devm_extcon_dev_release,
100b225d00fSChanwoo Choi devm_extcon_dev_match, edev));
101b225d00fSChanwoo Choi }
102b225d00fSChanwoo Choi EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
103b225d00fSChanwoo Choi
104b225d00fSChanwoo Choi /**
105b225d00fSChanwoo Choi * devm_extcon_dev_register() - Resource-managed extcon_dev_register()
1066ab6094fSChanwoo Choi * @dev: the device owning the extcon device being created
1076ab6094fSChanwoo Choi * @edev: the extcon device to be registered
108b225d00fSChanwoo Choi *
109b225d00fSChanwoo Choi * this function, that extcon device is automatically unregistered on driver
110b225d00fSChanwoo Choi * detach. Internally this function calls extcon_dev_register() function.
111b225d00fSChanwoo Choi * To get more information, refer that function.
112b225d00fSChanwoo Choi *
113b225d00fSChanwoo Choi * If extcon device is registered with this function and the device needs to be
114b225d00fSChanwoo Choi * unregistered separately, devm_extcon_dev_unregister() should be used.
115b225d00fSChanwoo Choi *
116b225d00fSChanwoo Choi * Returns 0 if success or negaive error number if failure.
117b225d00fSChanwoo Choi */
devm_extcon_dev_register(struct device * dev,struct extcon_dev * edev)118b225d00fSChanwoo Choi int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev)
119b225d00fSChanwoo Choi {
120b225d00fSChanwoo Choi struct extcon_dev **ptr;
121b225d00fSChanwoo Choi int ret;
122b225d00fSChanwoo Choi
123b225d00fSChanwoo Choi ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL);
124b225d00fSChanwoo Choi if (!ptr)
125b225d00fSChanwoo Choi return -ENOMEM;
126b225d00fSChanwoo Choi
127b225d00fSChanwoo Choi ret = extcon_dev_register(edev);
128b225d00fSChanwoo Choi if (ret) {
129b225d00fSChanwoo Choi devres_free(ptr);
130b225d00fSChanwoo Choi return ret;
131b225d00fSChanwoo Choi }
132b225d00fSChanwoo Choi
133b225d00fSChanwoo Choi *ptr = edev;
134b225d00fSChanwoo Choi devres_add(dev, ptr);
135b225d00fSChanwoo Choi
136b225d00fSChanwoo Choi return 0;
137b225d00fSChanwoo Choi }
138b225d00fSChanwoo Choi EXPORT_SYMBOL_GPL(devm_extcon_dev_register);
139b225d00fSChanwoo Choi
140b225d00fSChanwoo Choi /**
141b225d00fSChanwoo Choi * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister()
1426ab6094fSChanwoo Choi * @dev: the device owning the extcon device being created
1436ab6094fSChanwoo Choi * @edev: the extcon device to unregistered
144b225d00fSChanwoo Choi *
145b225d00fSChanwoo Choi * Unregister extcon device that is registered with devm_extcon_dev_register()
146b225d00fSChanwoo Choi * function.
147b225d00fSChanwoo Choi */
devm_extcon_dev_unregister(struct device * dev,struct extcon_dev * edev)148b225d00fSChanwoo Choi void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev)
149b225d00fSChanwoo Choi {
150b225d00fSChanwoo Choi WARN_ON(devres_release(dev, devm_extcon_dev_unreg,
151b225d00fSChanwoo Choi devm_extcon_dev_match, edev));
152b225d00fSChanwoo Choi }
153b225d00fSChanwoo Choi EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister);
15458f38656SChanwoo Choi
15558f38656SChanwoo Choi /**
15658f38656SChanwoo Choi * devm_extcon_register_notifier() - Resource-managed extcon_register_notifier()
1576ab6094fSChanwoo Choi * @dev: the device owning the extcon device being created
1586ab6094fSChanwoo Choi * @edev: the extcon device
1596ab6094fSChanwoo Choi * @id: the unique id among the extcon enumeration
1606ab6094fSChanwoo Choi * @nb: a notifier block to be registered
16158f38656SChanwoo Choi *
16258f38656SChanwoo Choi * This function manages automatically the notifier of extcon device using
16358f38656SChanwoo Choi * device resource management and simplify the control of unregistering
16458f38656SChanwoo Choi * the notifier of extcon device.
16558f38656SChanwoo Choi *
16658f38656SChanwoo Choi * Note that the second parameter given to the callback of nb (val) is
16758f38656SChanwoo Choi * "old_state", not the current state. The current state can be retrieved
16858f38656SChanwoo Choi * by looking at the third pameter (edev pointer)'s state value.
16958f38656SChanwoo Choi *
17058f38656SChanwoo Choi * Returns 0 if success or negaive error number if failure.
17158f38656SChanwoo Choi */
devm_extcon_register_notifier(struct device * dev,struct extcon_dev * edev,unsigned int id,struct notifier_block * nb)17258f38656SChanwoo Choi int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev,
17358f38656SChanwoo Choi unsigned int id, struct notifier_block *nb)
17458f38656SChanwoo Choi {
17558f38656SChanwoo Choi struct extcon_dev_notifier_devres *ptr;
17658f38656SChanwoo Choi int ret;
17758f38656SChanwoo Choi
17858f38656SChanwoo Choi ptr = devres_alloc(devm_extcon_dev_notifier_unreg, sizeof(*ptr),
17958f38656SChanwoo Choi GFP_KERNEL);
18058f38656SChanwoo Choi if (!ptr)
18158f38656SChanwoo Choi return -ENOMEM;
18258f38656SChanwoo Choi
18358f38656SChanwoo Choi ret = extcon_register_notifier(edev, id, nb);
18458f38656SChanwoo Choi if (ret) {
18558f38656SChanwoo Choi devres_free(ptr);
18658f38656SChanwoo Choi return ret;
18758f38656SChanwoo Choi }
18858f38656SChanwoo Choi
18958f38656SChanwoo Choi ptr->edev = edev;
19058f38656SChanwoo Choi ptr->id = id;
19158f38656SChanwoo Choi ptr->nb = nb;
19258f38656SChanwoo Choi devres_add(dev, ptr);
19358f38656SChanwoo Choi
19458f38656SChanwoo Choi return 0;
19558f38656SChanwoo Choi }
19658f38656SChanwoo Choi EXPORT_SYMBOL(devm_extcon_register_notifier);
19758f38656SChanwoo Choi
19858f38656SChanwoo Choi /**
19958f38656SChanwoo Choi * devm_extcon_unregister_notifier()
200db8b4aefSValdis Klētnieks * - Resource-managed extcon_unregister_notifier()
2016ab6094fSChanwoo Choi * @dev: the device owning the extcon device being created
2026ab6094fSChanwoo Choi * @edev: the extcon device
2036ab6094fSChanwoo Choi * @id: the unique id among the extcon enumeration
2046ab6094fSChanwoo Choi * @nb: a notifier block to be registered
20558f38656SChanwoo Choi */
devm_extcon_unregister_notifier(struct device * dev,struct extcon_dev * edev,unsigned int id,struct notifier_block * nb)20658f38656SChanwoo Choi void devm_extcon_unregister_notifier(struct device *dev,
20758f38656SChanwoo Choi struct extcon_dev *edev, unsigned int id,
20858f38656SChanwoo Choi struct notifier_block *nb)
20958f38656SChanwoo Choi {
21058f38656SChanwoo Choi WARN_ON(devres_release(dev, devm_extcon_dev_notifier_unreg,
21158f38656SChanwoo Choi devm_extcon_dev_match, edev));
21258f38656SChanwoo Choi }
21358f38656SChanwoo Choi EXPORT_SYMBOL(devm_extcon_unregister_notifier);
214815429b3SChanwoo Choi
215815429b3SChanwoo Choi /**
216815429b3SChanwoo Choi * devm_extcon_register_notifier_all()
217815429b3SChanwoo Choi * - Resource-managed extcon_register_notifier_all()
2186ab6094fSChanwoo Choi * @dev: the device owning the extcon device being created
2196ab6094fSChanwoo Choi * @edev: the extcon device
2206ab6094fSChanwoo Choi * @nb: a notifier block to be registered
221815429b3SChanwoo Choi *
222815429b3SChanwoo Choi * This function manages automatically the notifier of extcon device using
223815429b3SChanwoo Choi * device resource management and simplify the control of unregistering
224815429b3SChanwoo Choi * the notifier of extcon device. To get more information, refer that function.
225815429b3SChanwoo Choi *
226815429b3SChanwoo Choi * Returns 0 if success or negaive error number if failure.
227815429b3SChanwoo Choi */
devm_extcon_register_notifier_all(struct device * dev,struct extcon_dev * edev,struct notifier_block * nb)228815429b3SChanwoo Choi int devm_extcon_register_notifier_all(struct device *dev, struct extcon_dev *edev,
229815429b3SChanwoo Choi struct notifier_block *nb)
230815429b3SChanwoo Choi {
231815429b3SChanwoo Choi struct extcon_dev_notifier_devres *ptr;
232815429b3SChanwoo Choi int ret;
233815429b3SChanwoo Choi
234815429b3SChanwoo Choi ptr = devres_alloc(devm_extcon_dev_notifier_all_unreg, sizeof(*ptr),
235815429b3SChanwoo Choi GFP_KERNEL);
236815429b3SChanwoo Choi if (!ptr)
237815429b3SChanwoo Choi return -ENOMEM;
238815429b3SChanwoo Choi
239815429b3SChanwoo Choi ret = extcon_register_notifier_all(edev, nb);
240815429b3SChanwoo Choi if (ret) {
241815429b3SChanwoo Choi devres_free(ptr);
242815429b3SChanwoo Choi return ret;
243815429b3SChanwoo Choi }
244815429b3SChanwoo Choi
245815429b3SChanwoo Choi ptr->edev = edev;
246815429b3SChanwoo Choi ptr->nb = nb;
247815429b3SChanwoo Choi devres_add(dev, ptr);
248815429b3SChanwoo Choi
249815429b3SChanwoo Choi return 0;
250815429b3SChanwoo Choi }
251815429b3SChanwoo Choi EXPORT_SYMBOL(devm_extcon_register_notifier_all);
252815429b3SChanwoo Choi
253815429b3SChanwoo Choi /**
254815429b3SChanwoo Choi * devm_extcon_unregister_notifier_all()
255815429b3SChanwoo Choi * - Resource-managed extcon_unregister_notifier_all()
2566ab6094fSChanwoo Choi * @dev: the device owning the extcon device being created
2576ab6094fSChanwoo Choi * @edev: the extcon device
2586ab6094fSChanwoo Choi * @nb: a notifier block to be registered
259815429b3SChanwoo Choi */
devm_extcon_unregister_notifier_all(struct device * dev,struct extcon_dev * edev,struct notifier_block * nb)260815429b3SChanwoo Choi void devm_extcon_unregister_notifier_all(struct device *dev,
261815429b3SChanwoo Choi struct extcon_dev *edev,
262815429b3SChanwoo Choi struct notifier_block *nb)
263815429b3SChanwoo Choi {
264815429b3SChanwoo Choi WARN_ON(devres_release(dev, devm_extcon_dev_notifier_all_unreg,
265815429b3SChanwoo Choi devm_extcon_dev_match, edev));
266815429b3SChanwoo Choi }
267815429b3SChanwoo Choi EXPORT_SYMBOL(devm_extcon_unregister_notifier_all);
268