aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon/extcon.c
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2015-09-01 09:35:24 -0400
committerJiri Kosina <jkosina@suse.cz>2015-09-01 09:35:24 -0400
commit067e2601d3c076abbf45db91261f9065eaa879b2 (patch)
tree86c8d4b913873dbd3b4ff23562a3a8597984b4df /drivers/extcon/extcon.c
parent3e097d1271ecdff2f251a54ddfc5eaa1f9821e96 (diff)
parent931830aa5c251e0803523213428f777a48bde254 (diff)
Merge branch 'for-4.3/gembird' into for-linus
Diffstat (limited to 'drivers/extcon/extcon.c')
-rw-r--r--drivers/extcon/extcon.c347
1 files changed, 205 insertions, 142 deletions
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
index 4c9f165e4a04..43b57b02d050 100644
--- a/drivers/extcon/extcon.c
+++ b/drivers/extcon/extcon.c
@@ -1,8 +1,11 @@
1/* 1/*
2 * drivers/extcon/extcon_class.c 2 * drivers/extcon/extcon.c - External Connector (extcon) framework.
3 * 3 *
4 * External connector (extcon) class driver 4 * External connector (extcon) class driver
5 * 5 *
6 * Copyright (C) 2015 Samsung Electronics
7 * Author: Chanwoo Choi <cw00.choi@samsung.com>
8 *
6 * Copyright (C) 2012 Samsung Electronics 9 * Copyright (C) 2012 Samsung Electronics
7 * Author: Donggeun Kim <dg77.kim@samsung.com> 10 * Author: Donggeun Kim <dg77.kim@samsung.com>
8 * Author: MyungJoo Ham <myungjoo.ham@samsung.com> 11 * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
@@ -19,8 +22,7 @@
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details. 24 * GNU General Public License for more details.
22 * 25 */
23*/
24 26
25#include <linux/module.h> 27#include <linux/module.h>
26#include <linux/types.h> 28#include <linux/types.h>
@@ -33,36 +35,43 @@
33#include <linux/slab.h> 35#include <linux/slab.h>
34#include <linux/sysfs.h> 36#include <linux/sysfs.h>
35 37
36/* 38#define SUPPORTED_CABLE_MAX 32
37 * extcon_cable_name suggests the standard cable names for commonly used 39#define CABLE_NAME_MAX 30
38 * cable types. 40
39 * 41static const char *extcon_name[] = {
40 * However, please do not use extcon_cable_name directly for extcon_dev 42 [EXTCON_NONE] = "NONE",
41 * struct's supported_cable pointer unless your device really supports 43
42 * every single port-type of the following cable names. Please choose cable 44 /* USB external connector */
43 * names that are actually used in your extcon device.
44 */
45const char extcon_cable_name[][CABLE_NAME_MAX + 1] = {
46 [EXTCON_USB] = "USB", 45 [EXTCON_USB] = "USB",
47 [EXTCON_USB_HOST] = "USB-Host", 46 [EXTCON_USB_HOST] = "USB-HOST",
47
48 /* Charger external connector */
48 [EXTCON_TA] = "TA", 49 [EXTCON_TA] = "TA",
49 [EXTCON_FAST_CHARGER] = "Fast-charger", 50 [EXTCON_FAST_CHARGER] = "FAST-CHARGER",
50 [EXTCON_SLOW_CHARGER] = "Slow-charger", 51 [EXTCON_SLOW_CHARGER] = "SLOW-CHARGER",
51 [EXTCON_CHARGE_DOWNSTREAM] = "Charge-downstream", 52 [EXTCON_CHARGE_DOWNSTREAM] = "CHARGE-DOWNSTREAM",
53
54 /* Audio/Video external connector */
55 [EXTCON_LINE_IN] = "LINE-IN",
56 [EXTCON_LINE_OUT] = "LINE-OUT",
57 [EXTCON_MICROPHONE] = "MICROPHONE",
58 [EXTCON_HEADPHONE] = "HEADPHONE",
59
52 [EXTCON_HDMI] = "HDMI", 60 [EXTCON_HDMI] = "HDMI",
53 [EXTCON_MHL] = "MHL", 61 [EXTCON_MHL] = "MHL",
54 [EXTCON_DVI] = "DVI", 62 [EXTCON_DVI] = "DVI",
55 [EXTCON_VGA] = "VGA", 63 [EXTCON_VGA] = "VGA",
56 [EXTCON_DOCK] = "Dock", 64 [EXTCON_SPDIF_IN] = "SPDIF-IN",
57 [EXTCON_LINE_IN] = "Line-in", 65 [EXTCON_SPDIF_OUT] = "SPDIF-OUT",
58 [EXTCON_LINE_OUT] = "Line-out", 66 [EXTCON_VIDEO_IN] = "VIDEO-IN",
59 [EXTCON_MIC_IN] = "Microphone", 67 [EXTCON_VIDEO_OUT] = "VIDEO-OUT",
60 [EXTCON_HEADPHONE_OUT] = "Headphone", 68
61 [EXTCON_SPDIF_IN] = "SPDIF-in", 69 /* Etc external connector */
62 [EXTCON_SPDIF_OUT] = "SPDIF-out", 70 [EXTCON_DOCK] = "DOCK",
63 [EXTCON_VIDEO_IN] = "Video-in", 71 [EXTCON_JIG] = "JIG",
64 [EXTCON_VIDEO_OUT] = "Video-out", 72 [EXTCON_MECHANICAL] = "MECHANICAL",
65 [EXTCON_MECHANICAL] = "Mechanical", 73
74 NULL,
66}; 75};
67 76
68static struct class *extcon_class; 77static struct class *extcon_class;
@@ -102,6 +111,61 @@ static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
102 return 0; 111 return 0;
103} 112}
104 113
114static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id)
115{
116 int i;
117
118 /* Find the the index of extcon cable in edev->supported_cable */
119 for (i = 0; i < edev->max_supported; i++) {
120 if (edev->supported_cable[i] == id)
121 return i;
122 }
123
124 return -EINVAL;
125}
126
127static int find_cable_id_by_name(struct extcon_dev *edev, const char *name)
128{
129 unsigned int id = -EINVAL;
130 int i = 0;
131
132 /* Find the id of extcon cable */
133 while (extcon_name[i]) {
134 if (!strncmp(extcon_name[i], name, CABLE_NAME_MAX)) {
135 id = i;
136 break;
137 }
138 i++;
139 }
140
141 return id;
142}
143
144static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
145{
146 unsigned int id;
147
148 if (edev->max_supported == 0)
149 return -EINVAL;
150
151 /* Find the the number of extcon cable */
152 id = find_cable_id_by_name(edev, name);
153 if (id < 0)
154 return id;
155
156 return find_cable_index_by_id(edev, id);
157}
158
159static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached)
160{
161 if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) {
162 *attached = new ? true : false;
163 return true;
164 }
165
166 return false;
167}
168
105static ssize_t state_show(struct device *dev, struct device_attribute *attr, 169static ssize_t state_show(struct device *dev, struct device_attribute *attr,
106 char *buf) 170 char *buf)
107{ 171{
@@ -119,11 +183,9 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
119 if (edev->max_supported == 0) 183 if (edev->max_supported == 0)
120 return sprintf(buf, "%u\n", edev->state); 184 return sprintf(buf, "%u\n", edev->state);
121 185
122 for (i = 0; i < SUPPORTED_CABLE_MAX; i++) { 186 for (i = 0; i < edev->max_supported; i++) {
123 if (!edev->supported_cable[i])
124 break;
125 count += sprintf(buf + count, "%s=%d\n", 187 count += sprintf(buf + count, "%s=%d\n",
126 edev->supported_cable[i], 188 extcon_name[edev->supported_cable[i]],
127 !!(edev->state & (1 << i))); 189 !!(edev->state & (1 << i)));
128 } 190 }
129 191
@@ -155,15 +217,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
155{ 217{
156 struct extcon_dev *edev = dev_get_drvdata(dev); 218 struct extcon_dev *edev = dev_get_drvdata(dev);
157 219
158 /* Optional callback given by the user */ 220 return sprintf(buf, "%s\n", edev->name);
159 if (edev->print_name) {
160 int ret = edev->print_name(edev, buf);
161
162 if (ret >= 0)
163 return ret;
164 }
165
166 return sprintf(buf, "%s\n", dev_name(&edev->dev));
167} 221}
168static DEVICE_ATTR_RO(name); 222static DEVICE_ATTR_RO(name);
169 223
@@ -172,9 +226,10 @@ static ssize_t cable_name_show(struct device *dev,
172{ 226{
173 struct extcon_cable *cable = container_of(attr, struct extcon_cable, 227 struct extcon_cable *cable = container_of(attr, struct extcon_cable,
174 attr_name); 228 attr_name);
229 int i = cable->cable_index;
175 230
176 return sprintf(buf, "%s\n", 231 return sprintf(buf, "%s\n",
177 cable->edev->supported_cable[cable->cable_index]); 232 extcon_name[cable->edev->supported_cable[i]]);
178} 233}
179 234
180static ssize_t cable_state_show(struct device *dev, 235static ssize_t cable_state_show(struct device *dev,
@@ -183,9 +238,11 @@ static ssize_t cable_state_show(struct device *dev,
183 struct extcon_cable *cable = container_of(attr, struct extcon_cable, 238 struct extcon_cable *cable = container_of(attr, struct extcon_cable,
184 attr_state); 239 attr_state);
185 240
241 int i = cable->cable_index;
242
186 return sprintf(buf, "%d\n", 243 return sprintf(buf, "%d\n",
187 extcon_get_cable_state_(cable->edev, 244 extcon_get_cable_state_(cable->edev,
188 cable->cable_index)); 245 cable->edev->supported_cable[i]));
189} 246}
190 247
191/** 248/**
@@ -211,12 +268,14 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
211 char *envp[3]; 268 char *envp[3];
212 int env_offset = 0; 269 int env_offset = 0;
213 int length; 270 int length;
271 int index;
214 unsigned long flags; 272 unsigned long flags;
273 bool attached;
215 274
216 spin_lock_irqsave(&edev->lock, flags); 275 spin_lock_irqsave(&edev->lock, flags);
217 276
218 if (edev->state != ((edev->state & ~mask) | (state & mask))) { 277 if (edev->state != ((edev->state & ~mask) | (state & mask))) {
219 u32 old_state = edev->state; 278 u32 old_state;
220 279
221 if (check_mutually_exclusive(edev, (edev->state & ~mask) | 280 if (check_mutually_exclusive(edev, (edev->state & ~mask) |
222 (state & mask))) { 281 (state & mask))) {
@@ -224,10 +283,17 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
224 return -EPERM; 283 return -EPERM;
225 } 284 }
226 285
286 old_state = edev->state;
227 edev->state &= ~mask; 287 edev->state &= ~mask;
228 edev->state |= state & mask; 288 edev->state |= state & mask;
229 289
230 raw_notifier_call_chain(&edev->nh, old_state, edev); 290 for (index = 0; index < edev->max_supported; index++) {
291 if (is_extcon_changed(old_state, edev->state, index,
292 &attached))
293 raw_notifier_call_chain(&edev->nh[index],
294 attached, edev);
295 }
296
231 /* This could be in interrupt handler */ 297 /* This could be in interrupt handler */
232 prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); 298 prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
233 if (prop_buf) { 299 if (prop_buf) {
@@ -284,39 +350,19 @@ int extcon_set_state(struct extcon_dev *edev, u32 state)
284EXPORT_SYMBOL_GPL(extcon_set_state); 350EXPORT_SYMBOL_GPL(extcon_set_state);
285 351
286/** 352/**
287 * extcon_find_cable_index() - Get the cable index based on the cable name. 353 * extcon_get_cable_state_() - Get the status of a specific cable.
288 * @edev: the extcon device that has the cable. 354 * @edev: the extcon device that has the cable.
289 * @cable_name: cable name to be searched. 355 * @id: the unique id of each external connector in extcon enumeration.
290 *
291 * Note that accessing a cable state based on cable_index is faster than
292 * cable_name because using cable_name induces a loop with strncmp().
293 * Thus, when get/set_cable_state is repeatedly used, using cable_index
294 * is recommended.
295 */ 356 */
296int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name) 357int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id)
297{ 358{
298 int i; 359 int index;
299
300 if (edev->supported_cable) {
301 for (i = 0; edev->supported_cable[i]; i++) {
302 if (!strncmp(edev->supported_cable[i],
303 cable_name, CABLE_NAME_MAX))
304 return i;
305 }
306 }
307 360
308 return -EINVAL; 361 index = find_cable_index_by_id(edev, id);
309} 362 if (index < 0)
310EXPORT_SYMBOL_GPL(extcon_find_cable_index); 363 return index;
311 364
312/** 365 if (edev->max_supported && edev->max_supported <= index)
313 * extcon_get_cable_state_() - Get the status of a specific cable.
314 * @edev: the extcon device that has the cable.
315 * @index: cable index that can be retrieved by extcon_find_cable_index().
316 */
317int extcon_get_cable_state_(struct extcon_dev *edev, int index)
318{
319 if (index < 0 || (edev->max_supported && edev->max_supported <= index))
320 return -EINVAL; 366 return -EINVAL;
321 367
322 return !!(edev->state & (1 << index)); 368 return !!(edev->state & (1 << index));
@@ -332,25 +378,35 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
332 */ 378 */
333int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name) 379int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
334{ 380{
335 return extcon_get_cable_state_(edev, extcon_find_cable_index 381 unsigned int id;
336 (edev, cable_name)); 382
383 id = find_cable_id_by_name(edev, cable_name);
384 if (id < 0)
385 return id;
386
387 return extcon_get_cable_state_(edev, id);
337} 388}
338EXPORT_SYMBOL_GPL(extcon_get_cable_state); 389EXPORT_SYMBOL_GPL(extcon_get_cable_state);
339 390
340/** 391/**
341 * extcon_set_cable_state_() - Set the status of a specific cable. 392 * extcon_set_cable_state_() - Set the status of a specific cable.
342 * @edev: the extcon device that has the cable. 393 * @edev: the extcon device that has the cable.
343 * @index: cable index that can be retrieved by 394 * @id: the unique id of each external connector
344 * extcon_find_cable_index(). 395 * in extcon enumeration.
345 * @cable_state: the new cable status. The default semantics is 396 * @state: the new cable status. The default semantics is
346 * true: attached / false: detached. 397 * true: attached / false: detached.
347 */ 398 */
348int extcon_set_cable_state_(struct extcon_dev *edev, 399int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id,
349 int index, bool cable_state) 400 bool cable_state)
350{ 401{
351 u32 state; 402 u32 state;
403 int index;
404
405 index = find_cable_index_by_id(edev, id);
406 if (index < 0)
407 return index;
352 408
353 if (index < 0 || (edev->max_supported && edev->max_supported <= index)) 409 if (edev->max_supported && edev->max_supported <= index)
354 return -EINVAL; 410 return -EINVAL;
355 411
356 state = cable_state ? (1 << index) : 0; 412 state = cable_state ? (1 << index) : 0;
@@ -370,8 +426,13 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
370int extcon_set_cable_state(struct extcon_dev *edev, 426int extcon_set_cable_state(struct extcon_dev *edev,
371 const char *cable_name, bool cable_state) 427 const char *cable_name, bool cable_state)
372{ 428{
373 return extcon_set_cable_state_(edev, extcon_find_cable_index 429 unsigned int id;
374 (edev, cable_name), cable_state); 430
431 id = find_cable_id_by_name(edev, cable_name);
432 if (id < 0)
433 return id;
434
435 return extcon_set_cable_state_(edev, id, cable_state);
375} 436}
376EXPORT_SYMBOL_GPL(extcon_set_cable_state); 437EXPORT_SYMBOL_GPL(extcon_set_cable_state);
377 438
@@ -395,29 +456,6 @@ out:
395} 456}
396EXPORT_SYMBOL_GPL(extcon_get_extcon_dev); 457EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
397 458
398static int _call_per_cable(struct notifier_block *nb, unsigned long val,
399 void *ptr)
400{
401 struct extcon_specific_cable_nb *obj = container_of(nb,
402 struct extcon_specific_cable_nb, internal_nb);
403 struct extcon_dev *edev = ptr;
404
405 if ((val & (1 << obj->cable_index)) !=
406 (edev->state & (1 << obj->cable_index))) {
407 bool cable_state = true;
408
409 obj->previous_value = val;
410
411 if (val & (1 << obj->cable_index))
412 cable_state = false;
413
414 return obj->user_nb->notifier_call(obj->user_nb,
415 cable_state, ptr);
416 }
417
418 return NOTIFY_OK;
419}
420
421/** 459/**
422 * extcon_register_interest() - Register a notifier for a state change of a 460 * extcon_register_interest() - Register a notifier for a state change of a
423 * specific cable, not an entier set of cables of a 461 * specific cable, not an entier set of cables of a
@@ -456,20 +494,18 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
456 if (!obj->edev) 494 if (!obj->edev)
457 return -ENODEV; 495 return -ENODEV;
458 496
459 obj->cable_index = extcon_find_cable_index(obj->edev, 497 obj->cable_index = find_cable_index_by_name(obj->edev,
460 cable_name); 498 cable_name);
461 if (obj->cable_index < 0) 499 if (obj->cable_index < 0)
462 return obj->cable_index; 500 return obj->cable_index;
463 501
464 obj->user_nb = nb; 502 obj->user_nb = nb;
465 503
466 obj->internal_nb.notifier_call = _call_per_cable;
467
468 spin_lock_irqsave(&obj->edev->lock, flags); 504 spin_lock_irqsave(&obj->edev->lock, flags);
469 ret = raw_notifier_chain_register(&obj->edev->nh, 505 ret = raw_notifier_chain_register(
470 &obj->internal_nb); 506 &obj->edev->nh[obj->cable_index],
507 obj->user_nb);
471 spin_unlock_irqrestore(&obj->edev->lock, flags); 508 spin_unlock_irqrestore(&obj->edev->lock, flags);
472 return ret;
473 } else { 509 } else {
474 struct class_dev_iter iter; 510 struct class_dev_iter iter;
475 struct extcon_dev *extd; 511 struct extcon_dev *extd;
@@ -481,7 +517,7 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
481 while ((dev = class_dev_iter_next(&iter))) { 517 while ((dev = class_dev_iter_next(&iter))) {
482 extd = dev_get_drvdata(dev); 518 extd = dev_get_drvdata(dev);
483 519
484 if (extcon_find_cable_index(extd, cable_name) < 0) 520 if (find_cable_index_by_name(extd, cable_name) < 0)
485 continue; 521 continue;
486 522
487 class_dev_iter_exit(&iter); 523 class_dev_iter_exit(&iter);
@@ -489,8 +525,10 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
489 cable_name, nb); 525 cable_name, nb);
490 } 526 }
491 527
492 return -ENODEV; 528 ret = -ENODEV;
493 } 529 }
530
531 return ret;
494} 532}
495EXPORT_SYMBOL_GPL(extcon_register_interest); 533EXPORT_SYMBOL_GPL(extcon_register_interest);
496 534
@@ -509,7 +547,8 @@ int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
509 return -EINVAL; 547 return -EINVAL;
510 548
511 spin_lock_irqsave(&obj->edev->lock, flags); 549 spin_lock_irqsave(&obj->edev->lock, flags);
512 ret = raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb); 550 ret = raw_notifier_chain_unregister(
551 &obj->edev->nh[obj->cable_index], obj->user_nb);
513 spin_unlock_irqrestore(&obj->edev->lock, flags); 552 spin_unlock_irqrestore(&obj->edev->lock, flags);
514 553
515 return ret; 554 return ret;
@@ -519,21 +558,24 @@ EXPORT_SYMBOL_GPL(extcon_unregister_interest);
519/** 558/**
520 * extcon_register_notifier() - Register a notifiee to get notified by 559 * extcon_register_notifier() - Register a notifiee to get notified by
521 * any attach status changes from the extcon. 560 * any attach status changes from the extcon.
522 * @edev: the extcon device. 561 * @edev: the extcon device that has the external connecotr.
562 * @id: the unique id of each external connector in extcon enumeration.
523 * @nb: a notifier block to be registered. 563 * @nb: a notifier block to be registered.
524 * 564 *
525 * Note that the second parameter given to the callback of nb (val) is 565 * Note that the second parameter given to the callback of nb (val) is
526 * "old_state", not the current state. The current state can be retrieved 566 * "old_state", not the current state. The current state can be retrieved
527 * by looking at the third pameter (edev pointer)'s state value. 567 * by looking at the third pameter (edev pointer)'s state value.
528 */ 568 */
529int extcon_register_notifier(struct extcon_dev *edev, 569int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
530 struct notifier_block *nb) 570 struct notifier_block *nb)
531{ 571{
532 unsigned long flags; 572 unsigned long flags;
533 int ret; 573 int ret, idx;
574
575 idx = find_cable_index_by_id(edev, id);
534 576
535 spin_lock_irqsave(&edev->lock, flags); 577 spin_lock_irqsave(&edev->lock, flags);
536 ret = raw_notifier_chain_register(&edev->nh, nb); 578 ret = raw_notifier_chain_register(&edev->nh[idx], nb);
537 spin_unlock_irqrestore(&edev->lock, flags); 579 spin_unlock_irqrestore(&edev->lock, flags);
538 580
539 return ret; 581 return ret;
@@ -542,17 +584,20 @@ EXPORT_SYMBOL_GPL(extcon_register_notifier);
542 584
543/** 585/**
544 * extcon_unregister_notifier() - Unregister a notifiee from the extcon device. 586 * extcon_unregister_notifier() - Unregister a notifiee from the extcon device.
545 * @edev: the extcon device. 587 * @edev: the extcon device that has the external connecotr.
546 * @nb: a registered notifier block to be unregistered. 588 * @id: the unique id of each external connector in extcon enumeration.
589 * @nb: a notifier block to be registered.
547 */ 590 */
548int extcon_unregister_notifier(struct extcon_dev *edev, 591int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
549 struct notifier_block *nb) 592 struct notifier_block *nb)
550{ 593{
551 unsigned long flags; 594 unsigned long flags;
552 int ret; 595 int ret, idx;
596
597 idx = find_cable_index_by_id(edev, id);
553 598
554 spin_lock_irqsave(&edev->lock, flags); 599 spin_lock_irqsave(&edev->lock, flags);
555 ret = raw_notifier_chain_unregister(&edev->nh, nb); 600 ret = raw_notifier_chain_unregister(&edev->nh[idx], nb);
556 spin_unlock_irqrestore(&edev->lock, flags); 601 spin_unlock_irqrestore(&edev->lock, flags);
557 602
558 return ret; 603 return ret;
@@ -595,7 +640,7 @@ static void dummy_sysfs_dev_release(struct device *dev)
595 640
596/* 641/*
597 * extcon_dev_allocate() - Allocate the memory of extcon device. 642 * extcon_dev_allocate() - Allocate the memory of extcon device.
598 * @supported_cable: Array of supported cable names ending with NULL. 643 * @supported_cable: Array of supported extcon ending with EXTCON_NONE.
599 * If supported_cable is NULL, cable name related APIs 644 * If supported_cable is NULL, cable name related APIs
600 * are disabled. 645 * are disabled.
601 * 646 *
@@ -605,7 +650,7 @@ static void dummy_sysfs_dev_release(struct device *dev)
605 * 650 *
606 * Return the pointer of extcon device if success or ERR_PTR(err) if fail 651 * Return the pointer of extcon device if success or ERR_PTR(err) if fail
607 */ 652 */
608struct extcon_dev *extcon_dev_allocate(const char **supported_cable) 653struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable)
609{ 654{
610 struct extcon_dev *edev; 655 struct extcon_dev *edev;
611 656
@@ -647,7 +692,7 @@ static void devm_extcon_dev_release(struct device *dev, void *res)
647/** 692/**
648 * devm_extcon_dev_allocate - Allocate managed extcon device 693 * devm_extcon_dev_allocate - Allocate managed extcon device
649 * @dev: device owning the extcon device being created 694 * @dev: device owning the extcon device being created
650 * @supported_cable: Array of supported cable names ending with NULL. 695 * @supported_cable: Array of supported extcon ending with EXTCON_NONE.
651 * If supported_cable is NULL, cable name related APIs 696 * If supported_cable is NULL, cable name related APIs
652 * are disabled. 697 * are disabled.
653 * 698 *
@@ -659,7 +704,7 @@ static void devm_extcon_dev_release(struct device *dev, void *res)
659 * or ERR_PTR(err) if fail 704 * or ERR_PTR(err) if fail
660 */ 705 */
661struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, 706struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
662 const char **supported_cable) 707 const unsigned int *supported_cable)
663{ 708{
664 struct extcon_dev **ptr, *edev; 709 struct extcon_dev **ptr, *edev;
665 710
@@ -701,6 +746,7 @@ EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
701int extcon_dev_register(struct extcon_dev *edev) 746int extcon_dev_register(struct extcon_dev *edev)
702{ 747{
703 int ret, index = 0; 748 int ret, index = 0;
749 static atomic_t edev_no = ATOMIC_INIT(-1);
704 750
705 if (!extcon_class) { 751 if (!extcon_class) {
706 ret = create_extcon_class(); 752 ret = create_extcon_class();
@@ -708,30 +754,29 @@ int extcon_dev_register(struct extcon_dev *edev)
708 return ret; 754 return ret;
709 } 755 }
710 756
711 if (edev->supported_cable) { 757 if (!edev->supported_cable)
712 /* Get size of array */ 758 return -EINVAL;
713 for (index = 0; edev->supported_cable[index]; index++) 759
714 ; 760 for (; edev->supported_cable[index] != EXTCON_NONE; index++);
715 edev->max_supported = index;
716 } else {
717 edev->max_supported = 0;
718 }
719 761
762 edev->max_supported = index;
720 if (index > SUPPORTED_CABLE_MAX) { 763 if (index > SUPPORTED_CABLE_MAX) {
721 dev_err(&edev->dev, "extcon: maximum number of supported cables exceeded.\n"); 764 dev_err(&edev->dev,
765 "exceed the maximum number of supported cables\n");
722 return -EINVAL; 766 return -EINVAL;
723 } 767 }
724 768
725 edev->dev.class = extcon_class; 769 edev->dev.class = extcon_class;
726 edev->dev.release = extcon_dev_release; 770 edev->dev.release = extcon_dev_release;
727 771
728 edev->name = edev->name ? edev->name : dev_name(edev->dev.parent); 772 edev->name = dev_name(edev->dev.parent);
729 if (IS_ERR_OR_NULL(edev->name)) { 773 if (IS_ERR_OR_NULL(edev->name)) {
730 dev_err(&edev->dev, 774 dev_err(&edev->dev,
731 "extcon device name is null\n"); 775 "extcon device name is null\n");
732 return -EINVAL; 776 return -EINVAL;
733 } 777 }
734 dev_set_name(&edev->dev, "%s", edev->name); 778 dev_set_name(&edev->dev, "extcon%lu",
779 (unsigned long)atomic_inc_return(&edev_no));
735 780
736 if (edev->max_supported) { 781 if (edev->max_supported) {
737 char buf[10]; 782 char buf[10];
@@ -864,7 +909,15 @@ int extcon_dev_register(struct extcon_dev *edev)
864 909
865 spin_lock_init(&edev->lock); 910 spin_lock_init(&edev->lock);
866 911
867 RAW_INIT_NOTIFIER_HEAD(&edev->nh); 912 edev->nh = devm_kzalloc(&edev->dev,
913 sizeof(*edev->nh) * edev->max_supported, GFP_KERNEL);
914 if (!edev->nh) {
915 ret = -ENOMEM;
916 goto err_dev;
917 }
918
919 for (index = 0; index < edev->max_supported; index++)
920 RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]);
868 921
869 dev_set_drvdata(&edev->dev, edev); 922 dev_set_drvdata(&edev->dev, edev);
870 edev->state = 0; 923 edev->state = 0;
@@ -1044,6 +1097,15 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
1044#endif /* CONFIG_OF */ 1097#endif /* CONFIG_OF */
1045EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle); 1098EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle);
1046 1099
1100/**
1101 * extcon_get_edev_name() - Get the name of the extcon device.
1102 * @edev: the extcon device
1103 */
1104const char *extcon_get_edev_name(struct extcon_dev *edev)
1105{
1106 return !edev ? NULL : edev->name;
1107}
1108
1047static int __init extcon_class_init(void) 1109static int __init extcon_class_init(void)
1048{ 1110{
1049 return create_extcon_class(); 1111 return create_extcon_class();
@@ -1059,6 +1121,7 @@ static void __exit extcon_class_exit(void)
1059} 1121}
1060module_exit(extcon_class_exit); 1122module_exit(extcon_class_exit);
1061 1123
1124MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
1062MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); 1125MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
1063MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); 1126MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
1064MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 1127MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");