xref: /linux-6.15/drivers/extcon/devres.c (revision b225d00f)
1 /*
2  *  drivers/extcon/devres.c - EXTCON device's resource management
3  *
4  * Copyright (C) 2016 Samsung Electronics
5  * Author: Chanwoo Choi <[email protected]>
6  *
7  * This software is licensed under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation, and
9  * may be copied, distributed, and modified under those terms.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 
17 #include <linux/extcon.h>
18 
19 static int devm_extcon_dev_match(struct device *dev, void *res, void *data)
20 {
21 	struct extcon_dev **r = res;
22 
23 	if (WARN_ON(!r || !*r))
24 		return 0;
25 
26 	return *r == data;
27 }
28 
29 static void devm_extcon_dev_release(struct device *dev, void *res)
30 {
31 	extcon_dev_free(*(struct extcon_dev **)res);
32 }
33 
34 
35 static void devm_extcon_dev_unreg(struct device *dev, void *res)
36 {
37 	extcon_dev_unregister(*(struct extcon_dev **)res);
38 }
39 
40 /**
41  * devm_extcon_dev_allocate - Allocate managed extcon device
42  * @dev:		device owning the extcon device being created
43  * @supported_cable:	Array of supported extcon ending with EXTCON_NONE.
44  *			If supported_cable is NULL, cable name related APIs
45  *			are disabled.
46  *
47  * This function manages automatically the memory of extcon device using device
48  * resource management and simplify the control of freeing the memory of extcon
49  * device.
50  *
51  * Returns the pointer memory of allocated extcon_dev if success
52  * or ERR_PTR(err) if fail
53  */
54 struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
55 					const unsigned int *supported_cable)
56 {
57 	struct extcon_dev **ptr, *edev;
58 
59 	ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL);
60 	if (!ptr)
61 		return ERR_PTR(-ENOMEM);
62 
63 	edev = extcon_dev_allocate(supported_cable);
64 	if (IS_ERR(edev)) {
65 		devres_free(ptr);
66 		return edev;
67 	}
68 
69 	edev->dev.parent = dev;
70 
71 	*ptr = edev;
72 	devres_add(dev, ptr);
73 
74 	return edev;
75 }
76 EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate);
77 
78 /**
79  * devm_extcon_dev_free() - Resource-managed extcon_dev_unregister()
80  * @dev:	device the extcon belongs to
81  * @edev:	the extcon device to unregister
82  *
83  * Free the memory that is allocated with devm_extcon_dev_allocate()
84  * function.
85  */
86 void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev)
87 {
88 	WARN_ON(devres_release(dev, devm_extcon_dev_release,
89 			       devm_extcon_dev_match, edev));
90 }
91 EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
92 
93 /**
94  * devm_extcon_dev_register() - Resource-managed extcon_dev_register()
95  * @dev:	device to allocate extcon device
96  * @edev:	the new extcon device to register
97  *
98  * Managed extcon_dev_register() function. If extcon device is attached with
99  * this function, that extcon device is automatically unregistered on driver
100  * detach. Internally this function calls extcon_dev_register() function.
101  * To get more information, refer that function.
102  *
103  * If extcon device is registered with this function and the device needs to be
104  * unregistered separately, devm_extcon_dev_unregister() should be used.
105  *
106  * Returns 0 if success or negaive error number if failure.
107  */
108 int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev)
109 {
110 	struct extcon_dev **ptr;
111 	int ret;
112 
113 	ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL);
114 	if (!ptr)
115 		return -ENOMEM;
116 
117 	ret = extcon_dev_register(edev);
118 	if (ret) {
119 		devres_free(ptr);
120 		return ret;
121 	}
122 
123 	*ptr = edev;
124 	devres_add(dev, ptr);
125 
126 	return 0;
127 }
128 EXPORT_SYMBOL_GPL(devm_extcon_dev_register);
129 
130 /**
131  * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister()
132  * @dev:	device the extcon belongs to
133  * @edev:	the extcon device to unregister
134  *
135  * Unregister extcon device that is registered with devm_extcon_dev_register()
136  * function.
137  */
138 void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev)
139 {
140 	WARN_ON(devres_release(dev, devm_extcon_dev_unreg,
141 			       devm_extcon_dev_match, edev));
142 }
143 EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister);
144