xref: /linux-6.15/drivers/extcon/extcon.c (revision f68a8342)
1*f68a8342SChanwoo Choi /*
2*f68a8342SChanwoo Choi  *  drivers/extcon/extcon_class.c
3*f68a8342SChanwoo Choi  *
4*f68a8342SChanwoo Choi  *  External connector (extcon) class driver
5*f68a8342SChanwoo Choi  *
6*f68a8342SChanwoo Choi  * Copyright (C) 2012 Samsung Electronics
7*f68a8342SChanwoo Choi  * Author: Donggeun Kim <[email protected]>
8*f68a8342SChanwoo Choi  * Author: MyungJoo Ham <[email protected]>
9*f68a8342SChanwoo Choi  *
10*f68a8342SChanwoo Choi  * based on android/drivers/switch/switch_class.c
11*f68a8342SChanwoo Choi  * Copyright (C) 2008 Google, Inc.
12*f68a8342SChanwoo Choi  * Author: Mike Lockwood <[email protected]>
13*f68a8342SChanwoo Choi  *
14*f68a8342SChanwoo Choi  * This software is licensed under the terms of the GNU General Public
15*f68a8342SChanwoo Choi  * License version 2, as published by the Free Software Foundation, and
16*f68a8342SChanwoo Choi  * may be copied, distributed, and modified under those terms.
17*f68a8342SChanwoo Choi  *
18*f68a8342SChanwoo Choi  * This program is distributed in the hope that it will be useful,
19*f68a8342SChanwoo Choi  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20*f68a8342SChanwoo Choi  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21*f68a8342SChanwoo Choi  * GNU General Public License for more details.
22*f68a8342SChanwoo Choi  *
23*f68a8342SChanwoo Choi */
24*f68a8342SChanwoo Choi 
25*f68a8342SChanwoo Choi #include <linux/module.h>
26*f68a8342SChanwoo Choi #include <linux/types.h>
27*f68a8342SChanwoo Choi #include <linux/init.h>
28*f68a8342SChanwoo Choi #include <linux/device.h>
29*f68a8342SChanwoo Choi #include <linux/fs.h>
30*f68a8342SChanwoo Choi #include <linux/err.h>
31*f68a8342SChanwoo Choi #include <linux/extcon.h>
32*f68a8342SChanwoo Choi #include <linux/of.h>
33*f68a8342SChanwoo Choi #include <linux/slab.h>
34*f68a8342SChanwoo Choi #include <linux/sysfs.h>
35*f68a8342SChanwoo Choi 
36*f68a8342SChanwoo Choi /*
37*f68a8342SChanwoo Choi  * extcon_cable_name suggests the standard cable names for commonly used
38*f68a8342SChanwoo Choi  * cable types.
39*f68a8342SChanwoo Choi  *
40*f68a8342SChanwoo Choi  * However, please do not use extcon_cable_name directly for extcon_dev
41*f68a8342SChanwoo Choi  * struct's supported_cable pointer unless your device really supports
42*f68a8342SChanwoo Choi  * every single port-type of the following cable names. Please choose cable
43*f68a8342SChanwoo Choi  * names that are actually used in your extcon device.
44*f68a8342SChanwoo Choi  */
45*f68a8342SChanwoo Choi const char extcon_cable_name[][CABLE_NAME_MAX + 1] = {
46*f68a8342SChanwoo Choi 	[EXTCON_USB]		= "USB",
47*f68a8342SChanwoo Choi 	[EXTCON_USB_HOST]	= "USB-Host",
48*f68a8342SChanwoo Choi 	[EXTCON_TA]		= "TA",
49*f68a8342SChanwoo Choi 	[EXTCON_FAST_CHARGER]	= "Fast-charger",
50*f68a8342SChanwoo Choi 	[EXTCON_SLOW_CHARGER]	= "Slow-charger",
51*f68a8342SChanwoo Choi 	[EXTCON_CHARGE_DOWNSTREAM]	= "Charge-downstream",
52*f68a8342SChanwoo Choi 	[EXTCON_HDMI]		= "HDMI",
53*f68a8342SChanwoo Choi 	[EXTCON_MHL]		= "MHL",
54*f68a8342SChanwoo Choi 	[EXTCON_DVI]		= "DVI",
55*f68a8342SChanwoo Choi 	[EXTCON_VGA]		= "VGA",
56*f68a8342SChanwoo Choi 	[EXTCON_DOCK]		= "Dock",
57*f68a8342SChanwoo Choi 	[EXTCON_LINE_IN]	= "Line-in",
58*f68a8342SChanwoo Choi 	[EXTCON_LINE_OUT]	= "Line-out",
59*f68a8342SChanwoo Choi 	[EXTCON_MIC_IN]		= "Microphone",
60*f68a8342SChanwoo Choi 	[EXTCON_HEADPHONE_OUT]	= "Headphone",
61*f68a8342SChanwoo Choi 	[EXTCON_SPDIF_IN]	= "SPDIF-in",
62*f68a8342SChanwoo Choi 	[EXTCON_SPDIF_OUT]	= "SPDIF-out",
63*f68a8342SChanwoo Choi 	[EXTCON_VIDEO_IN]	= "Video-in",
64*f68a8342SChanwoo Choi 	[EXTCON_VIDEO_OUT]	= "Video-out",
65*f68a8342SChanwoo Choi 	[EXTCON_MECHANICAL]	= "Mechanical",
66*f68a8342SChanwoo Choi };
67*f68a8342SChanwoo Choi 
68*f68a8342SChanwoo Choi static struct class *extcon_class;
69*f68a8342SChanwoo Choi #if defined(CONFIG_ANDROID)
70*f68a8342SChanwoo Choi static struct class_compat *switch_class;
71*f68a8342SChanwoo Choi #endif /* CONFIG_ANDROID */
72*f68a8342SChanwoo Choi 
73*f68a8342SChanwoo Choi static LIST_HEAD(extcon_dev_list);
74*f68a8342SChanwoo Choi static DEFINE_MUTEX(extcon_dev_list_lock);
75*f68a8342SChanwoo Choi 
76*f68a8342SChanwoo Choi /**
77*f68a8342SChanwoo Choi  * check_mutually_exclusive - Check if new_state violates mutually_exclusive
78*f68a8342SChanwoo Choi  *			      condition.
79*f68a8342SChanwoo Choi  * @edev:	the extcon device
80*f68a8342SChanwoo Choi  * @new_state:	new cable attach status for @edev
81*f68a8342SChanwoo Choi  *
82*f68a8342SChanwoo Choi  * Returns 0 if nothing violates. Returns the index + 1 for the first
83*f68a8342SChanwoo Choi  * violated condition.
84*f68a8342SChanwoo Choi  */
85*f68a8342SChanwoo Choi static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
86*f68a8342SChanwoo Choi {
87*f68a8342SChanwoo Choi 	int i = 0;
88*f68a8342SChanwoo Choi 
89*f68a8342SChanwoo Choi 	if (!edev->mutually_exclusive)
90*f68a8342SChanwoo Choi 		return 0;
91*f68a8342SChanwoo Choi 
92*f68a8342SChanwoo Choi 	for (i = 0; edev->mutually_exclusive[i]; i++) {
93*f68a8342SChanwoo Choi 		int weight;
94*f68a8342SChanwoo Choi 		u32 correspondants = new_state & edev->mutually_exclusive[i];
95*f68a8342SChanwoo Choi 
96*f68a8342SChanwoo Choi 		/* calculate the total number of bits set */
97*f68a8342SChanwoo Choi 		weight = hweight32(correspondants);
98*f68a8342SChanwoo Choi 		if (weight > 1)
99*f68a8342SChanwoo Choi 			return i + 1;
100*f68a8342SChanwoo Choi 	}
101*f68a8342SChanwoo Choi 
102*f68a8342SChanwoo Choi 	return 0;
103*f68a8342SChanwoo Choi }
104*f68a8342SChanwoo Choi 
105*f68a8342SChanwoo Choi static ssize_t state_show(struct device *dev, struct device_attribute *attr,
106*f68a8342SChanwoo Choi 			  char *buf)
107*f68a8342SChanwoo Choi {
108*f68a8342SChanwoo Choi 	int i, count = 0;
109*f68a8342SChanwoo Choi 	struct extcon_dev *edev = dev_get_drvdata(dev);
110*f68a8342SChanwoo Choi 
111*f68a8342SChanwoo Choi 	if (edev->print_state) {
112*f68a8342SChanwoo Choi 		int ret = edev->print_state(edev, buf);
113*f68a8342SChanwoo Choi 
114*f68a8342SChanwoo Choi 		if (ret >= 0)
115*f68a8342SChanwoo Choi 			return ret;
116*f68a8342SChanwoo Choi 		/* Use default if failed */
117*f68a8342SChanwoo Choi 	}
118*f68a8342SChanwoo Choi 
119*f68a8342SChanwoo Choi 	if (edev->max_supported == 0)
120*f68a8342SChanwoo Choi 		return sprintf(buf, "%u\n", edev->state);
121*f68a8342SChanwoo Choi 
122*f68a8342SChanwoo Choi 	for (i = 0; i < SUPPORTED_CABLE_MAX; i++) {
123*f68a8342SChanwoo Choi 		if (!edev->supported_cable[i])
124*f68a8342SChanwoo Choi 			break;
125*f68a8342SChanwoo Choi 		count += sprintf(buf + count, "%s=%d\n",
126*f68a8342SChanwoo Choi 				 edev->supported_cable[i],
127*f68a8342SChanwoo Choi 				 !!(edev->state & (1 << i)));
128*f68a8342SChanwoo Choi 	}
129*f68a8342SChanwoo Choi 
130*f68a8342SChanwoo Choi 	return count;
131*f68a8342SChanwoo Choi }
132*f68a8342SChanwoo Choi 
133*f68a8342SChanwoo Choi static ssize_t state_store(struct device *dev, struct device_attribute *attr,
134*f68a8342SChanwoo Choi 			   const char *buf, size_t count)
135*f68a8342SChanwoo Choi {
136*f68a8342SChanwoo Choi 	u32 state;
137*f68a8342SChanwoo Choi 	ssize_t ret = 0;
138*f68a8342SChanwoo Choi 	struct extcon_dev *edev = dev_get_drvdata(dev);
139*f68a8342SChanwoo Choi 
140*f68a8342SChanwoo Choi 	ret = sscanf(buf, "0x%x", &state);
141*f68a8342SChanwoo Choi 	if (ret == 0)
142*f68a8342SChanwoo Choi 		ret = -EINVAL;
143*f68a8342SChanwoo Choi 	else
144*f68a8342SChanwoo Choi 		ret = extcon_set_state(edev, state);
145*f68a8342SChanwoo Choi 
146*f68a8342SChanwoo Choi 	if (ret < 0)
147*f68a8342SChanwoo Choi 		return ret;
148*f68a8342SChanwoo Choi 
149*f68a8342SChanwoo Choi 	return count;
150*f68a8342SChanwoo Choi }
151*f68a8342SChanwoo Choi static DEVICE_ATTR_RW(state);
152*f68a8342SChanwoo Choi 
153*f68a8342SChanwoo Choi static ssize_t name_show(struct device *dev, struct device_attribute *attr,
154*f68a8342SChanwoo Choi 		char *buf)
155*f68a8342SChanwoo Choi {
156*f68a8342SChanwoo Choi 	struct extcon_dev *edev = dev_get_drvdata(dev);
157*f68a8342SChanwoo Choi 
158*f68a8342SChanwoo Choi 	/* Optional callback given by the user */
159*f68a8342SChanwoo Choi 	if (edev->print_name) {
160*f68a8342SChanwoo Choi 		int ret = edev->print_name(edev, buf);
161*f68a8342SChanwoo Choi 		if (ret >= 0)
162*f68a8342SChanwoo Choi 			return ret;
163*f68a8342SChanwoo Choi 	}
164*f68a8342SChanwoo Choi 
165*f68a8342SChanwoo Choi 	return sprintf(buf, "%s\n", dev_name(&edev->dev));
166*f68a8342SChanwoo Choi }
167*f68a8342SChanwoo Choi static DEVICE_ATTR_RO(name);
168*f68a8342SChanwoo Choi 
169*f68a8342SChanwoo Choi static ssize_t cable_name_show(struct device *dev,
170*f68a8342SChanwoo Choi 			       struct device_attribute *attr, char *buf)
171*f68a8342SChanwoo Choi {
172*f68a8342SChanwoo Choi 	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
173*f68a8342SChanwoo Choi 						  attr_name);
174*f68a8342SChanwoo Choi 
175*f68a8342SChanwoo Choi 	return sprintf(buf, "%s\n",
176*f68a8342SChanwoo Choi 		       cable->edev->supported_cable[cable->cable_index]);
177*f68a8342SChanwoo Choi }
178*f68a8342SChanwoo Choi 
179*f68a8342SChanwoo Choi static ssize_t cable_state_show(struct device *dev,
180*f68a8342SChanwoo Choi 				struct device_attribute *attr, char *buf)
181*f68a8342SChanwoo Choi {
182*f68a8342SChanwoo Choi 	struct extcon_cable *cable = container_of(attr, struct extcon_cable,
183*f68a8342SChanwoo Choi 						  attr_state);
184*f68a8342SChanwoo Choi 
185*f68a8342SChanwoo Choi 	return sprintf(buf, "%d\n",
186*f68a8342SChanwoo Choi 		       extcon_get_cable_state_(cable->edev,
187*f68a8342SChanwoo Choi 					       cable->cable_index));
188*f68a8342SChanwoo Choi }
189*f68a8342SChanwoo Choi 
190*f68a8342SChanwoo Choi /**
191*f68a8342SChanwoo Choi  * extcon_update_state() - Update the cable attach states of the extcon device
192*f68a8342SChanwoo Choi  *			   only for the masked bits.
193*f68a8342SChanwoo Choi  * @edev:	the extcon device
194*f68a8342SChanwoo Choi  * @mask:	the bit mask to designate updated bits.
195*f68a8342SChanwoo Choi  * @state:	new cable attach status for @edev
196*f68a8342SChanwoo Choi  *
197*f68a8342SChanwoo Choi  * Changing the state sends uevent with environment variable containing
198*f68a8342SChanwoo Choi  * the name of extcon device (envp[0]) and the state output (envp[1]).
199*f68a8342SChanwoo Choi  * Tizen uses this format for extcon device to get events from ports.
200*f68a8342SChanwoo Choi  * Android uses this format as well.
201*f68a8342SChanwoo Choi  *
202*f68a8342SChanwoo Choi  * Note that the notifier provides which bits are changed in the state
203*f68a8342SChanwoo Choi  * variable with the val parameter (second) to the callback.
204*f68a8342SChanwoo Choi  */
205*f68a8342SChanwoo Choi int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
206*f68a8342SChanwoo Choi {
207*f68a8342SChanwoo Choi 	char name_buf[120];
208*f68a8342SChanwoo Choi 	char state_buf[120];
209*f68a8342SChanwoo Choi 	char *prop_buf;
210*f68a8342SChanwoo Choi 	char *envp[3];
211*f68a8342SChanwoo Choi 	int env_offset = 0;
212*f68a8342SChanwoo Choi 	int length;
213*f68a8342SChanwoo Choi 	unsigned long flags;
214*f68a8342SChanwoo Choi 
215*f68a8342SChanwoo Choi 	spin_lock_irqsave(&edev->lock, flags);
216*f68a8342SChanwoo Choi 
217*f68a8342SChanwoo Choi 	if (edev->state != ((edev->state & ~mask) | (state & mask))) {
218*f68a8342SChanwoo Choi 		u32 old_state = edev->state;
219*f68a8342SChanwoo Choi 
220*f68a8342SChanwoo Choi 		if (check_mutually_exclusive(edev, (edev->state & ~mask) |
221*f68a8342SChanwoo Choi 						   (state & mask))) {
222*f68a8342SChanwoo Choi 			spin_unlock_irqrestore(&edev->lock, flags);
223*f68a8342SChanwoo Choi 			return -EPERM;
224*f68a8342SChanwoo Choi 		}
225*f68a8342SChanwoo Choi 
226*f68a8342SChanwoo Choi 		edev->state &= ~mask;
227*f68a8342SChanwoo Choi 		edev->state |= state & mask;
228*f68a8342SChanwoo Choi 
229*f68a8342SChanwoo Choi 		raw_notifier_call_chain(&edev->nh, old_state, edev);
230*f68a8342SChanwoo Choi 		/* This could be in interrupt handler */
231*f68a8342SChanwoo Choi 		prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
232*f68a8342SChanwoo Choi 		if (prop_buf) {
233*f68a8342SChanwoo Choi 			length = name_show(&edev->dev, NULL, prop_buf);
234*f68a8342SChanwoo Choi 			if (length > 0) {
235*f68a8342SChanwoo Choi 				if (prop_buf[length - 1] == '\n')
236*f68a8342SChanwoo Choi 					prop_buf[length - 1] = 0;
237*f68a8342SChanwoo Choi 				snprintf(name_buf, sizeof(name_buf),
238*f68a8342SChanwoo Choi 					"NAME=%s", prop_buf);
239*f68a8342SChanwoo Choi 				envp[env_offset++] = name_buf;
240*f68a8342SChanwoo Choi 			}
241*f68a8342SChanwoo Choi 			length = state_show(&edev->dev, NULL, prop_buf);
242*f68a8342SChanwoo Choi 			if (length > 0) {
243*f68a8342SChanwoo Choi 				if (prop_buf[length - 1] == '\n')
244*f68a8342SChanwoo Choi 					prop_buf[length - 1] = 0;
245*f68a8342SChanwoo Choi 				snprintf(state_buf, sizeof(state_buf),
246*f68a8342SChanwoo Choi 					"STATE=%s", prop_buf);
247*f68a8342SChanwoo Choi 				envp[env_offset++] = state_buf;
248*f68a8342SChanwoo Choi 			}
249*f68a8342SChanwoo Choi 			envp[env_offset] = NULL;
250*f68a8342SChanwoo Choi 			/* Unlock early before uevent */
251*f68a8342SChanwoo Choi 			spin_unlock_irqrestore(&edev->lock, flags);
252*f68a8342SChanwoo Choi 
253*f68a8342SChanwoo Choi 			kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp);
254*f68a8342SChanwoo Choi 			free_page((unsigned long)prop_buf);
255*f68a8342SChanwoo Choi 		} else {
256*f68a8342SChanwoo Choi 			/* Unlock early before uevent */
257*f68a8342SChanwoo Choi 			spin_unlock_irqrestore(&edev->lock, flags);
258*f68a8342SChanwoo Choi 
259*f68a8342SChanwoo Choi 			dev_err(&edev->dev, "out of memory in extcon_set_state\n");
260*f68a8342SChanwoo Choi 			kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE);
261*f68a8342SChanwoo Choi 		}
262*f68a8342SChanwoo Choi 	} else {
263*f68a8342SChanwoo Choi 		/* No changes */
264*f68a8342SChanwoo Choi 		spin_unlock_irqrestore(&edev->lock, flags);
265*f68a8342SChanwoo Choi 	}
266*f68a8342SChanwoo Choi 
267*f68a8342SChanwoo Choi 	return 0;
268*f68a8342SChanwoo Choi }
269*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_update_state);
270*f68a8342SChanwoo Choi 
271*f68a8342SChanwoo Choi /**
272*f68a8342SChanwoo Choi  * extcon_set_state() - Set the cable attach states of the extcon device.
273*f68a8342SChanwoo Choi  * @edev:	the extcon device
274*f68a8342SChanwoo Choi  * @state:	new cable attach status for @edev
275*f68a8342SChanwoo Choi  *
276*f68a8342SChanwoo Choi  * Note that notifier provides which bits are changed in the state
277*f68a8342SChanwoo Choi  * variable with the val parameter (second) to the callback.
278*f68a8342SChanwoo Choi  */
279*f68a8342SChanwoo Choi int extcon_set_state(struct extcon_dev *edev, u32 state)
280*f68a8342SChanwoo Choi {
281*f68a8342SChanwoo Choi 	return extcon_update_state(edev, 0xffffffff, state);
282*f68a8342SChanwoo Choi }
283*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_set_state);
284*f68a8342SChanwoo Choi 
285*f68a8342SChanwoo Choi /**
286*f68a8342SChanwoo Choi  * extcon_find_cable_index() - Get the cable index based on the cable name.
287*f68a8342SChanwoo Choi  * @edev:	the extcon device that has the cable.
288*f68a8342SChanwoo Choi  * @cable_name:	cable name to be searched.
289*f68a8342SChanwoo Choi  *
290*f68a8342SChanwoo Choi  * Note that accessing a cable state based on cable_index is faster than
291*f68a8342SChanwoo Choi  * cable_name because using cable_name induces a loop with strncmp().
292*f68a8342SChanwoo Choi  * Thus, when get/set_cable_state is repeatedly used, using cable_index
293*f68a8342SChanwoo Choi  * is recommended.
294*f68a8342SChanwoo Choi  */
295*f68a8342SChanwoo Choi int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name)
296*f68a8342SChanwoo Choi {
297*f68a8342SChanwoo Choi 	int i;
298*f68a8342SChanwoo Choi 
299*f68a8342SChanwoo Choi 	if (edev->supported_cable) {
300*f68a8342SChanwoo Choi 		for (i = 0; edev->supported_cable[i]; i++) {
301*f68a8342SChanwoo Choi 			if (!strncmp(edev->supported_cable[i],
302*f68a8342SChanwoo Choi 				cable_name, CABLE_NAME_MAX))
303*f68a8342SChanwoo Choi 				return i;
304*f68a8342SChanwoo Choi 		}
305*f68a8342SChanwoo Choi 	}
306*f68a8342SChanwoo Choi 
307*f68a8342SChanwoo Choi 	return -EINVAL;
308*f68a8342SChanwoo Choi }
309*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_find_cable_index);
310*f68a8342SChanwoo Choi 
311*f68a8342SChanwoo Choi /**
312*f68a8342SChanwoo Choi  * extcon_get_cable_state_() - Get the status of a specific cable.
313*f68a8342SChanwoo Choi  * @edev:	the extcon device that has the cable.
314*f68a8342SChanwoo Choi  * @index:	cable index that can be retrieved by extcon_find_cable_index().
315*f68a8342SChanwoo Choi  */
316*f68a8342SChanwoo Choi int extcon_get_cable_state_(struct extcon_dev *edev, int index)
317*f68a8342SChanwoo Choi {
318*f68a8342SChanwoo Choi 	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
319*f68a8342SChanwoo Choi 		return -EINVAL;
320*f68a8342SChanwoo Choi 
321*f68a8342SChanwoo Choi 	return !!(edev->state & (1 << index));
322*f68a8342SChanwoo Choi }
323*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
324*f68a8342SChanwoo Choi 
325*f68a8342SChanwoo Choi /**
326*f68a8342SChanwoo Choi  * extcon_get_cable_state() - Get the status of a specific cable.
327*f68a8342SChanwoo Choi  * @edev:	the extcon device that has the cable.
328*f68a8342SChanwoo Choi  * @cable_name:	cable name.
329*f68a8342SChanwoo Choi  *
330*f68a8342SChanwoo Choi  * Note that this is slower than extcon_get_cable_state_.
331*f68a8342SChanwoo Choi  */
332*f68a8342SChanwoo Choi int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
333*f68a8342SChanwoo Choi {
334*f68a8342SChanwoo Choi 	return extcon_get_cable_state_(edev, extcon_find_cable_index
335*f68a8342SChanwoo Choi 						(edev, cable_name));
336*f68a8342SChanwoo Choi }
337*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_get_cable_state);
338*f68a8342SChanwoo Choi 
339*f68a8342SChanwoo Choi /**
340*f68a8342SChanwoo Choi  * extcon_set_cable_state_() - Set the status of a specific cable.
341*f68a8342SChanwoo Choi  * @edev:		the extcon device that has the cable.
342*f68a8342SChanwoo Choi  * @index:		cable index that can be retrieved by
343*f68a8342SChanwoo Choi  *			extcon_find_cable_index().
344*f68a8342SChanwoo Choi  * @cable_state:	the new cable status. The default semantics is
345*f68a8342SChanwoo Choi  *			true: attached / false: detached.
346*f68a8342SChanwoo Choi  */
347*f68a8342SChanwoo Choi int extcon_set_cable_state_(struct extcon_dev *edev,
348*f68a8342SChanwoo Choi 			int index, bool cable_state)
349*f68a8342SChanwoo Choi {
350*f68a8342SChanwoo Choi 	u32 state;
351*f68a8342SChanwoo Choi 
352*f68a8342SChanwoo Choi 	if (index < 0 || (edev->max_supported && edev->max_supported <= index))
353*f68a8342SChanwoo Choi 		return -EINVAL;
354*f68a8342SChanwoo Choi 
355*f68a8342SChanwoo Choi 	state = cable_state ? (1 << index) : 0;
356*f68a8342SChanwoo Choi 	return extcon_update_state(edev, 1 << index, state);
357*f68a8342SChanwoo Choi }
358*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
359*f68a8342SChanwoo Choi 
360*f68a8342SChanwoo Choi /**
361*f68a8342SChanwoo Choi  * extcon_set_cable_state() - Set the status of a specific cable.
362*f68a8342SChanwoo Choi  * @edev:		the extcon device that has the cable.
363*f68a8342SChanwoo Choi  * @cable_name:		cable name.
364*f68a8342SChanwoo Choi  * @cable_state:	the new cable status. The default semantics is
365*f68a8342SChanwoo Choi  *			true: attached / false: detached.
366*f68a8342SChanwoo Choi  *
367*f68a8342SChanwoo Choi  * Note that this is slower than extcon_set_cable_state_.
368*f68a8342SChanwoo Choi  */
369*f68a8342SChanwoo Choi int extcon_set_cable_state(struct extcon_dev *edev,
370*f68a8342SChanwoo Choi 			const char *cable_name, bool cable_state)
371*f68a8342SChanwoo Choi {
372*f68a8342SChanwoo Choi 	return extcon_set_cable_state_(edev, extcon_find_cable_index
373*f68a8342SChanwoo Choi 					(edev, cable_name), cable_state);
374*f68a8342SChanwoo Choi }
375*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_set_cable_state);
376*f68a8342SChanwoo Choi 
377*f68a8342SChanwoo Choi /**
378*f68a8342SChanwoo Choi  * extcon_get_extcon_dev() - Get the extcon device instance from the name
379*f68a8342SChanwoo Choi  * @extcon_name:	The extcon name provided with extcon_dev_register()
380*f68a8342SChanwoo Choi  */
381*f68a8342SChanwoo Choi struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
382*f68a8342SChanwoo Choi {
383*f68a8342SChanwoo Choi 	struct extcon_dev *sd;
384*f68a8342SChanwoo Choi 
385*f68a8342SChanwoo Choi 	mutex_lock(&extcon_dev_list_lock);
386*f68a8342SChanwoo Choi 	list_for_each_entry(sd, &extcon_dev_list, entry) {
387*f68a8342SChanwoo Choi 		if (!strcmp(sd->name, extcon_name))
388*f68a8342SChanwoo Choi 			goto out;
389*f68a8342SChanwoo Choi 	}
390*f68a8342SChanwoo Choi 	sd = NULL;
391*f68a8342SChanwoo Choi out:
392*f68a8342SChanwoo Choi 	mutex_unlock(&extcon_dev_list_lock);
393*f68a8342SChanwoo Choi 	return sd;
394*f68a8342SChanwoo Choi }
395*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
396*f68a8342SChanwoo Choi 
397*f68a8342SChanwoo Choi static int _call_per_cable(struct notifier_block *nb, unsigned long val,
398*f68a8342SChanwoo Choi 			   void *ptr)
399*f68a8342SChanwoo Choi {
400*f68a8342SChanwoo Choi 	struct extcon_specific_cable_nb *obj = container_of(nb,
401*f68a8342SChanwoo Choi 			struct extcon_specific_cable_nb, internal_nb);
402*f68a8342SChanwoo Choi 	struct extcon_dev *edev = ptr;
403*f68a8342SChanwoo Choi 
404*f68a8342SChanwoo Choi 	if ((val & (1 << obj->cable_index)) !=
405*f68a8342SChanwoo Choi 	    (edev->state & (1 << obj->cable_index))) {
406*f68a8342SChanwoo Choi 		bool cable_state = true;
407*f68a8342SChanwoo Choi 
408*f68a8342SChanwoo Choi 		obj->previous_value = val;
409*f68a8342SChanwoo Choi 
410*f68a8342SChanwoo Choi 		if (val & (1 << obj->cable_index))
411*f68a8342SChanwoo Choi 			cable_state = false;
412*f68a8342SChanwoo Choi 
413*f68a8342SChanwoo Choi 		return obj->user_nb->notifier_call(obj->user_nb,
414*f68a8342SChanwoo Choi 				cable_state, ptr);
415*f68a8342SChanwoo Choi 	}
416*f68a8342SChanwoo Choi 
417*f68a8342SChanwoo Choi 	return NOTIFY_OK;
418*f68a8342SChanwoo Choi }
419*f68a8342SChanwoo Choi 
420*f68a8342SChanwoo Choi /**
421*f68a8342SChanwoo Choi  * extcon_register_interest() - Register a notifier for a state change of a
422*f68a8342SChanwoo Choi  *				specific cable, not an entier set of cables of a
423*f68a8342SChanwoo Choi  *				extcon device.
424*f68a8342SChanwoo Choi  * @obj:		an empty extcon_specific_cable_nb object to be returned.
425*f68a8342SChanwoo Choi  * @extcon_name:	the name of extcon device.
426*f68a8342SChanwoo Choi  *			if NULL, extcon_register_interest will register
427*f68a8342SChanwoo Choi  *			every cable with the target cable_name given.
428*f68a8342SChanwoo Choi  * @cable_name:		the target cable name.
429*f68a8342SChanwoo Choi  * @nb:			the notifier block to get notified.
430*f68a8342SChanwoo Choi  *
431*f68a8342SChanwoo Choi  * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets
432*f68a8342SChanwoo Choi  * the struct for you.
433*f68a8342SChanwoo Choi  *
434*f68a8342SChanwoo Choi  * extcon_register_interest is a helper function for those who want to get
435*f68a8342SChanwoo Choi  * notification for a single specific cable's status change. If a user wants
436*f68a8342SChanwoo Choi  * to get notification for any changes of all cables of a extcon device,
437*f68a8342SChanwoo Choi  * he/she should use the general extcon_register_notifier().
438*f68a8342SChanwoo Choi  *
439*f68a8342SChanwoo Choi  * Note that the second parameter given to the callback of nb (val) is
440*f68a8342SChanwoo Choi  * "old_state", not the current state. The current state can be retrieved
441*f68a8342SChanwoo Choi  * by looking at the third pameter (edev pointer)'s state value.
442*f68a8342SChanwoo Choi  */
443*f68a8342SChanwoo Choi int extcon_register_interest(struct extcon_specific_cable_nb *obj,
444*f68a8342SChanwoo Choi 			     const char *extcon_name, const char *cable_name,
445*f68a8342SChanwoo Choi 			     struct notifier_block *nb)
446*f68a8342SChanwoo Choi {
447*f68a8342SChanwoo Choi 	if (!obj || !cable_name || !nb)
448*f68a8342SChanwoo Choi 		return -EINVAL;
449*f68a8342SChanwoo Choi 
450*f68a8342SChanwoo Choi 	if (extcon_name) {
451*f68a8342SChanwoo Choi 		obj->edev = extcon_get_extcon_dev(extcon_name);
452*f68a8342SChanwoo Choi 		if (!obj->edev)
453*f68a8342SChanwoo Choi 			return -ENODEV;
454*f68a8342SChanwoo Choi 
455*f68a8342SChanwoo Choi 		obj->cable_index = extcon_find_cable_index(obj->edev,
456*f68a8342SChanwoo Choi 							  cable_name);
457*f68a8342SChanwoo Choi 		if (obj->cable_index < 0)
458*f68a8342SChanwoo Choi 			return obj->cable_index;
459*f68a8342SChanwoo Choi 
460*f68a8342SChanwoo Choi 		obj->user_nb = nb;
461*f68a8342SChanwoo Choi 
462*f68a8342SChanwoo Choi 		obj->internal_nb.notifier_call = _call_per_cable;
463*f68a8342SChanwoo Choi 
464*f68a8342SChanwoo Choi 		return raw_notifier_chain_register(&obj->edev->nh,
465*f68a8342SChanwoo Choi 						  &obj->internal_nb);
466*f68a8342SChanwoo Choi 	} else {
467*f68a8342SChanwoo Choi 		struct class_dev_iter iter;
468*f68a8342SChanwoo Choi 		struct extcon_dev *extd;
469*f68a8342SChanwoo Choi 		struct device *dev;
470*f68a8342SChanwoo Choi 
471*f68a8342SChanwoo Choi 		if (!extcon_class)
472*f68a8342SChanwoo Choi 			return -ENODEV;
473*f68a8342SChanwoo Choi 		class_dev_iter_init(&iter, extcon_class, NULL, NULL);
474*f68a8342SChanwoo Choi 		while ((dev = class_dev_iter_next(&iter))) {
475*f68a8342SChanwoo Choi 			extd = dev_get_drvdata(dev);
476*f68a8342SChanwoo Choi 
477*f68a8342SChanwoo Choi 			if (extcon_find_cable_index(extd, cable_name) < 0)
478*f68a8342SChanwoo Choi 				continue;
479*f68a8342SChanwoo Choi 
480*f68a8342SChanwoo Choi 			class_dev_iter_exit(&iter);
481*f68a8342SChanwoo Choi 			return extcon_register_interest(obj, extd->name,
482*f68a8342SChanwoo Choi 						cable_name, nb);
483*f68a8342SChanwoo Choi 		}
484*f68a8342SChanwoo Choi 
485*f68a8342SChanwoo Choi 		return -ENODEV;
486*f68a8342SChanwoo Choi 	}
487*f68a8342SChanwoo Choi }
488*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_register_interest);
489*f68a8342SChanwoo Choi 
490*f68a8342SChanwoo Choi /**
491*f68a8342SChanwoo Choi  * extcon_unregister_interest() - Unregister the notifier registered by
492*f68a8342SChanwoo Choi  *				  extcon_register_interest().
493*f68a8342SChanwoo Choi  * @obj:	the extcon_specific_cable_nb object returned by
494*f68a8342SChanwoo Choi  *		extcon_register_interest().
495*f68a8342SChanwoo Choi  */
496*f68a8342SChanwoo Choi int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
497*f68a8342SChanwoo Choi {
498*f68a8342SChanwoo Choi 	if (!obj)
499*f68a8342SChanwoo Choi 		return -EINVAL;
500*f68a8342SChanwoo Choi 
501*f68a8342SChanwoo Choi 	return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
502*f68a8342SChanwoo Choi }
503*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_unregister_interest);
504*f68a8342SChanwoo Choi 
505*f68a8342SChanwoo Choi /**
506*f68a8342SChanwoo Choi  * extcon_register_notifier() - Register a notifiee to get notified by
507*f68a8342SChanwoo Choi  *				any attach status changes from the extcon.
508*f68a8342SChanwoo Choi  * @edev:	the extcon device.
509*f68a8342SChanwoo Choi  * @nb:		a notifier block to be registered.
510*f68a8342SChanwoo Choi  *
511*f68a8342SChanwoo Choi  * Note that the second parameter given to the callback of nb (val) is
512*f68a8342SChanwoo Choi  * "old_state", not the current state. The current state can be retrieved
513*f68a8342SChanwoo Choi  * by looking at the third pameter (edev pointer)'s state value.
514*f68a8342SChanwoo Choi  */
515*f68a8342SChanwoo Choi int extcon_register_notifier(struct extcon_dev *edev,
516*f68a8342SChanwoo Choi 			struct notifier_block *nb)
517*f68a8342SChanwoo Choi {
518*f68a8342SChanwoo Choi 	return raw_notifier_chain_register(&edev->nh, nb);
519*f68a8342SChanwoo Choi }
520*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_register_notifier);
521*f68a8342SChanwoo Choi 
522*f68a8342SChanwoo Choi /**
523*f68a8342SChanwoo Choi  * extcon_unregister_notifier() - Unregister a notifiee from the extcon device.
524*f68a8342SChanwoo Choi  * @edev:	the extcon device.
525*f68a8342SChanwoo Choi  * @nb:		a registered notifier block to be unregistered.
526*f68a8342SChanwoo Choi  */
527*f68a8342SChanwoo Choi int extcon_unregister_notifier(struct extcon_dev *edev,
528*f68a8342SChanwoo Choi 			struct notifier_block *nb)
529*f68a8342SChanwoo Choi {
530*f68a8342SChanwoo Choi 	return raw_notifier_chain_unregister(&edev->nh, nb);
531*f68a8342SChanwoo Choi }
532*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
533*f68a8342SChanwoo Choi 
534*f68a8342SChanwoo Choi static struct attribute *extcon_attrs[] = {
535*f68a8342SChanwoo Choi 	&dev_attr_state.attr,
536*f68a8342SChanwoo Choi 	&dev_attr_name.attr,
537*f68a8342SChanwoo Choi 	NULL,
538*f68a8342SChanwoo Choi };
539*f68a8342SChanwoo Choi ATTRIBUTE_GROUPS(extcon);
540*f68a8342SChanwoo Choi 
541*f68a8342SChanwoo Choi static int create_extcon_class(void)
542*f68a8342SChanwoo Choi {
543*f68a8342SChanwoo Choi 	if (!extcon_class) {
544*f68a8342SChanwoo Choi 		extcon_class = class_create(THIS_MODULE, "extcon");
545*f68a8342SChanwoo Choi 		if (IS_ERR(extcon_class))
546*f68a8342SChanwoo Choi 			return PTR_ERR(extcon_class);
547*f68a8342SChanwoo Choi 		extcon_class->dev_groups = extcon_groups;
548*f68a8342SChanwoo Choi 
549*f68a8342SChanwoo Choi #if defined(CONFIG_ANDROID)
550*f68a8342SChanwoo Choi 		switch_class = class_compat_register("switch");
551*f68a8342SChanwoo Choi 		if (WARN(!switch_class, "cannot allocate"))
552*f68a8342SChanwoo Choi 			return -ENOMEM;
553*f68a8342SChanwoo Choi #endif /* CONFIG_ANDROID */
554*f68a8342SChanwoo Choi 	}
555*f68a8342SChanwoo Choi 
556*f68a8342SChanwoo Choi 	return 0;
557*f68a8342SChanwoo Choi }
558*f68a8342SChanwoo Choi 
559*f68a8342SChanwoo Choi static void extcon_dev_release(struct device *dev)
560*f68a8342SChanwoo Choi {
561*f68a8342SChanwoo Choi }
562*f68a8342SChanwoo Choi 
563*f68a8342SChanwoo Choi static const char *muex_name = "mutually_exclusive";
564*f68a8342SChanwoo Choi static void dummy_sysfs_dev_release(struct device *dev)
565*f68a8342SChanwoo Choi {
566*f68a8342SChanwoo Choi }
567*f68a8342SChanwoo Choi 
568*f68a8342SChanwoo Choi /*
569*f68a8342SChanwoo Choi  * extcon_dev_allocate() - Allocate the memory of extcon device.
570*f68a8342SChanwoo Choi  * @supported_cable:	Array of supported cable names ending with NULL.
571*f68a8342SChanwoo Choi  *			If supported_cable is NULL, cable name related APIs
572*f68a8342SChanwoo Choi  *			are disabled.
573*f68a8342SChanwoo Choi  *
574*f68a8342SChanwoo Choi  * This function allocates the memory for extcon device without allocating
575*f68a8342SChanwoo Choi  * memory in each extcon provider driver and initialize default setting for
576*f68a8342SChanwoo Choi  * extcon device.
577*f68a8342SChanwoo Choi  *
578*f68a8342SChanwoo Choi  * Return the pointer of extcon device if success or ERR_PTR(err) if fail
579*f68a8342SChanwoo Choi  */
580*f68a8342SChanwoo Choi struct extcon_dev *extcon_dev_allocate(const char **supported_cable)
581*f68a8342SChanwoo Choi {
582*f68a8342SChanwoo Choi 	struct extcon_dev *edev;
583*f68a8342SChanwoo Choi 
584*f68a8342SChanwoo Choi 	edev = kzalloc(sizeof(*edev), GFP_KERNEL);
585*f68a8342SChanwoo Choi 	if (!edev)
586*f68a8342SChanwoo Choi 		return ERR_PTR(-ENOMEM);
587*f68a8342SChanwoo Choi 
588*f68a8342SChanwoo Choi 	edev->max_supported = 0;
589*f68a8342SChanwoo Choi 	edev->supported_cable = supported_cable;
590*f68a8342SChanwoo Choi 
591*f68a8342SChanwoo Choi 	return edev;
592*f68a8342SChanwoo Choi }
593*f68a8342SChanwoo Choi 
594*f68a8342SChanwoo Choi /*
595*f68a8342SChanwoo Choi  * extcon_dev_free() - Free the memory of extcon device.
596*f68a8342SChanwoo Choi  * @edev:	the extcon device to free
597*f68a8342SChanwoo Choi  */
598*f68a8342SChanwoo Choi void extcon_dev_free(struct extcon_dev *edev)
599*f68a8342SChanwoo Choi {
600*f68a8342SChanwoo Choi 	kfree(edev);
601*f68a8342SChanwoo Choi }
602*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_dev_free);
603*f68a8342SChanwoo Choi 
604*f68a8342SChanwoo Choi static int devm_extcon_dev_match(struct device *dev, void *res, void *data)
605*f68a8342SChanwoo Choi {
606*f68a8342SChanwoo Choi 	struct extcon_dev **r = res;
607*f68a8342SChanwoo Choi 
608*f68a8342SChanwoo Choi 	if (WARN_ON(!r || !*r))
609*f68a8342SChanwoo Choi 		return 0;
610*f68a8342SChanwoo Choi 
611*f68a8342SChanwoo Choi 	return *r == data;
612*f68a8342SChanwoo Choi }
613*f68a8342SChanwoo Choi 
614*f68a8342SChanwoo Choi static void devm_extcon_dev_release(struct device *dev, void *res)
615*f68a8342SChanwoo Choi {
616*f68a8342SChanwoo Choi 	extcon_dev_free(*(struct extcon_dev **)res);
617*f68a8342SChanwoo Choi }
618*f68a8342SChanwoo Choi 
619*f68a8342SChanwoo Choi /**
620*f68a8342SChanwoo Choi  * devm_extcon_dev_allocate - Allocate managed extcon device
621*f68a8342SChanwoo Choi  * @dev:		device owning the extcon device being created
622*f68a8342SChanwoo Choi  * @supported_cable:	Array of supported cable names ending with NULL.
623*f68a8342SChanwoo Choi  *			If supported_cable is NULL, cable name related APIs
624*f68a8342SChanwoo Choi  *			are disabled.
625*f68a8342SChanwoo Choi  *
626*f68a8342SChanwoo Choi  * This function manages automatically the memory of extcon device using device
627*f68a8342SChanwoo Choi  * resource management and simplify the control of freeing the memory of extcon
628*f68a8342SChanwoo Choi  * device.
629*f68a8342SChanwoo Choi  *
630*f68a8342SChanwoo Choi  * Returns the pointer memory of allocated extcon_dev if success
631*f68a8342SChanwoo Choi  * or ERR_PTR(err) if fail
632*f68a8342SChanwoo Choi  */
633*f68a8342SChanwoo Choi struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
634*f68a8342SChanwoo Choi 					    const char **supported_cable)
635*f68a8342SChanwoo Choi {
636*f68a8342SChanwoo Choi 	struct extcon_dev **ptr, *edev;
637*f68a8342SChanwoo Choi 
638*f68a8342SChanwoo Choi 	ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL);
639*f68a8342SChanwoo Choi 	if (!ptr)
640*f68a8342SChanwoo Choi 		return ERR_PTR(-ENOMEM);
641*f68a8342SChanwoo Choi 
642*f68a8342SChanwoo Choi 	edev = extcon_dev_allocate(supported_cable);
643*f68a8342SChanwoo Choi 	if (IS_ERR(edev)) {
644*f68a8342SChanwoo Choi 		devres_free(ptr);
645*f68a8342SChanwoo Choi 		return edev;
646*f68a8342SChanwoo Choi 	}
647*f68a8342SChanwoo Choi 
648*f68a8342SChanwoo Choi 	edev->dev.parent = dev;
649*f68a8342SChanwoo Choi 
650*f68a8342SChanwoo Choi 	*ptr = edev;
651*f68a8342SChanwoo Choi 	devres_add(dev, ptr);
652*f68a8342SChanwoo Choi 
653*f68a8342SChanwoo Choi 	return edev;
654*f68a8342SChanwoo Choi }
655*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate);
656*f68a8342SChanwoo Choi 
657*f68a8342SChanwoo Choi void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev)
658*f68a8342SChanwoo Choi {
659*f68a8342SChanwoo Choi 	WARN_ON(devres_release(dev, devm_extcon_dev_release,
660*f68a8342SChanwoo Choi 			       devm_extcon_dev_match, edev));
661*f68a8342SChanwoo Choi }
662*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
663*f68a8342SChanwoo Choi 
664*f68a8342SChanwoo Choi /**
665*f68a8342SChanwoo Choi  * extcon_dev_register() - Register a new extcon device
666*f68a8342SChanwoo Choi  * @edev	: the new extcon device (should be allocated before calling)
667*f68a8342SChanwoo Choi  *
668*f68a8342SChanwoo Choi  * Among the members of edev struct, please set the "user initializing data"
669*f68a8342SChanwoo Choi  * in any case and set the "optional callbacks" if required. However, please
670*f68a8342SChanwoo Choi  * do not set the values of "internal data", which are initialized by
671*f68a8342SChanwoo Choi  * this function.
672*f68a8342SChanwoo Choi  */
673*f68a8342SChanwoo Choi int extcon_dev_register(struct extcon_dev *edev)
674*f68a8342SChanwoo Choi {
675*f68a8342SChanwoo Choi 	int ret, index = 0;
676*f68a8342SChanwoo Choi 
677*f68a8342SChanwoo Choi 	if (!extcon_class) {
678*f68a8342SChanwoo Choi 		ret = create_extcon_class();
679*f68a8342SChanwoo Choi 		if (ret < 0)
680*f68a8342SChanwoo Choi 			return ret;
681*f68a8342SChanwoo Choi 	}
682*f68a8342SChanwoo Choi 
683*f68a8342SChanwoo Choi 	if (edev->supported_cable) {
684*f68a8342SChanwoo Choi 		/* Get size of array */
685*f68a8342SChanwoo Choi 		for (index = 0; edev->supported_cable[index]; index++)
686*f68a8342SChanwoo Choi 			;
687*f68a8342SChanwoo Choi 		edev->max_supported = index;
688*f68a8342SChanwoo Choi 	} else {
689*f68a8342SChanwoo Choi 		edev->max_supported = 0;
690*f68a8342SChanwoo Choi 	}
691*f68a8342SChanwoo Choi 
692*f68a8342SChanwoo Choi 	if (index > SUPPORTED_CABLE_MAX) {
693*f68a8342SChanwoo Choi 		dev_err(&edev->dev, "extcon: maximum number of supported cables exceeded.\n");
694*f68a8342SChanwoo Choi 		return -EINVAL;
695*f68a8342SChanwoo Choi 	}
696*f68a8342SChanwoo Choi 
697*f68a8342SChanwoo Choi 	edev->dev.class = extcon_class;
698*f68a8342SChanwoo Choi 	edev->dev.release = extcon_dev_release;
699*f68a8342SChanwoo Choi 
700*f68a8342SChanwoo Choi 	edev->name = edev->name ? edev->name : dev_name(edev->dev.parent);
701*f68a8342SChanwoo Choi 	if (IS_ERR_OR_NULL(edev->name)) {
702*f68a8342SChanwoo Choi 		dev_err(&edev->dev,
703*f68a8342SChanwoo Choi 			"extcon device name is null\n");
704*f68a8342SChanwoo Choi 		return -EINVAL;
705*f68a8342SChanwoo Choi 	}
706*f68a8342SChanwoo Choi 	dev_set_name(&edev->dev, "%s", edev->name);
707*f68a8342SChanwoo Choi 
708*f68a8342SChanwoo Choi 	if (edev->max_supported) {
709*f68a8342SChanwoo Choi 		char buf[10];
710*f68a8342SChanwoo Choi 		char *str;
711*f68a8342SChanwoo Choi 		struct extcon_cable *cable;
712*f68a8342SChanwoo Choi 
713*f68a8342SChanwoo Choi 		edev->cables = kzalloc(sizeof(struct extcon_cable) *
714*f68a8342SChanwoo Choi 				       edev->max_supported, GFP_KERNEL);
715*f68a8342SChanwoo Choi 		if (!edev->cables) {
716*f68a8342SChanwoo Choi 			ret = -ENOMEM;
717*f68a8342SChanwoo Choi 			goto err_sysfs_alloc;
718*f68a8342SChanwoo Choi 		}
719*f68a8342SChanwoo Choi 		for (index = 0; index < edev->max_supported; index++) {
720*f68a8342SChanwoo Choi 			cable = &edev->cables[index];
721*f68a8342SChanwoo Choi 
722*f68a8342SChanwoo Choi 			snprintf(buf, 10, "cable.%d", index);
723*f68a8342SChanwoo Choi 			str = kzalloc(sizeof(char) * (strlen(buf) + 1),
724*f68a8342SChanwoo Choi 				      GFP_KERNEL);
725*f68a8342SChanwoo Choi 			if (!str) {
726*f68a8342SChanwoo Choi 				for (index--; index >= 0; index--) {
727*f68a8342SChanwoo Choi 					cable = &edev->cables[index];
728*f68a8342SChanwoo Choi 					kfree(cable->attr_g.name);
729*f68a8342SChanwoo Choi 				}
730*f68a8342SChanwoo Choi 				ret = -ENOMEM;
731*f68a8342SChanwoo Choi 
732*f68a8342SChanwoo Choi 				goto err_alloc_cables;
733*f68a8342SChanwoo Choi 			}
734*f68a8342SChanwoo Choi 			strcpy(str, buf);
735*f68a8342SChanwoo Choi 
736*f68a8342SChanwoo Choi 			cable->edev = edev;
737*f68a8342SChanwoo Choi 			cable->cable_index = index;
738*f68a8342SChanwoo Choi 			cable->attrs[0] = &cable->attr_name.attr;
739*f68a8342SChanwoo Choi 			cable->attrs[1] = &cable->attr_state.attr;
740*f68a8342SChanwoo Choi 			cable->attrs[2] = NULL;
741*f68a8342SChanwoo Choi 			cable->attr_g.name = str;
742*f68a8342SChanwoo Choi 			cable->attr_g.attrs = cable->attrs;
743*f68a8342SChanwoo Choi 
744*f68a8342SChanwoo Choi 			sysfs_attr_init(&cable->attr_name.attr);
745*f68a8342SChanwoo Choi 			cable->attr_name.attr.name = "name";
746*f68a8342SChanwoo Choi 			cable->attr_name.attr.mode = 0444;
747*f68a8342SChanwoo Choi 			cable->attr_name.show = cable_name_show;
748*f68a8342SChanwoo Choi 
749*f68a8342SChanwoo Choi 			sysfs_attr_init(&cable->attr_state.attr);
750*f68a8342SChanwoo Choi 			cable->attr_state.attr.name = "state";
751*f68a8342SChanwoo Choi 			cable->attr_state.attr.mode = 0444;
752*f68a8342SChanwoo Choi 			cable->attr_state.show = cable_state_show;
753*f68a8342SChanwoo Choi 		}
754*f68a8342SChanwoo Choi 	}
755*f68a8342SChanwoo Choi 
756*f68a8342SChanwoo Choi 	if (edev->max_supported && edev->mutually_exclusive) {
757*f68a8342SChanwoo Choi 		char buf[80];
758*f68a8342SChanwoo Choi 		char *name;
759*f68a8342SChanwoo Choi 
760*f68a8342SChanwoo Choi 		/* Count the size of mutually_exclusive array */
761*f68a8342SChanwoo Choi 		for (index = 0; edev->mutually_exclusive[index]; index++)
762*f68a8342SChanwoo Choi 			;
763*f68a8342SChanwoo Choi 
764*f68a8342SChanwoo Choi 		edev->attrs_muex = kzalloc(sizeof(struct attribute *) *
765*f68a8342SChanwoo Choi 					   (index + 1), GFP_KERNEL);
766*f68a8342SChanwoo Choi 		if (!edev->attrs_muex) {
767*f68a8342SChanwoo Choi 			ret = -ENOMEM;
768*f68a8342SChanwoo Choi 			goto err_muex;
769*f68a8342SChanwoo Choi 		}
770*f68a8342SChanwoo Choi 
771*f68a8342SChanwoo Choi 		edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) *
772*f68a8342SChanwoo Choi 					     index, GFP_KERNEL);
773*f68a8342SChanwoo Choi 		if (!edev->d_attrs_muex) {
774*f68a8342SChanwoo Choi 			ret = -ENOMEM;
775*f68a8342SChanwoo Choi 			kfree(edev->attrs_muex);
776*f68a8342SChanwoo Choi 			goto err_muex;
777*f68a8342SChanwoo Choi 		}
778*f68a8342SChanwoo Choi 
779*f68a8342SChanwoo Choi 		for (index = 0; edev->mutually_exclusive[index]; index++) {
780*f68a8342SChanwoo Choi 			sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
781*f68a8342SChanwoo Choi 			name = kzalloc(sizeof(char) * (strlen(buf) + 1),
782*f68a8342SChanwoo Choi 				       GFP_KERNEL);
783*f68a8342SChanwoo Choi 			if (!name) {
784*f68a8342SChanwoo Choi 				for (index--; index >= 0; index--) {
785*f68a8342SChanwoo Choi 					kfree(edev->d_attrs_muex[index].attr.
786*f68a8342SChanwoo Choi 					      name);
787*f68a8342SChanwoo Choi 				}
788*f68a8342SChanwoo Choi 				kfree(edev->d_attrs_muex);
789*f68a8342SChanwoo Choi 				kfree(edev->attrs_muex);
790*f68a8342SChanwoo Choi 				ret = -ENOMEM;
791*f68a8342SChanwoo Choi 				goto err_muex;
792*f68a8342SChanwoo Choi 			}
793*f68a8342SChanwoo Choi 			strcpy(name, buf);
794*f68a8342SChanwoo Choi 			sysfs_attr_init(&edev->d_attrs_muex[index].attr);
795*f68a8342SChanwoo Choi 			edev->d_attrs_muex[index].attr.name = name;
796*f68a8342SChanwoo Choi 			edev->d_attrs_muex[index].attr.mode = 0000;
797*f68a8342SChanwoo Choi 			edev->attrs_muex[index] = &edev->d_attrs_muex[index]
798*f68a8342SChanwoo Choi 							.attr;
799*f68a8342SChanwoo Choi 		}
800*f68a8342SChanwoo Choi 		edev->attr_g_muex.name = muex_name;
801*f68a8342SChanwoo Choi 		edev->attr_g_muex.attrs = edev->attrs_muex;
802*f68a8342SChanwoo Choi 
803*f68a8342SChanwoo Choi 	}
804*f68a8342SChanwoo Choi 
805*f68a8342SChanwoo Choi 	if (edev->max_supported) {
806*f68a8342SChanwoo Choi 		edev->extcon_dev_type.groups =
807*f68a8342SChanwoo Choi 			kzalloc(sizeof(struct attribute_group *) *
808*f68a8342SChanwoo Choi 				(edev->max_supported + 2), GFP_KERNEL);
809*f68a8342SChanwoo Choi 		if (!edev->extcon_dev_type.groups) {
810*f68a8342SChanwoo Choi 			ret = -ENOMEM;
811*f68a8342SChanwoo Choi 			goto err_alloc_groups;
812*f68a8342SChanwoo Choi 		}
813*f68a8342SChanwoo Choi 
814*f68a8342SChanwoo Choi 		edev->extcon_dev_type.name = dev_name(&edev->dev);
815*f68a8342SChanwoo Choi 		edev->extcon_dev_type.release = dummy_sysfs_dev_release;
816*f68a8342SChanwoo Choi 
817*f68a8342SChanwoo Choi 		for (index = 0; index < edev->max_supported; index++)
818*f68a8342SChanwoo Choi 			edev->extcon_dev_type.groups[index] =
819*f68a8342SChanwoo Choi 				&edev->cables[index].attr_g;
820*f68a8342SChanwoo Choi 		if (edev->mutually_exclusive)
821*f68a8342SChanwoo Choi 			edev->extcon_dev_type.groups[index] =
822*f68a8342SChanwoo Choi 				&edev->attr_g_muex;
823*f68a8342SChanwoo Choi 
824*f68a8342SChanwoo Choi 		edev->dev.type = &edev->extcon_dev_type;
825*f68a8342SChanwoo Choi 	}
826*f68a8342SChanwoo Choi 
827*f68a8342SChanwoo Choi 	ret = device_register(&edev->dev);
828*f68a8342SChanwoo Choi 	if (ret) {
829*f68a8342SChanwoo Choi 		put_device(&edev->dev);
830*f68a8342SChanwoo Choi 		goto err_dev;
831*f68a8342SChanwoo Choi 	}
832*f68a8342SChanwoo Choi #if defined(CONFIG_ANDROID)
833*f68a8342SChanwoo Choi 	if (switch_class)
834*f68a8342SChanwoo Choi 		ret = class_compat_create_link(switch_class, &edev->dev, NULL);
835*f68a8342SChanwoo Choi #endif /* CONFIG_ANDROID */
836*f68a8342SChanwoo Choi 
837*f68a8342SChanwoo Choi 	spin_lock_init(&edev->lock);
838*f68a8342SChanwoo Choi 
839*f68a8342SChanwoo Choi 	RAW_INIT_NOTIFIER_HEAD(&edev->nh);
840*f68a8342SChanwoo Choi 
841*f68a8342SChanwoo Choi 	dev_set_drvdata(&edev->dev, edev);
842*f68a8342SChanwoo Choi 	edev->state = 0;
843*f68a8342SChanwoo Choi 
844*f68a8342SChanwoo Choi 	mutex_lock(&extcon_dev_list_lock);
845*f68a8342SChanwoo Choi 	list_add(&edev->entry, &extcon_dev_list);
846*f68a8342SChanwoo Choi 	mutex_unlock(&extcon_dev_list_lock);
847*f68a8342SChanwoo Choi 
848*f68a8342SChanwoo Choi 	return 0;
849*f68a8342SChanwoo Choi 
850*f68a8342SChanwoo Choi err_dev:
851*f68a8342SChanwoo Choi 	if (edev->max_supported)
852*f68a8342SChanwoo Choi 		kfree(edev->extcon_dev_type.groups);
853*f68a8342SChanwoo Choi err_alloc_groups:
854*f68a8342SChanwoo Choi 	if (edev->max_supported && edev->mutually_exclusive) {
855*f68a8342SChanwoo Choi 		for (index = 0; edev->mutually_exclusive[index]; index++)
856*f68a8342SChanwoo Choi 			kfree(edev->d_attrs_muex[index].attr.name);
857*f68a8342SChanwoo Choi 		kfree(edev->d_attrs_muex);
858*f68a8342SChanwoo Choi 		kfree(edev->attrs_muex);
859*f68a8342SChanwoo Choi 	}
860*f68a8342SChanwoo Choi err_muex:
861*f68a8342SChanwoo Choi 	for (index = 0; index < edev->max_supported; index++)
862*f68a8342SChanwoo Choi 		kfree(edev->cables[index].attr_g.name);
863*f68a8342SChanwoo Choi err_alloc_cables:
864*f68a8342SChanwoo Choi 	if (edev->max_supported)
865*f68a8342SChanwoo Choi 		kfree(edev->cables);
866*f68a8342SChanwoo Choi err_sysfs_alloc:
867*f68a8342SChanwoo Choi 	return ret;
868*f68a8342SChanwoo Choi }
869*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_dev_register);
870*f68a8342SChanwoo Choi 
871*f68a8342SChanwoo Choi /**
872*f68a8342SChanwoo Choi  * extcon_dev_unregister() - Unregister the extcon device.
873*f68a8342SChanwoo Choi  * @edev:	the extcon device instance to be unregistered.
874*f68a8342SChanwoo Choi  *
875*f68a8342SChanwoo Choi  * Note that this does not call kfree(edev) because edev was not allocated
876*f68a8342SChanwoo Choi  * by this class.
877*f68a8342SChanwoo Choi  */
878*f68a8342SChanwoo Choi void extcon_dev_unregister(struct extcon_dev *edev)
879*f68a8342SChanwoo Choi {
880*f68a8342SChanwoo Choi 	int index;
881*f68a8342SChanwoo Choi 
882*f68a8342SChanwoo Choi 	mutex_lock(&extcon_dev_list_lock);
883*f68a8342SChanwoo Choi 	list_del(&edev->entry);
884*f68a8342SChanwoo Choi 	mutex_unlock(&extcon_dev_list_lock);
885*f68a8342SChanwoo Choi 
886*f68a8342SChanwoo Choi 	if (IS_ERR_OR_NULL(get_device(&edev->dev))) {
887*f68a8342SChanwoo Choi 		dev_err(&edev->dev, "Failed to unregister extcon_dev (%s)\n",
888*f68a8342SChanwoo Choi 				dev_name(&edev->dev));
889*f68a8342SChanwoo Choi 		return;
890*f68a8342SChanwoo Choi 	}
891*f68a8342SChanwoo Choi 
892*f68a8342SChanwoo Choi 	device_unregister(&edev->dev);
893*f68a8342SChanwoo Choi 
894*f68a8342SChanwoo Choi 	if (edev->mutually_exclusive && edev->max_supported) {
895*f68a8342SChanwoo Choi 		for (index = 0; edev->mutually_exclusive[index];
896*f68a8342SChanwoo Choi 				index++)
897*f68a8342SChanwoo Choi 			kfree(edev->d_attrs_muex[index].attr.name);
898*f68a8342SChanwoo Choi 		kfree(edev->d_attrs_muex);
899*f68a8342SChanwoo Choi 		kfree(edev->attrs_muex);
900*f68a8342SChanwoo Choi 	}
901*f68a8342SChanwoo Choi 
902*f68a8342SChanwoo Choi 	for (index = 0; index < edev->max_supported; index++)
903*f68a8342SChanwoo Choi 		kfree(edev->cables[index].attr_g.name);
904*f68a8342SChanwoo Choi 
905*f68a8342SChanwoo Choi 	if (edev->max_supported) {
906*f68a8342SChanwoo Choi 		kfree(edev->extcon_dev_type.groups);
907*f68a8342SChanwoo Choi 		kfree(edev->cables);
908*f68a8342SChanwoo Choi 	}
909*f68a8342SChanwoo Choi 
910*f68a8342SChanwoo Choi #if defined(CONFIG_ANDROID)
911*f68a8342SChanwoo Choi 	if (switch_class)
912*f68a8342SChanwoo Choi 		class_compat_remove_link(switch_class, &edev->dev, NULL);
913*f68a8342SChanwoo Choi #endif
914*f68a8342SChanwoo Choi 	put_device(&edev->dev);
915*f68a8342SChanwoo Choi }
916*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_dev_unregister);
917*f68a8342SChanwoo Choi 
918*f68a8342SChanwoo Choi static void devm_extcon_dev_unreg(struct device *dev, void *res)
919*f68a8342SChanwoo Choi {
920*f68a8342SChanwoo Choi 	extcon_dev_unregister(*(struct extcon_dev **)res);
921*f68a8342SChanwoo Choi }
922*f68a8342SChanwoo Choi 
923*f68a8342SChanwoo Choi /**
924*f68a8342SChanwoo Choi  * devm_extcon_dev_register() - Resource-managed extcon_dev_register()
925*f68a8342SChanwoo Choi  * @dev:	device to allocate extcon device
926*f68a8342SChanwoo Choi  * @edev:	the new extcon device to register
927*f68a8342SChanwoo Choi  *
928*f68a8342SChanwoo Choi  * Managed extcon_dev_register() function. If extcon device is attached with
929*f68a8342SChanwoo Choi  * this function, that extcon device is automatically unregistered on driver
930*f68a8342SChanwoo Choi  * detach. Internally this function calls extcon_dev_register() function.
931*f68a8342SChanwoo Choi  * To get more information, refer that function.
932*f68a8342SChanwoo Choi  *
933*f68a8342SChanwoo Choi  * If extcon device is registered with this function and the device needs to be
934*f68a8342SChanwoo Choi  * unregistered separately, devm_extcon_dev_unregister() should be used.
935*f68a8342SChanwoo Choi  *
936*f68a8342SChanwoo Choi  * Returns 0 if success or negaive error number if failure.
937*f68a8342SChanwoo Choi  */
938*f68a8342SChanwoo Choi int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev)
939*f68a8342SChanwoo Choi {
940*f68a8342SChanwoo Choi 	struct extcon_dev **ptr;
941*f68a8342SChanwoo Choi 	int ret;
942*f68a8342SChanwoo Choi 
943*f68a8342SChanwoo Choi 	ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL);
944*f68a8342SChanwoo Choi 	if (!ptr)
945*f68a8342SChanwoo Choi 		return -ENOMEM;
946*f68a8342SChanwoo Choi 
947*f68a8342SChanwoo Choi 	ret = extcon_dev_register(edev);
948*f68a8342SChanwoo Choi 	if (ret) {
949*f68a8342SChanwoo Choi 		devres_free(ptr);
950*f68a8342SChanwoo Choi 		return ret;
951*f68a8342SChanwoo Choi 	}
952*f68a8342SChanwoo Choi 
953*f68a8342SChanwoo Choi 	*ptr = edev;
954*f68a8342SChanwoo Choi 	devres_add(dev, ptr);
955*f68a8342SChanwoo Choi 
956*f68a8342SChanwoo Choi 	return 0;
957*f68a8342SChanwoo Choi }
958*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(devm_extcon_dev_register);
959*f68a8342SChanwoo Choi 
960*f68a8342SChanwoo Choi /**
961*f68a8342SChanwoo Choi  * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister()
962*f68a8342SChanwoo Choi  * @dev:	device the extcon belongs to
963*f68a8342SChanwoo Choi  * @edev:	the extcon device to unregister
964*f68a8342SChanwoo Choi  *
965*f68a8342SChanwoo Choi  * Unregister extcon device that is registered with devm_extcon_dev_register()
966*f68a8342SChanwoo Choi  * function.
967*f68a8342SChanwoo Choi  */
968*f68a8342SChanwoo Choi void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev)
969*f68a8342SChanwoo Choi {
970*f68a8342SChanwoo Choi 	WARN_ON(devres_release(dev, devm_extcon_dev_unreg,
971*f68a8342SChanwoo Choi 			       devm_extcon_dev_match, edev));
972*f68a8342SChanwoo Choi }
973*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister);
974*f68a8342SChanwoo Choi 
975*f68a8342SChanwoo Choi #ifdef CONFIG_OF
976*f68a8342SChanwoo Choi /*
977*f68a8342SChanwoo Choi  * extcon_get_edev_by_phandle - Get the extcon device from devicetree
978*f68a8342SChanwoo Choi  * @dev - instance to the given device
979*f68a8342SChanwoo Choi  * @index - index into list of extcon_dev
980*f68a8342SChanwoo Choi  *
981*f68a8342SChanwoo Choi  * return the instance of extcon device
982*f68a8342SChanwoo Choi  */
983*f68a8342SChanwoo Choi struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
984*f68a8342SChanwoo Choi {
985*f68a8342SChanwoo Choi 	struct device_node *node;
986*f68a8342SChanwoo Choi 	struct extcon_dev *edev;
987*f68a8342SChanwoo Choi 
988*f68a8342SChanwoo Choi 	if (!dev->of_node) {
989*f68a8342SChanwoo Choi 		dev_err(dev, "device does not have a device node entry\n");
990*f68a8342SChanwoo Choi 		return ERR_PTR(-EINVAL);
991*f68a8342SChanwoo Choi 	}
992*f68a8342SChanwoo Choi 
993*f68a8342SChanwoo Choi 	node = of_parse_phandle(dev->of_node, "extcon", index);
994*f68a8342SChanwoo Choi 	if (!node) {
995*f68a8342SChanwoo Choi 		dev_err(dev, "failed to get phandle in %s node\n",
996*f68a8342SChanwoo Choi 			dev->of_node->full_name);
997*f68a8342SChanwoo Choi 		return ERR_PTR(-ENODEV);
998*f68a8342SChanwoo Choi 	}
999*f68a8342SChanwoo Choi 
1000*f68a8342SChanwoo Choi 	mutex_lock(&extcon_dev_list_lock);
1001*f68a8342SChanwoo Choi 	list_for_each_entry(edev, &extcon_dev_list, entry) {
1002*f68a8342SChanwoo Choi 		if (edev->dev.parent && edev->dev.parent->of_node == node) {
1003*f68a8342SChanwoo Choi 			mutex_unlock(&extcon_dev_list_lock);
1004*f68a8342SChanwoo Choi 			return edev;
1005*f68a8342SChanwoo Choi 		}
1006*f68a8342SChanwoo Choi 	}
1007*f68a8342SChanwoo Choi 	mutex_unlock(&extcon_dev_list_lock);
1008*f68a8342SChanwoo Choi 
1009*f68a8342SChanwoo Choi 	return ERR_PTR(-EPROBE_DEFER);
1010*f68a8342SChanwoo Choi }
1011*f68a8342SChanwoo Choi #else
1012*f68a8342SChanwoo Choi struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
1013*f68a8342SChanwoo Choi {
1014*f68a8342SChanwoo Choi 	return ERR_PTR(-ENOSYS);
1015*f68a8342SChanwoo Choi }
1016*f68a8342SChanwoo Choi #endif /* CONFIG_OF */
1017*f68a8342SChanwoo Choi EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle);
1018*f68a8342SChanwoo Choi 
1019*f68a8342SChanwoo Choi static int __init extcon_class_init(void)
1020*f68a8342SChanwoo Choi {
1021*f68a8342SChanwoo Choi 	return create_extcon_class();
1022*f68a8342SChanwoo Choi }
1023*f68a8342SChanwoo Choi module_init(extcon_class_init);
1024*f68a8342SChanwoo Choi 
1025*f68a8342SChanwoo Choi static void __exit extcon_class_exit(void)
1026*f68a8342SChanwoo Choi {
1027*f68a8342SChanwoo Choi #if defined(CONFIG_ANDROID)
1028*f68a8342SChanwoo Choi 	class_compat_unregister(switch_class);
1029*f68a8342SChanwoo Choi #endif
1030*f68a8342SChanwoo Choi 	class_destroy(extcon_class);
1031*f68a8342SChanwoo Choi }
1032*f68a8342SChanwoo Choi module_exit(extcon_class_exit);
1033*f68a8342SChanwoo Choi 
1034*f68a8342SChanwoo Choi MODULE_AUTHOR("Mike Lockwood <[email protected]>");
1035*f68a8342SChanwoo Choi MODULE_AUTHOR("Donggeun Kim <[email protected]>");
1036*f68a8342SChanwoo Choi MODULE_AUTHOR("MyungJoo Ham <[email protected]>");
1037*f68a8342SChanwoo Choi MODULE_DESCRIPTION("External connector (extcon) class driver");
1038*f68a8342SChanwoo Choi MODULE_LICENSE("GPL");
1039