Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
[pandora-kernel.git] / drivers / extcon / extcon_class.c
1 /*
2  *  drivers/extcon/extcon_class.c
3  *
4  *  External connector (extcon) class driver
5  *
6  * Copyright (C) 2012 Samsung Electronics
7  * Author: Donggeun Kim <dg77.kim@samsung.com>
8  * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
9  *
10  * based on android/drivers/switch/switch_class.c
11  * Copyright (C) 2008 Google, Inc.
12  * Author: Mike Lockwood <lockwood@android.com>
13  *
14  * This software is licensed under the terms of the GNU General Public
15  * License version 2, as published by the Free Software Foundation, and
16  * may be copied, distributed, and modified under those terms.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23 */
24
25 #include <linux/module.h>
26 #include <linux/types.h>
27 #include <linux/init.h>
28 #include <linux/device.h>
29 #include <linux/fs.h>
30 #include <linux/err.h>
31 #include <linux/extcon.h>
32 #include <linux/slab.h>
33
34 /*
35  * extcon_cable_name suggests the standard cable names for commonly used
36  * cable types.
37  *
38  * However, please do not use extcon_cable_name directly for extcon_dev
39  * struct's supported_cable pointer unless your device really supports
40  * every single port-type of the following cable names. Please choose cable
41  * names that are actually used in your extcon device.
42  */
43 const char *extcon_cable_name[] = {
44         [EXTCON_USB]            = "USB",
45         [EXTCON_USB_HOST]       = "USB-Host",
46         [EXTCON_TA]             = "TA",
47         [EXTCON_FAST_CHARGER]   = "Fast-charger",
48         [EXTCON_SLOW_CHARGER]   = "Slow-charger",
49         [EXTCON_CHARGE_DOWNSTREAM]      = "Charge-downstream",
50         [EXTCON_HDMI]           = "HDMI",
51         [EXTCON_MHL]            = "MHL",
52         [EXTCON_DVI]            = "DVI",
53         [EXTCON_VGA]            = "VGA",
54         [EXTCON_DOCK]           = "Dock",
55         [EXTCON_LINE_IN]        = "Line-in",
56         [EXTCON_LINE_OUT]       = "Line-out",
57         [EXTCON_MIC_IN]         = "Microphone",
58         [EXTCON_HEADPHONE_OUT]  = "Headphone",
59         [EXTCON_SPDIF_IN]       = "SPDIF-in",
60         [EXTCON_SPDIF_OUT]      = "SPDIF-out",
61         [EXTCON_VIDEO_IN]       = "Video-in",
62         [EXTCON_VIDEO_OUT]      = "Video-out",
63         [EXTCON_MECHANICAL]     = "Mechanical",
64
65         NULL,
66 };
67
68 static struct class *extcon_class;
69 #if defined(CONFIG_ANDROID)
70 static struct class_compat *switch_class;
71 #endif /* CONFIG_ANDROID */
72
73 static LIST_HEAD(extcon_dev_list);
74 static DEFINE_MUTEX(extcon_dev_list_lock);
75
76 /**
77  * check_mutually_exclusive - Check if new_state violates mutually_exclusive
78  *                          condition.
79  * @edev:       the extcon device
80  * @new_state:  new cable attach status for @edev
81  *
82  * Returns 0 if nothing violates. Returns the index + 1 for the first
83  * violated condition.
84  */
85 static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
86 {
87         int i = 0;
88
89         if (!edev->mutually_exclusive)
90                 return 0;
91
92         for (i = 0; edev->mutually_exclusive[i]; i++) {
93                 int count = 0, j;
94                 u32 correspondants = new_state & edev->mutually_exclusive[i];
95                 u32 exp = 1;
96
97                 for (j = 0; j < 32; j++) {
98                         if (exp & correspondants)
99                                 count++;
100                         if (count > 1)
101                                 return i + 1;
102                         exp <<= 1;
103                 }
104         }
105
106         return 0;
107 }
108
109 static ssize_t state_show(struct device *dev, struct device_attribute *attr,
110                           char *buf)
111 {
112         int i, count = 0;
113         struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
114
115         if (edev->print_state) {
116                 int ret = edev->print_state(edev, buf);
117
118                 if (ret >= 0)
119                         return ret;
120                 /* Use default if failed */
121         }
122
123         if (edev->max_supported == 0)
124                 return sprintf(buf, "%u\n", edev->state);
125
126         for (i = 0; i < SUPPORTED_CABLE_MAX; i++) {
127                 if (!edev->supported_cable[i])
128                         break;
129                 count += sprintf(buf + count, "%s=%d\n",
130                                  edev->supported_cable[i],
131                                  !!(edev->state & (1 << i)));
132         }
133
134         return count;
135 }
136
137 int extcon_set_state(struct extcon_dev *edev, u32 state);
138 static ssize_t state_store(struct device *dev, struct device_attribute *attr,
139                            const char *buf, size_t count)
140 {
141         u32 state;
142         ssize_t ret = 0;
143         struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
144
145         ret = sscanf(buf, "0x%x", &state);
146         if (ret == 0)
147                 ret = -EINVAL;
148         else
149                 ret = extcon_set_state(edev, state);
150
151         if (ret < 0)
152                 return ret;
153
154         return count;
155 }
156
157 static ssize_t name_show(struct device *dev, struct device_attribute *attr,
158                 char *buf)
159 {
160         struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
161
162         /* Optional callback given by the user */
163         if (edev->print_name) {
164                 int ret = edev->print_name(edev, buf);
165                 if (ret >= 0)
166                         return ret;
167         }
168
169         return sprintf(buf, "%s\n", dev_name(edev->dev));
170 }
171
172 static ssize_t cable_name_show(struct device *dev,
173                                struct device_attribute *attr, char *buf)
174 {
175         struct extcon_cable *cable = container_of(attr, struct extcon_cable,
176                                                   attr_name);
177
178         return sprintf(buf, "%s\n",
179                        cable->edev->supported_cable[cable->cable_index]);
180 }
181
182 static ssize_t cable_state_show(struct device *dev,
183                                 struct device_attribute *attr, char *buf)
184 {
185         struct extcon_cable *cable = container_of(attr, struct extcon_cable,
186                                                   attr_state);
187
188         return sprintf(buf, "%d\n",
189                        extcon_get_cable_state_(cable->edev,
190                                                cable->cable_index));
191 }
192
193 static ssize_t cable_state_store(struct device *dev,
194                                  struct device_attribute *attr, const char *buf,
195                                  size_t count)
196 {
197         struct extcon_cable *cable = container_of(attr, struct extcon_cable,
198                                                   attr_state);
199         int ret, state;
200
201         ret = sscanf(buf, "%d", &state);
202         if (ret == 0)
203                 ret = -EINVAL;
204         else
205                 ret = extcon_set_cable_state_(cable->edev, cable->cable_index,
206                                               state);
207
208         if (ret < 0)
209                 return ret;
210         return count;
211 }
212
213 /**
214  * extcon_update_state() - Update the cable attach states of the extcon device
215  *                      only for the masked bits.
216  * @edev:       the extcon device
217  * @mask:       the bit mask to designate updated bits.
218  * @state:      new cable attach status for @edev
219  *
220  * Changing the state sends uevent with environment variable containing
221  * the name of extcon device (envp[0]) and the state output (envp[1]).
222  * Tizen uses this format for extcon device to get events from ports.
223  * Android uses this format as well.
224  *
225  * Note that the notifier provides which bits are changed in the state
226  * variable with the val parameter (second) to the callback.
227  */
228 int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
229 {
230         char name_buf[120];
231         char state_buf[120];
232         char *prop_buf;
233         char *envp[3];
234         int env_offset = 0;
235         int length;
236         unsigned long flags;
237
238         spin_lock_irqsave(&edev->lock, flags);
239
240         if (edev->state != ((edev->state & ~mask) | (state & mask))) {
241                 u32 old_state = edev->state;
242
243                 if (check_mutually_exclusive(edev, (edev->state & ~mask) |
244                                                    (state & mask))) {
245                         spin_unlock_irqrestore(&edev->lock, flags);
246                         return -EPERM;
247                 }
248
249                 edev->state &= ~mask;
250                 edev->state |= state & mask;
251
252                 raw_notifier_call_chain(&edev->nh, old_state, edev);
253
254                 /* This could be in interrupt handler */
255                 prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
256                 if (prop_buf) {
257                         length = name_show(edev->dev, NULL, prop_buf);
258                         if (length > 0) {
259                                 if (prop_buf[length - 1] == '\n')
260                                         prop_buf[length - 1] = 0;
261                                 snprintf(name_buf, sizeof(name_buf),
262                                         "NAME=%s", prop_buf);
263                                 envp[env_offset++] = name_buf;
264                         }
265                         length = state_show(edev->dev, NULL, prop_buf);
266                         if (length > 0) {
267                                 if (prop_buf[length - 1] == '\n')
268                                         prop_buf[length - 1] = 0;
269                                 snprintf(state_buf, sizeof(state_buf),
270                                         "STATE=%s", prop_buf);
271                                 envp[env_offset++] = state_buf;
272                         }
273                         envp[env_offset] = NULL;
274                         /* Unlock early before uevent */
275                         spin_unlock_irqrestore(&edev->lock, flags);
276
277                         kobject_uevent_env(&edev->dev->kobj, KOBJ_CHANGE, envp);
278                         free_page((unsigned long)prop_buf);
279                 } else {
280                         /* Unlock early before uevent */
281                         spin_unlock_irqrestore(&edev->lock, flags);
282
283                         dev_err(edev->dev, "out of memory in extcon_set_state\n");
284                         kobject_uevent(&edev->dev->kobj, KOBJ_CHANGE);
285                 }
286         } else {
287                 /* No changes */
288                 spin_unlock_irqrestore(&edev->lock, flags);
289         }
290
291         return 0;
292 }
293 EXPORT_SYMBOL_GPL(extcon_update_state);
294
295 /**
296  * extcon_set_state() - Set the cable attach states of the extcon device.
297  * @edev:       the extcon device
298  * @state:      new cable attach status for @edev
299  *
300  * Note that notifier provides which bits are changed in the state
301  * variable with the val parameter (second) to the callback.
302  */
303 int extcon_set_state(struct extcon_dev *edev, u32 state)
304 {
305         return extcon_update_state(edev, 0xffffffff, state);
306 }
307 EXPORT_SYMBOL_GPL(extcon_set_state);
308
309 /**
310  * extcon_find_cable_index() - Get the cable index based on the cable name.
311  * @edev:       the extcon device that has the cable.
312  * @cable_name: cable name to be searched.
313  *
314  * Note that accessing a cable state based on cable_index is faster than
315  * cable_name because using cable_name induces a loop with strncmp().
316  * Thus, when get/set_cable_state is repeatedly used, using cable_index
317  * is recommended.
318  */
319 int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name)
320 {
321         int i;
322
323         if (edev->supported_cable) {
324                 for (i = 0; edev->supported_cable[i]; i++) {
325                         if (!strncmp(edev->supported_cable[i],
326                                 cable_name, CABLE_NAME_MAX))
327                                 return i;
328                 }
329         }
330
331         return -EINVAL;
332 }
333 EXPORT_SYMBOL_GPL(extcon_find_cable_index);
334
335 /**
336  * extcon_get_cable_state_() - Get the status of a specific cable.
337  * @edev:       the extcon device that has the cable.
338  * @index:      cable index that can be retrieved by extcon_find_cable_index().
339  */
340 int extcon_get_cable_state_(struct extcon_dev *edev, int index)
341 {
342         if (index < 0 || (edev->max_supported && edev->max_supported <= index))
343                 return -EINVAL;
344
345         return !!(edev->state & (1 << index));
346 }
347 EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
348
349 /**
350  * extcon_get_cable_state() - Get the status of a specific cable.
351  * @edev:       the extcon device that has the cable.
352  * @cable_name: cable name.
353  *
354  * Note that this is slower than extcon_get_cable_state_.
355  */
356 int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
357 {
358         return extcon_get_cable_state_(edev, extcon_find_cable_index
359                                                 (edev, cable_name));
360 }
361 EXPORT_SYMBOL_GPL(extcon_get_cable_state);
362
363 /**
364  * extcon_get_cable_state_() - Set the status of a specific cable.
365  * @edev:       the extcon device that has the cable.
366  * @index:      cable index that can be retrieved by extcon_find_cable_index().
367  * @cable_state:        the new cable status. The default semantics is
368  *                      true: attached / false: detached.
369  */
370 int extcon_set_cable_state_(struct extcon_dev *edev,
371                         int index, bool cable_state)
372 {
373         u32 state;
374
375         if (index < 0 || (edev->max_supported && edev->max_supported <= index))
376                 return -EINVAL;
377
378         state = cable_state ? (1 << index) : 0;
379         return extcon_update_state(edev, 1 << index, state);
380 }
381 EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
382
383 /**
384  * extcon_get_cable_state() - Set the status of a specific cable.
385  * @edev:       the extcon device that has the cable.
386  * @cable_name: cable name.
387  * @cable_state:        the new cable status. The default semantics is
388  *                      true: attached / false: detached.
389  *
390  * Note that this is slower than extcon_set_cable_state_.
391  */
392 int extcon_set_cable_state(struct extcon_dev *edev,
393                         const char *cable_name, bool cable_state)
394 {
395         return extcon_set_cable_state_(edev, extcon_find_cable_index
396                                         (edev, cable_name), cable_state);
397 }
398 EXPORT_SYMBOL_GPL(extcon_set_cable_state);
399
400 /**
401  * extcon_get_extcon_dev() - Get the extcon device instance from the name
402  * @extcon_name:        The extcon name provided with extcon_dev_register()
403  */
404 struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
405 {
406         struct extcon_dev *sd;
407
408         mutex_lock(&extcon_dev_list_lock);
409         list_for_each_entry(sd, &extcon_dev_list, entry) {
410                 if (!strcmp(sd->name, extcon_name))
411                         goto out;
412         }
413         sd = NULL;
414 out:
415         mutex_unlock(&extcon_dev_list_lock);
416         return sd;
417 }
418 EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
419
420 static int _call_per_cable(struct notifier_block *nb, unsigned long val,
421                            void *ptr)
422 {
423         struct extcon_specific_cable_nb *obj = container_of(nb,
424                         struct extcon_specific_cable_nb, internal_nb);
425         struct extcon_dev *edev = ptr;
426
427         if ((val & (1 << obj->cable_index)) !=
428             (edev->state & (1 << obj->cable_index))) {
429                 bool cable_state = true;
430
431                 obj->previous_value = val;
432
433                 if (val & (1 << obj->cable_index))
434                         cable_state = false;
435
436                 return obj->user_nb->notifier_call(obj->user_nb,
437                                 cable_state, ptr);
438         }
439
440         return NOTIFY_OK;
441 }
442
443 /**
444  * extcon_register_interest() - Register a notifier for a state change of a
445  *                            specific cable, not a entier set of cables of a
446  *                            extcon device.
447  * @obj:        an empty extcon_specific_cable_nb object to be returned.
448  * @extcon_name:        the name of extcon device.
449  * @cable_name:         the target cable name.
450  * @nb:         the notifier block to get notified.
451  *
452  * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets
453  * the struct for you.
454  *
455  * extcon_register_interest is a helper function for those who want to get
456  * notification for a single specific cable's status change. If a user wants
457  * to get notification for any changes of all cables of a extcon device,
458  * he/she should use the general extcon_register_notifier().
459  *
460  * Note that the second parameter given to the callback of nb (val) is
461  * "old_state", not the current state. The current state can be retrieved
462  * by looking at the third pameter (edev pointer)'s state value.
463  */
464 int extcon_register_interest(struct extcon_specific_cable_nb *obj,
465                              const char *extcon_name, const char *cable_name,
466                              struct notifier_block *nb)
467 {
468         if (!obj || !extcon_name || !cable_name || !nb)
469                 return -EINVAL;
470
471         obj->edev = extcon_get_extcon_dev(extcon_name);
472         if (!obj->edev)
473                 return -ENODEV;
474
475         obj->cable_index = extcon_find_cable_index(obj->edev, cable_name);
476         if (obj->cable_index < 0)
477                 return -ENODEV;
478
479         obj->user_nb = nb;
480
481         obj->internal_nb.notifier_call = _call_per_cable;
482
483         return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb);
484 }
485
486 /**
487  * extcon_unregister_interest() - Unregister the notifier registered by
488  *                              extcon_register_interest().
489  * @obj:        the extcon_specific_cable_nb object returned by
490  *              extcon_register_interest().
491  */
492 int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
493 {
494         if (!obj)
495                 return -EINVAL;
496
497         return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
498 }
499
500 /**
501  * extcon_register_notifier() - Register a notifee to get notified by
502  *                            any attach status changes from the extcon.
503  * @edev:       the extcon device.
504  * @nb:         a notifier block to be registered.
505  *
506  * Note that the second parameter given to the callback of nb (val) is
507  * "old_state", not the current state. The current state can be retrieved
508  * by looking at the third pameter (edev pointer)'s state value.
509  */
510 int extcon_register_notifier(struct extcon_dev *edev,
511                         struct notifier_block *nb)
512 {
513         return raw_notifier_chain_register(&edev->nh, nb);
514 }
515 EXPORT_SYMBOL_GPL(extcon_register_notifier);
516
517 /**
518  * extcon_unregister_notifier() - Unregister a notifee from the extcon device.
519  * @edev:       the extcon device.
520  * @nb:         a registered notifier block to be unregistered.
521  */
522 int extcon_unregister_notifier(struct extcon_dev *edev,
523                         struct notifier_block *nb)
524 {
525         return raw_notifier_chain_unregister(&edev->nh, nb);
526 }
527 EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
528
529 static struct device_attribute extcon_attrs[] = {
530         __ATTR(state, S_IRUGO | S_IWUSR, state_show, state_store),
531         __ATTR_RO(name),
532         __ATTR_NULL,
533 };
534
535 static int create_extcon_class(void)
536 {
537         if (!extcon_class) {
538                 extcon_class = class_create(THIS_MODULE, "extcon");
539                 if (IS_ERR(extcon_class))
540                         return PTR_ERR(extcon_class);
541                 extcon_class->dev_attrs = extcon_attrs;
542
543 #if defined(CONFIG_ANDROID)
544                 switch_class = class_compat_register("switch");
545                 if (WARN(!switch_class, "cannot allocate"))
546                         return -ENOMEM;
547 #endif /* CONFIG_ANDROID */
548         }
549
550         return 0;
551 }
552
553 static void extcon_cleanup(struct extcon_dev *edev, bool skip)
554 {
555         mutex_lock(&extcon_dev_list_lock);
556         list_del(&edev->entry);
557         mutex_unlock(&extcon_dev_list_lock);
558
559         if (!skip && get_device(edev->dev)) {
560                 int index;
561
562                 if (edev->mutually_exclusive && edev->max_supported) {
563                         for (index = 0; edev->mutually_exclusive[index];
564                              index++)
565                                 kfree(edev->d_attrs_muex[index].attr.name);
566                         kfree(edev->d_attrs_muex);
567                         kfree(edev->attrs_muex);
568                 }
569
570                 for (index = 0; index < edev->max_supported; index++)
571                         kfree(edev->cables[index].attr_g.name);
572
573                 if (edev->max_supported) {
574                         kfree(edev->extcon_dev_type.groups);
575                         kfree(edev->cables);
576                 }
577
578                 device_unregister(edev->dev);
579                 put_device(edev->dev);
580         }
581
582         kfree(edev->dev);
583 }
584
585 static void extcon_dev_release(struct device *dev)
586 {
587         struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
588
589         extcon_cleanup(edev, true);
590 }
591
592 static const char *muex_name = "mutually_exclusive";
593 static void dummy_sysfs_dev_release(struct device *dev)
594 {
595 }
596
597 /**
598  * extcon_dev_register() - Register a new extcon device
599  * @edev        : the new extcon device (should be allocated before calling)
600  * @dev         : the parent device for this extcon device.
601  *
602  * Among the members of edev struct, please set the "user initializing data"
603  * in any case and set the "optional callbacks" if required. However, please
604  * do not set the values of "internal data", which are initialized by
605  * this function.
606  */
607 int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
608 {
609         int ret, index = 0;
610
611         if (!extcon_class) {
612                 ret = create_extcon_class();
613                 if (ret < 0)
614                         return ret;
615         }
616
617         if (edev->supported_cable) {
618                 /* Get size of array */
619                 for (index = 0; edev->supported_cable[index]; index++)
620                         ;
621                 edev->max_supported = index;
622         } else {
623                 edev->max_supported = 0;
624         }
625
626         if (index > SUPPORTED_CABLE_MAX) {
627                 dev_err(edev->dev, "extcon: maximum number of supported cables exceeded.\n");
628                 return -EINVAL;
629         }
630
631         edev->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
632         if (!edev->dev)
633                 return -ENOMEM;
634         edev->dev->parent = dev;
635         edev->dev->class = extcon_class;
636         edev->dev->release = extcon_dev_release;
637
638         dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev));
639
640         if (edev->max_supported) {
641                 char buf[10];
642                 char *str;
643                 struct extcon_cable *cable;
644
645                 edev->cables = kzalloc(sizeof(struct extcon_cable) *
646                                        edev->max_supported, GFP_KERNEL);
647                 if (!edev->cables) {
648                         ret = -ENOMEM;
649                         goto err_sysfs_alloc;
650                 }
651                 for (index = 0; index < edev->max_supported; index++) {
652                         cable = &edev->cables[index];
653
654                         snprintf(buf, 10, "cable.%d", index);
655                         str = kzalloc(sizeof(char) * (strlen(buf) + 1),
656                                       GFP_KERNEL);
657                         if (!str) {
658                                 for (index--; index >= 0; index--) {
659                                         cable = &edev->cables[index];
660                                         kfree(cable->attr_g.name);
661                                 }
662                                 ret = -ENOMEM;
663
664                                 goto err_alloc_cables;
665                         }
666                         strcpy(str, buf);
667
668                         cable->edev = edev;
669                         cable->cable_index = index;
670                         cable->attrs[0] = &cable->attr_name.attr;
671                         cable->attrs[1] = &cable->attr_state.attr;
672                         cable->attrs[2] = NULL;
673                         cable->attr_g.name = str;
674                         cable->attr_g.attrs = cable->attrs;
675
676                         cable->attr_name.attr.name = "name";
677                         cable->attr_name.attr.mode = 0444;
678                         cable->attr_name.show = cable_name_show;
679
680                         cable->attr_state.attr.name = "state";
681                         cable->attr_state.attr.mode = 0644;
682                         cable->attr_state.show = cable_state_show;
683                         cable->attr_state.store = cable_state_store;
684                 }
685         }
686
687         if (edev->max_supported && edev->mutually_exclusive) {
688                 char buf[80];
689                 char *name;
690
691                 /* Count the size of mutually_exclusive array */
692                 for (index = 0; edev->mutually_exclusive[index]; index++)
693                         ;
694
695                 edev->attrs_muex = kzalloc(sizeof(struct attribute *) *
696                                            (index + 1), GFP_KERNEL);
697                 if (!edev->attrs_muex) {
698                         ret = -ENOMEM;
699                         goto err_muex;
700                 }
701
702                 edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) *
703                                              index, GFP_KERNEL);
704                 if (!edev->d_attrs_muex) {
705                         ret = -ENOMEM;
706                         kfree(edev->attrs_muex);
707                         goto err_muex;
708                 }
709
710                 for (index = 0; edev->mutually_exclusive[index]; index++) {
711                         sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
712                         name = kzalloc(sizeof(char) * (strlen(buf) + 1),
713                                        GFP_KERNEL);
714                         if (!name) {
715                                 for (index--; index >= 0; index--) {
716                                         kfree(edev->d_attrs_muex[index].attr.
717                                               name);
718                                 }
719                                 kfree(edev->d_attrs_muex);
720                                 kfree(edev->attrs_muex);
721                                 ret = -ENOMEM;
722                                 goto err_muex;
723                         }
724                         strcpy(name, buf);
725                         edev->d_attrs_muex[index].attr.name = name;
726                         edev->d_attrs_muex[index].attr.mode = 0000;
727                         edev->attrs_muex[index] = &edev->d_attrs_muex[index]
728                                                         .attr;
729                 }
730                 edev->attr_g_muex.name = muex_name;
731                 edev->attr_g_muex.attrs = edev->attrs_muex;
732
733         }
734
735         if (edev->max_supported) {
736                 edev->extcon_dev_type.groups =
737                         kzalloc(sizeof(struct attribute_group *) *
738                                 (edev->max_supported + 2), GFP_KERNEL);
739                 if (!edev->extcon_dev_type.groups) {
740                         ret = -ENOMEM;
741                         goto err_alloc_groups;
742                 }
743
744                 edev->extcon_dev_type.name = dev_name(edev->dev);
745                 edev->extcon_dev_type.release = dummy_sysfs_dev_release;
746
747                 for (index = 0; index < edev->max_supported; index++)
748                         edev->extcon_dev_type.groups[index] =
749                                 &edev->cables[index].attr_g;
750                 if (edev->mutually_exclusive)
751                         edev->extcon_dev_type.groups[index] =
752                                 &edev->attr_g_muex;
753
754                 edev->dev->type = &edev->extcon_dev_type;
755         }
756
757         ret = device_register(edev->dev);
758         if (ret) {
759                 put_device(edev->dev);
760                 goto err_dev;
761         }
762 #if defined(CONFIG_ANDROID)
763         if (switch_class)
764                 ret = class_compat_create_link(switch_class, edev->dev,
765                                                NULL);
766 #endif /* CONFIG_ANDROID */
767
768         spin_lock_init(&edev->lock);
769
770         RAW_INIT_NOTIFIER_HEAD(&edev->nh);
771
772         dev_set_drvdata(edev->dev, edev);
773         edev->state = 0;
774
775         mutex_lock(&extcon_dev_list_lock);
776         list_add(&edev->entry, &extcon_dev_list);
777         mutex_unlock(&extcon_dev_list_lock);
778
779         return 0;
780
781 err_dev:
782         if (edev->max_supported)
783                 kfree(edev->extcon_dev_type.groups);
784 err_alloc_groups:
785         if (edev->max_supported && edev->mutually_exclusive) {
786                 for (index = 0; edev->mutually_exclusive[index]; index++)
787                         kfree(edev->d_attrs_muex[index].attr.name);
788                 kfree(edev->d_attrs_muex);
789                 kfree(edev->attrs_muex);
790         }
791 err_muex:
792         for (index = 0; index < edev->max_supported; index++)
793                 kfree(edev->cables[index].attr_g.name);
794 err_alloc_cables:
795         if (edev->max_supported)
796                 kfree(edev->cables);
797 err_sysfs_alloc:
798         kfree(edev->dev);
799         return ret;
800 }
801 EXPORT_SYMBOL_GPL(extcon_dev_register);
802
803 /**
804  * extcon_dev_unregister() - Unregister the extcon device.
805  * @edev:       the extcon device instance to be unregitered.
806  *
807  * Note that this does not call kfree(edev) because edev was not allocated
808  * by this class.
809  */
810 void extcon_dev_unregister(struct extcon_dev *edev)
811 {
812         extcon_cleanup(edev, false);
813 }
814 EXPORT_SYMBOL_GPL(extcon_dev_unregister);
815
816 static int __init extcon_class_init(void)
817 {
818         return create_extcon_class();
819 }
820 module_init(extcon_class_init);
821
822 static void __exit extcon_class_exit(void)
823 {
824         class_destroy(extcon_class);
825 }
826 module_exit(extcon_class_exit);
827
828 MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
829 MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
830 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
831 MODULE_DESCRIPTION("External connector (extcon) class driver");
832 MODULE_LICENSE("GPL");