1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * drivers/extcon/extcon.c - External Connector (extcon) framework. 4 * 5 * Copyright (C) 2015 Samsung Electronics 6 * Author: Chanwoo Choi <cw00.choi@samsung.com> 7 * 8 * Copyright (C) 2012 Samsung Electronics 9 * Author: Donggeun Kim <dg77.kim@samsung.com> 10 * Author: MyungJoo Ham <myungjoo.ham@samsung.com> 11 * 12 * based on android/drivers/switch/switch_class.c 13 * Copyright (C) 2008 Google, Inc. 14 * Author: Mike Lockwood <lockwood@android.com> 15 */ 16 17 #include <linux/module.h> 18 #include <linux/types.h> 19 #include <linux/idr.h> 20 #include <linux/init.h> 21 #include <linux/device.h> 22 #include <linux/fs.h> 23 #include <linux/err.h> 24 #include <linux/of.h> 25 #include <linux/slab.h> 26 #include <linux/sysfs.h> 27 28 #include "extcon.h" 29 30 #define SUPPORTED_CABLE_MAX 32 31 32 static const struct __extcon_info { 33 unsigned int type; 34 unsigned int id; 35 const char *name; 36 37 } extcon_info[] = { 38 [EXTCON_NONE] = { 39 .type = EXTCON_TYPE_MISC, 40 .id = EXTCON_NONE, 41 .name = "NONE", 42 }, 43 44 /* USB external connector */ 45 [EXTCON_USB] = { 46 .type = EXTCON_TYPE_USB, 47 .id = EXTCON_USB, 48 .name = "USB", 49 }, 50 [EXTCON_USB_HOST] = { 51 .type = EXTCON_TYPE_USB, 52 .id = EXTCON_USB_HOST, 53 .name = "USB-HOST", 54 }, 55 56 /* Charging external connector */ 57 [EXTCON_CHG_USB_SDP] = { 58 .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, 59 .id = EXTCON_CHG_USB_SDP, 60 .name = "SDP", 61 }, 62 [EXTCON_CHG_USB_DCP] = { 63 .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, 64 .id = EXTCON_CHG_USB_DCP, 65 .name = "DCP", 66 }, 67 [EXTCON_CHG_USB_CDP] = { 68 .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, 69 .id = EXTCON_CHG_USB_CDP, 70 .name = "CDP", 71 }, 72 [EXTCON_CHG_USB_ACA] = { 73 .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, 74 .id = EXTCON_CHG_USB_ACA, 75 .name = "ACA", 76 }, 77 [EXTCON_CHG_USB_FAST] = { 78 .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, 79 .id = EXTCON_CHG_USB_FAST, 80 .name = "FAST-CHARGER", 81 }, 82 [EXTCON_CHG_USB_SLOW] = { 83 .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, 84 .id = EXTCON_CHG_USB_SLOW, 85 .name = "SLOW-CHARGER", 86 }, 87 [EXTCON_CHG_WPT] = { 88 .type = EXTCON_TYPE_CHG, 89 .id = EXTCON_CHG_WPT, 90 .name = "WPT", 91 }, 92 [EXTCON_CHG_USB_PD] = { 93 .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, 94 .id = EXTCON_CHG_USB_PD, 95 .name = "PD", 96 }, 97 98 /* Jack external connector */ 99 [EXTCON_JACK_MICROPHONE] = { 100 .type = EXTCON_TYPE_JACK, 101 .id = EXTCON_JACK_MICROPHONE, 102 .name = "MICROPHONE", 103 }, 104 [EXTCON_JACK_HEADPHONE] = { 105 .type = EXTCON_TYPE_JACK, 106 .id = EXTCON_JACK_HEADPHONE, 107 .name = "HEADPHONE", 108 }, 109 [EXTCON_JACK_LINE_IN] = { 110 .type = EXTCON_TYPE_JACK, 111 .id = EXTCON_JACK_LINE_IN, 112 .name = "LINE-IN", 113 }, 114 [EXTCON_JACK_LINE_OUT] = { 115 .type = EXTCON_TYPE_JACK, 116 .id = EXTCON_JACK_LINE_OUT, 117 .name = "LINE-OUT", 118 }, 119 [EXTCON_JACK_VIDEO_IN] = { 120 .type = EXTCON_TYPE_JACK, 121 .id = EXTCON_JACK_VIDEO_IN, 122 .name = "VIDEO-IN", 123 }, 124 [EXTCON_JACK_VIDEO_OUT] = { 125 .type = EXTCON_TYPE_JACK, 126 .id = EXTCON_JACK_VIDEO_OUT, 127 .name = "VIDEO-OUT", 128 }, 129 [EXTCON_JACK_SPDIF_IN] = { 130 .type = EXTCON_TYPE_JACK, 131 .id = EXTCON_JACK_SPDIF_IN, 132 .name = "SPDIF-IN", 133 }, 134 [EXTCON_JACK_SPDIF_OUT] = { 135 .type = EXTCON_TYPE_JACK, 136 .id = EXTCON_JACK_SPDIF_OUT, 137 .name = "SPDIF-OUT", 138 }, 139 140 /* Display external connector */ 141 [EXTCON_DISP_HDMI] = { 142 .type = EXTCON_TYPE_DISP, 143 .id = EXTCON_DISP_HDMI, 144 .name = "HDMI", 145 }, 146 [EXTCON_DISP_MHL] = { 147 .type = EXTCON_TYPE_DISP, 148 .id = EXTCON_DISP_MHL, 149 .name = "MHL", 150 }, 151 [EXTCON_DISP_DVI] = { 152 .type = EXTCON_TYPE_DISP, 153 .id = EXTCON_DISP_DVI, 154 .name = "DVI", 155 }, 156 [EXTCON_DISP_VGA] = { 157 .type = EXTCON_TYPE_DISP, 158 .id = EXTCON_DISP_VGA, 159 .name = "VGA", 160 }, 161 [EXTCON_DISP_DP] = { 162 .type = EXTCON_TYPE_DISP | EXTCON_TYPE_USB, 163 .id = EXTCON_DISP_DP, 164 .name = "DP", 165 }, 166 [EXTCON_DISP_HMD] = { 167 .type = EXTCON_TYPE_DISP | EXTCON_TYPE_USB, 168 .id = EXTCON_DISP_HMD, 169 .name = "HMD", 170 }, 171 [EXTCON_DISP_CVBS] = { 172 .type = EXTCON_TYPE_DISP, 173 .id = EXTCON_DISP_CVBS, 174 .name = "CVBS", 175 }, 176 [EXTCON_DISP_EDP] = { 177 .type = EXTCON_TYPE_DISP, 178 .id = EXTCON_DISP_EDP, 179 .name = "EDP", 180 }, 181 182 /* Miscellaneous external connector */ 183 [EXTCON_DOCK] = { 184 .type = EXTCON_TYPE_MISC, 185 .id = EXTCON_DOCK, 186 .name = "DOCK", 187 }, 188 [EXTCON_JIG] = { 189 .type = EXTCON_TYPE_MISC, 190 .id = EXTCON_JIG, 191 .name = "JIG", 192 }, 193 [EXTCON_MECHANICAL] = { 194 .type = EXTCON_TYPE_MISC, 195 .id = EXTCON_MECHANICAL, 196 .name = "MECHANICAL", 197 }, 198 199 { /* sentinel */ } 200 }; 201 202 /** 203 * struct extcon_cable - An internal data for an external connector. 204 * @edev: the extcon device 205 * @cable_index: the index of this cable in the edev 206 * @attr_g: the attribute group for the cable 207 * @attr_name: "name" sysfs entry 208 * @attr_state: "state" sysfs entry 209 * @attrs: the array pointing to attr_name and attr_state for attr_g 210 * @usb_propval: the array of USB connector properties 211 * @chg_propval: the array of charger connector properties 212 * @jack_propval: the array of jack connector properties 213 * @disp_propval: the array of display connector properties 214 * @usb_bits: the bit array of the USB connector property capabilities 215 * @chg_bits: the bit array of the charger connector property capabilities 216 * @jack_bits: the bit array of the jack connector property capabilities 217 * @disp_bits: the bit array of the display connector property capabilities 218 */ 219 struct extcon_cable { 220 struct extcon_dev *edev; 221 int cable_index; 222 223 struct attribute_group attr_g; 224 struct device_attribute attr_name; 225 struct device_attribute attr_state; 226 227 struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ 228 229 union extcon_property_value usb_propval[EXTCON_PROP_USB_CNT]; 230 union extcon_property_value chg_propval[EXTCON_PROP_CHG_CNT]; 231 union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT]; 232 union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT]; 233 234 DECLARE_BITMAP(usb_bits, EXTCON_PROP_USB_CNT); 235 DECLARE_BITMAP(chg_bits, EXTCON_PROP_CHG_CNT); 236 DECLARE_BITMAP(jack_bits, EXTCON_PROP_JACK_CNT); 237 DECLARE_BITMAP(disp_bits, EXTCON_PROP_DISP_CNT); 238 }; 239 240 static struct class *extcon_class; 241 242 static DEFINE_IDA(extcon_dev_ids); 243 static LIST_HEAD(extcon_dev_list); 244 static DEFINE_MUTEX(extcon_dev_list_lock); 245 246 static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state) 247 { 248 int i; 249 250 if (!edev->mutually_exclusive) 251 return 0; 252 253 for (i = 0; edev->mutually_exclusive[i]; i++) { 254 int weight; 255 u32 correspondants = new_state & edev->mutually_exclusive[i]; 256 257 /* calculate the total number of bits set */ 258 weight = hweight32(correspondants); 259 if (weight > 1) 260 return i + 1; 261 } 262 263 return 0; 264 } 265 266 static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id) 267 { 268 int i; 269 270 /* Find the index of extcon cable in edev->supported_cable */ 271 for (i = 0; i < edev->max_supported; i++) { 272 if (edev->supported_cable[i] == id) 273 return i; 274 } 275 276 return -EINVAL; 277 } 278 279 static int get_extcon_type(unsigned int prop) 280 { 281 switch (prop) { 282 case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX: 283 return EXTCON_TYPE_USB; 284 case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX: 285 return EXTCON_TYPE_CHG; 286 case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX: 287 return EXTCON_TYPE_JACK; 288 case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX: 289 return EXTCON_TYPE_DISP; 290 default: 291 return -EINVAL; 292 } 293 } 294 295 static bool is_extcon_attached(struct extcon_dev *edev, unsigned int index) 296 { 297 return !!(edev->state & BIT(index)); 298 } 299 300 static bool is_extcon_changed(struct extcon_dev *edev, int index, 301 bool new_state) 302 { 303 int state = !!(edev->state & BIT(index)); 304 return (state != new_state); 305 } 306 307 static bool is_extcon_property_supported(unsigned int id, unsigned int prop) 308 { 309 int type; 310 311 /* Check whether the property is supported or not. */ 312 type = get_extcon_type(prop); 313 if (type < 0) 314 return false; 315 316 /* Check whether a specific extcon id supports the property or not. */ 317 return !!(extcon_info[id].type & type); 318 } 319 320 static int is_extcon_property_capability(struct extcon_dev *edev, 321 unsigned int id, int index,unsigned int prop) 322 { 323 struct extcon_cable *cable; 324 int type, ret; 325 326 /* Check whether the property is supported or not. */ 327 type = get_extcon_type(prop); 328 if (type < 0) 329 return type; 330 331 cable = &edev->cables[index]; 332 333 switch (type) { 334 case EXTCON_TYPE_USB: 335 ret = test_bit(prop - EXTCON_PROP_USB_MIN, cable->usb_bits); 336 break; 337 case EXTCON_TYPE_CHG: 338 ret = test_bit(prop - EXTCON_PROP_CHG_MIN, cable->chg_bits); 339 break; 340 case EXTCON_TYPE_JACK: 341 ret = test_bit(prop - EXTCON_PROP_JACK_MIN, cable->jack_bits); 342 break; 343 case EXTCON_TYPE_DISP: 344 ret = test_bit(prop - EXTCON_PROP_DISP_MIN, cable->disp_bits); 345 break; 346 default: 347 ret = -EINVAL; 348 } 349 350 return ret; 351 } 352 353 static void init_property(struct extcon_dev *edev, unsigned int id, int index) 354 { 355 unsigned int type = extcon_info[id].type; 356 struct extcon_cable *cable = &edev->cables[index]; 357 358 if (EXTCON_TYPE_USB & type) 359 memset(cable->usb_propval, 0, sizeof(cable->usb_propval)); 360 if (EXTCON_TYPE_CHG & type) 361 memset(cable->chg_propval, 0, sizeof(cable->chg_propval)); 362 if (EXTCON_TYPE_JACK & type) 363 memset(cable->jack_propval, 0, sizeof(cable->jack_propval)); 364 if (EXTCON_TYPE_DISP & type) 365 memset(cable->disp_propval, 0, sizeof(cable->disp_propval)); 366 } 367 368 static ssize_t state_show(struct device *dev, struct device_attribute *attr, 369 char *buf) 370 { 371 int i, count = 0; 372 struct extcon_dev *edev = dev_get_drvdata(dev); 373 374 if (edev->max_supported == 0) 375 return sysfs_emit(buf, "%u\n", edev->state); 376 377 for (i = 0; i < edev->max_supported; i++) { 378 count += sysfs_emit_at(buf, count, "%s=%d\n", 379 extcon_info[edev->supported_cable[i]].name, 380 !!(edev->state & BIT(i))); 381 } 382 383 return count; 384 } 385 static DEVICE_ATTR_RO(state); 386 387 static ssize_t name_show(struct device *dev, struct device_attribute *attr, 388 char *buf) 389 { 390 struct extcon_dev *edev = dev_get_drvdata(dev); 391 392 return sysfs_emit(buf, "%s\n", edev->name); 393 } 394 static DEVICE_ATTR_RO(name); 395 396 static ssize_t cable_name_show(struct device *dev, 397 struct device_attribute *attr, char *buf) 398 { 399 struct extcon_cable *cable = container_of(attr, struct extcon_cable, 400 attr_name); 401 int i = cable->cable_index; 402 403 return sysfs_emit(buf, "%s\n", 404 extcon_info[cable->edev->supported_cable[i]].name); 405 } 406 407 static ssize_t cable_state_show(struct device *dev, 408 struct device_attribute *attr, char *buf) 409 { 410 struct extcon_cable *cable = container_of(attr, struct extcon_cable, 411 attr_state); 412 413 int i = cable->cable_index; 414 415 return sysfs_emit(buf, "%d\n", 416 extcon_get_state(cable->edev, cable->edev->supported_cable[i])); 417 } 418 419 /** 420 * extcon_sync() - Synchronize the state for an external connector. 421 * @edev: the extcon device 422 * @id: the unique id indicating an external connector 423 * 424 * Note that this function send a notification in order to synchronize 425 * the state and property of an external connector. 426 * 427 * Returns 0 if success or error number if fail. 428 */ 429 int extcon_sync(struct extcon_dev *edev, unsigned int id) 430 { 431 char name_buf[120]; 432 char state_buf[120]; 433 char *prop_buf; 434 char *envp[3]; 435 int env_offset = 0; 436 int length; 437 int index; 438 int state; 439 unsigned long flags; 440 441 if (!edev) 442 return -EINVAL; 443 444 index = find_cable_index_by_id(edev, id); 445 if (index < 0) 446 return index; 447 448 spin_lock_irqsave(&edev->lock, flags); 449 state = !!(edev->state & BIT(index)); 450 spin_unlock_irqrestore(&edev->lock, flags); 451 452 /* 453 * Call functions in a raw notifier chain for the specific one 454 * external connector. 455 */ 456 raw_notifier_call_chain(&edev->nh[index], state, edev); 457 458 /* 459 * Call functions in a raw notifier chain for the all supported 460 * external connectors. 461 */ 462 raw_notifier_call_chain(&edev->nh_all, state, edev); 463 464 spin_lock_irqsave(&edev->lock, flags); 465 /* This could be in interrupt handler */ 466 prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); 467 if (!prop_buf) { 468 /* Unlock early before uevent */ 469 spin_unlock_irqrestore(&edev->lock, flags); 470 471 dev_err(&edev->dev, "out of memory in extcon_set_state\n"); 472 kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE); 473 474 return -ENOMEM; 475 } 476 477 length = name_show(&edev->dev, NULL, prop_buf); 478 if (length > 0) { 479 if (prop_buf[length - 1] == '\n') 480 prop_buf[length - 1] = 0; 481 snprintf(name_buf, sizeof(name_buf), "NAME=%s", prop_buf); 482 envp[env_offset++] = name_buf; 483 } 484 485 length = state_show(&edev->dev, NULL, prop_buf); 486 if (length > 0) { 487 if (prop_buf[length - 1] == '\n') 488 prop_buf[length - 1] = 0; 489 snprintf(state_buf, sizeof(state_buf), "STATE=%s", prop_buf); 490 envp[env_offset++] = state_buf; 491 } 492 envp[env_offset] = NULL; 493 494 /* Unlock early before uevent */ 495 spin_unlock_irqrestore(&edev->lock, flags); 496 kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp); 497 free_page((unsigned long)prop_buf); 498 499 return 0; 500 } 501 EXPORT_SYMBOL_GPL(extcon_sync); 502 503 /** 504 * extcon_get_state() - Get the state of an external connector. 505 * @edev: the extcon device 506 * @id: the unique id indicating an external connector 507 * 508 * Returns 0 if success or error number if fail. 509 */ 510 int extcon_get_state(struct extcon_dev *edev, const unsigned int id) 511 { 512 int index, state; 513 unsigned long flags; 514 515 if (!edev) 516 return -EINVAL; 517 518 index = find_cable_index_by_id(edev, id); 519 if (index < 0) 520 return index; 521 522 spin_lock_irqsave(&edev->lock, flags); 523 state = is_extcon_attached(edev, index); 524 spin_unlock_irqrestore(&edev->lock, flags); 525 526 return state; 527 } 528 EXPORT_SYMBOL_GPL(extcon_get_state); 529 530 /** 531 * extcon_set_state() - Set the state of an external connector. 532 * @edev: the extcon device 533 * @id: the unique id indicating an external connector 534 * @state: the new state of an external connector. 535 * the default semantics is true: attached / false: detached. 536 * 537 * Note that this function set the state of an external connector without 538 * a notification. To synchronize the state of an external connector, 539 * have to use extcon_set_state_sync() and extcon_sync(). 540 * 541 * Returns 0 if success or error number if fail. 542 */ 543 int extcon_set_state(struct extcon_dev *edev, unsigned int id, bool state) 544 { 545 unsigned long flags; 546 int index, ret = 0; 547 548 if (!edev) 549 return -EINVAL; 550 551 index = find_cable_index_by_id(edev, id); 552 if (index < 0) 553 return index; 554 555 spin_lock_irqsave(&edev->lock, flags); 556 557 /* Check whether the external connector's state is changed. */ 558 if (!is_extcon_changed(edev, index, state)) 559 goto out; 560 561 if (check_mutually_exclusive(edev, 562 (edev->state & ~BIT(index)) | (state & BIT(index)))) { 563 ret = -EPERM; 564 goto out; 565 } 566 567 /* 568 * Initialize the value of extcon property before setting 569 * the detached state for an external connector. 570 */ 571 if (!state) 572 init_property(edev, id, index); 573 574 /* Update the state for an external connector. */ 575 if (state) 576 edev->state |= BIT(index); 577 else 578 edev->state &= ~(BIT(index)); 579 out: 580 spin_unlock_irqrestore(&edev->lock, flags); 581 582 return ret; 583 } 584 EXPORT_SYMBOL_GPL(extcon_set_state); 585 586 /** 587 * extcon_set_state_sync() - Set the state of an external connector with sync. 588 * @edev: the extcon device 589 * @id: the unique id indicating an external connector 590 * @state: the new state of external connector. 591 * the default semantics is true: attached / false: detached. 592 * 593 * Note that this function set the state of external connector 594 * and synchronize the state by sending a notification. 595 * 596 * Returns 0 if success or error number if fail. 597 */ 598 int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, bool state) 599 { 600 int ret; 601 602 ret = extcon_set_state(edev, id, state); 603 if (ret < 0) 604 return ret; 605 606 return extcon_sync(edev, id); 607 } 608 EXPORT_SYMBOL_GPL(extcon_set_state_sync); 609 610 /** 611 * extcon_get_property() - Get the property value of an external connector. 612 * @edev: the extcon device 613 * @id: the unique id indicating an external connector 614 * @prop: the property id indicating an extcon property 615 * @prop_val: the pointer which store the value of extcon property 616 * 617 * Note that when getting the property value of external connector, 618 * the external connector should be attached. If detached state, function 619 * return 0 without property value. Also, the each property should be 620 * included in the list of supported properties according to extcon type. 621 * 622 * Returns 0 if success or error number if fail. 623 */ 624 int extcon_get_property(struct extcon_dev *edev, unsigned int id, 625 unsigned int prop, 626 union extcon_property_value *prop_val) 627 { 628 struct extcon_cable *cable; 629 unsigned long flags; 630 int index, ret = 0; 631 632 *prop_val = (union extcon_property_value){0}; 633 634 if (!edev) 635 return -EINVAL; 636 637 /* Check whether the property is supported or not */ 638 if (!is_extcon_property_supported(id, prop)) 639 return -EINVAL; 640 641 /* Find the cable index of external connector by using id */ 642 index = find_cable_index_by_id(edev, id); 643 if (index < 0) 644 return index; 645 646 spin_lock_irqsave(&edev->lock, flags); 647 648 /* Check whether the property is available or not. */ 649 if (!is_extcon_property_capability(edev, id, index, prop)) { 650 spin_unlock_irqrestore(&edev->lock, flags); 651 return -EPERM; 652 } 653 654 /* 655 * Check whether the external connector is attached. 656 * If external connector is detached, the user can not 657 * get the property value. 658 */ 659 if (!is_extcon_attached(edev, index)) { 660 spin_unlock_irqrestore(&edev->lock, flags); 661 return 0; 662 } 663 664 cable = &edev->cables[index]; 665 666 /* Get the property value according to extcon type */ 667 switch (prop) { 668 case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX: 669 *prop_val = cable->usb_propval[prop - EXTCON_PROP_USB_MIN]; 670 break; 671 case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX: 672 *prop_val = cable->chg_propval[prop - EXTCON_PROP_CHG_MIN]; 673 break; 674 case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX: 675 *prop_val = cable->jack_propval[prop - EXTCON_PROP_JACK_MIN]; 676 break; 677 case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX: 678 *prop_val = cable->disp_propval[prop - EXTCON_PROP_DISP_MIN]; 679 break; 680 default: 681 ret = -EINVAL; 682 break; 683 } 684 685 spin_unlock_irqrestore(&edev->lock, flags); 686 687 return ret; 688 } 689 EXPORT_SYMBOL_GPL(extcon_get_property); 690 691 /** 692 * extcon_set_property() - Set the property value of an external connector. 693 * @edev: the extcon device 694 * @id: the unique id indicating an external connector 695 * @prop: the property id indicating an extcon property 696 * @prop_val: the pointer including the new value of extcon property 697 * 698 * Note that each property should be included in the list of supported 699 * properties according to the extcon type. 700 * 701 * Returns 0 if success or error number if fail. 702 */ 703 int extcon_set_property(struct extcon_dev *edev, unsigned int id, 704 unsigned int prop, 705 union extcon_property_value prop_val) 706 { 707 struct extcon_cable *cable; 708 unsigned long flags; 709 int index, ret = 0; 710 711 if (!edev) 712 return -EINVAL; 713 714 /* Check whether the property is supported or not */ 715 if (!is_extcon_property_supported(id, prop)) 716 return -EINVAL; 717 718 /* Find the cable index of external connector by using id */ 719 index = find_cable_index_by_id(edev, id); 720 if (index < 0) 721 return index; 722 723 spin_lock_irqsave(&edev->lock, flags); 724 725 /* Check whether the property is available or not. */ 726 if (!is_extcon_property_capability(edev, id, index, prop)) { 727 spin_unlock_irqrestore(&edev->lock, flags); 728 return -EPERM; 729 } 730 731 cable = &edev->cables[index]; 732 733 /* Set the property value according to extcon type */ 734 switch (prop) { 735 case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX: 736 cable->usb_propval[prop - EXTCON_PROP_USB_MIN] = prop_val; 737 break; 738 case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX: 739 cable->chg_propval[prop - EXTCON_PROP_CHG_MIN] = prop_val; 740 break; 741 case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX: 742 cable->jack_propval[prop - EXTCON_PROP_JACK_MIN] = prop_val; 743 break; 744 case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX: 745 cable->disp_propval[prop - EXTCON_PROP_DISP_MIN] = prop_val; 746 break; 747 default: 748 ret = -EINVAL; 749 break; 750 } 751 752 spin_unlock_irqrestore(&edev->lock, flags); 753 754 return ret; 755 } 756 EXPORT_SYMBOL_GPL(extcon_set_property); 757 758 /** 759 * extcon_set_property_sync() - Set property of an external connector with sync. 760 * @edev: the extcon device 761 * @id: the unique id indicating an external connector 762 * @prop: the property id indicating an extcon property 763 * @prop_val: the pointer including the new value of extcon property 764 * 765 * Note that when setting the property value of external connector, 766 * the external connector should be attached. The each property should 767 * be included in the list of supported properties according to extcon type. 768 * 769 * Returns 0 if success or error number if fail. 770 */ 771 int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, 772 unsigned int prop, 773 union extcon_property_value prop_val) 774 { 775 int ret; 776 777 ret = extcon_set_property(edev, id, prop, prop_val); 778 if (ret < 0) 779 return ret; 780 781 return extcon_sync(edev, id); 782 } 783 EXPORT_SYMBOL_GPL(extcon_set_property_sync); 784 785 /** 786 * extcon_get_property_capability() - Get the capability of the property 787 * for an external connector. 788 * @edev: the extcon device 789 * @id: the unique id indicating an external connector 790 * @prop: the property id indicating an extcon property 791 * 792 * Returns 1 if the property is available or 0 if not available. 793 */ 794 int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id, 795 unsigned int prop) 796 { 797 int index; 798 799 if (!edev) 800 return -EINVAL; 801 802 /* Check whether the property is supported or not */ 803 if (!is_extcon_property_supported(id, prop)) 804 return -EINVAL; 805 806 /* Find the cable index of external connector by using id */ 807 index = find_cable_index_by_id(edev, id); 808 if (index < 0) 809 return index; 810 811 return is_extcon_property_capability(edev, id, index, prop); 812 } 813 EXPORT_SYMBOL_GPL(extcon_get_property_capability); 814 815 /** 816 * extcon_set_property_capability() - Set the capability of the property 817 * for an external connector. 818 * @edev: the extcon device 819 * @id: the unique id indicating an external connector 820 * @prop: the property id indicating an extcon property 821 * 822 * Note that this function set the capability of the property 823 * for an external connector in order to mark the bit in capability 824 * bitmap which mean the available state of the property. 825 * 826 * Returns 0 if success or error number if fail. 827 */ 828 int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id, 829 unsigned int prop) 830 { 831 struct extcon_cable *cable; 832 int index, type, ret = 0; 833 834 if (!edev) 835 return -EINVAL; 836 837 /* Check whether the property is supported or not. */ 838 if (!is_extcon_property_supported(id, prop)) 839 return -EINVAL; 840 841 /* Find the cable index of external connector by using id. */ 842 index = find_cable_index_by_id(edev, id); 843 if (index < 0) 844 return index; 845 846 type = get_extcon_type(prop); 847 if (type < 0) 848 return type; 849 850 cable = &edev->cables[index]; 851 852 switch (type) { 853 case EXTCON_TYPE_USB: 854 __set_bit(prop - EXTCON_PROP_USB_MIN, cable->usb_bits); 855 break; 856 case EXTCON_TYPE_CHG: 857 __set_bit(prop - EXTCON_PROP_CHG_MIN, cable->chg_bits); 858 break; 859 case EXTCON_TYPE_JACK: 860 __set_bit(prop - EXTCON_PROP_JACK_MIN, cable->jack_bits); 861 break; 862 case EXTCON_TYPE_DISP: 863 __set_bit(prop - EXTCON_PROP_DISP_MIN, cable->disp_bits); 864 break; 865 default: 866 ret = -EINVAL; 867 } 868 869 return ret; 870 } 871 EXPORT_SYMBOL_GPL(extcon_set_property_capability); 872 873 /** 874 * extcon_get_extcon_dev() - Get the extcon device instance from the name. 875 * @extcon_name: the extcon name provided with extcon_dev_register() 876 * 877 * Return the pointer of extcon device if success or ERR_PTR(err) if fail. 878 * NOTE: This function returns -EPROBE_DEFER so it may only be called from 879 * probe() functions. 880 */ 881 struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) 882 { 883 struct extcon_dev *sd; 884 885 if (!extcon_name) 886 return ERR_PTR(-EINVAL); 887 888 mutex_lock(&extcon_dev_list_lock); 889 list_for_each_entry(sd, &extcon_dev_list, entry) { 890 if (!strcmp(sd->name, extcon_name)) 891 goto out; 892 } 893 sd = ERR_PTR(-EPROBE_DEFER); 894 out: 895 mutex_unlock(&extcon_dev_list_lock); 896 return sd; 897 } 898 EXPORT_SYMBOL_GPL(extcon_get_extcon_dev); 899 900 /** 901 * extcon_register_notifier() - Register a notifier block to get notified by 902 * any state changes from the extcon. 903 * @edev: the extcon device 904 * @id: the unique id indicating an external connector 905 * @nb: a notifier block to be registered 906 * 907 * Note that the second parameter given to the callback of nb (val) is 908 * the current state of an external connector and the third pameter 909 * is the pointer of extcon device. 910 * 911 * Returns 0 if success or error number if fail. 912 */ 913 int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, 914 struct notifier_block *nb) 915 { 916 unsigned long flags; 917 int ret, idx; 918 919 if (!edev || !nb) 920 return -EINVAL; 921 922 idx = find_cable_index_by_id(edev, id); 923 if (idx < 0) 924 return idx; 925 926 spin_lock_irqsave(&edev->lock, flags); 927 ret = raw_notifier_chain_register(&edev->nh[idx], nb); 928 spin_unlock_irqrestore(&edev->lock, flags); 929 930 return ret; 931 } 932 EXPORT_SYMBOL_GPL(extcon_register_notifier); 933 934 /** 935 * extcon_unregister_notifier() - Unregister a notifier block from the extcon. 936 * @edev: the extcon device 937 * @id: the unique id indicating an external connector 938 * @nb: a notifier block to be registered 939 * 940 * Returns 0 if success or error number if fail. 941 */ 942 int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, 943 struct notifier_block *nb) 944 { 945 unsigned long flags; 946 int ret, idx; 947 948 if (!edev || !nb) 949 return -EINVAL; 950 951 idx = find_cable_index_by_id(edev, id); 952 if (idx < 0) 953 return idx; 954 955 spin_lock_irqsave(&edev->lock, flags); 956 ret = raw_notifier_chain_unregister(&edev->nh[idx], nb); 957 spin_unlock_irqrestore(&edev->lock, flags); 958 959 return ret; 960 } 961 EXPORT_SYMBOL_GPL(extcon_unregister_notifier); 962 963 /** 964 * extcon_register_notifier_all() - Register a notifier block for all connectors. 965 * @edev: the extcon device 966 * @nb: a notifier block to be registered 967 * 968 * Note that this function registers a notifier block in order to receive 969 * the state change of all supported external connectors from extcon device. 970 * And the second parameter given to the callback of nb (val) is 971 * the current state and the third pameter is the pointer of extcon device. 972 * 973 * Returns 0 if success or error number if fail. 974 */ 975 int extcon_register_notifier_all(struct extcon_dev *edev, 976 struct notifier_block *nb) 977 { 978 unsigned long flags; 979 int ret; 980 981 if (!edev || !nb) 982 return -EINVAL; 983 984 spin_lock_irqsave(&edev->lock, flags); 985 ret = raw_notifier_chain_register(&edev->nh_all, nb); 986 spin_unlock_irqrestore(&edev->lock, flags); 987 988 return ret; 989 } 990 EXPORT_SYMBOL_GPL(extcon_register_notifier_all); 991 992 /** 993 * extcon_unregister_notifier_all() - Unregister a notifier block from extcon. 994 * @edev: the extcon device 995 * @nb: a notifier block to be registered 996 * 997 * Returns 0 if success or error number if fail. 998 */ 999 int extcon_unregister_notifier_all(struct extcon_dev *edev, 1000 struct notifier_block *nb) 1001 { 1002 unsigned long flags; 1003 int ret; 1004 1005 if (!edev || !nb) 1006 return -EINVAL; 1007 1008 spin_lock_irqsave(&edev->lock, flags); 1009 ret = raw_notifier_chain_unregister(&edev->nh_all, nb); 1010 spin_unlock_irqrestore(&edev->lock, flags); 1011 1012 return ret; 1013 } 1014 EXPORT_SYMBOL_GPL(extcon_unregister_notifier_all); 1015 1016 static struct attribute *extcon_attrs[] = { 1017 &dev_attr_state.attr, 1018 &dev_attr_name.attr, 1019 NULL, 1020 }; 1021 ATTRIBUTE_GROUPS(extcon); 1022 1023 static int create_extcon_class(void) 1024 { 1025 if (extcon_class) 1026 return 0; 1027 1028 extcon_class = class_create("extcon"); 1029 if (IS_ERR(extcon_class)) 1030 return PTR_ERR(extcon_class); 1031 extcon_class->dev_groups = extcon_groups; 1032 1033 return 0; 1034 } 1035 1036 static void extcon_dev_release(struct device *dev) 1037 { 1038 } 1039 1040 static const char *muex_name = "mutually_exclusive"; 1041 static void dummy_sysfs_dev_release(struct device *dev) 1042 { 1043 } 1044 1045 /* 1046 * extcon_dev_allocate() - Allocate the memory of extcon device. 1047 * @supported_cable: the array of the supported external connectors 1048 * ending with EXTCON_NONE. 1049 * 1050 * Note that this function allocates the memory for extcon device 1051 * and initialize default setting for the extcon device. 1052 * 1053 * Returns the pointer memory of allocated extcon_dev if success 1054 * or ERR_PTR(err) if fail. 1055 */ 1056 struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable) 1057 { 1058 struct extcon_dev *edev; 1059 1060 if (!supported_cable) 1061 return ERR_PTR(-EINVAL); 1062 1063 edev = kzalloc_obj(*edev); 1064 if (!edev) 1065 return ERR_PTR(-ENOMEM); 1066 1067 edev->max_supported = 0; 1068 edev->supported_cable = supported_cable; 1069 1070 return edev; 1071 } 1072 1073 /* 1074 * extcon_dev_free() - Free the memory of extcon device. 1075 * @edev: the extcon device 1076 */ 1077 void extcon_dev_free(struct extcon_dev *edev) 1078 { 1079 kfree(edev); 1080 } 1081 EXPORT_SYMBOL_GPL(extcon_dev_free); 1082 1083 /** 1084 * extcon_alloc_cables() - alloc the cables for extcon device 1085 * @edev: extcon device which has cables 1086 * 1087 * Returns 0 if success or error number if fail. 1088 */ 1089 static int extcon_alloc_cables(struct extcon_dev *edev) 1090 { 1091 int index; 1092 char *str; 1093 struct extcon_cable *cable; 1094 1095 if (!edev) 1096 return -EINVAL; 1097 1098 if (!edev->max_supported) 1099 return 0; 1100 1101 edev->cables = kzalloc_objs(*edev->cables, edev->max_supported); 1102 if (!edev->cables) 1103 return -ENOMEM; 1104 1105 for (index = 0; index < edev->max_supported; index++) { 1106 cable = &edev->cables[index]; 1107 1108 str = kasprintf(GFP_KERNEL, "cable.%d", index); 1109 if (!str) { 1110 for (index--; index >= 0; index--) { 1111 cable = &edev->cables[index]; 1112 kfree(cable->attr_g.name); 1113 } 1114 1115 kfree(edev->cables); 1116 return -ENOMEM; 1117 } 1118 1119 cable->edev = edev; 1120 cable->cable_index = index; 1121 cable->attrs[0] = &cable->attr_name.attr; 1122 cable->attrs[1] = &cable->attr_state.attr; 1123 cable->attrs[2] = NULL; 1124 cable->attr_g.name = str; 1125 cable->attr_g.attrs = cable->attrs; 1126 1127 sysfs_attr_init(&cable->attr_name.attr); 1128 cable->attr_name.attr.name = "name"; 1129 cable->attr_name.attr.mode = 0444; 1130 cable->attr_name.show = cable_name_show; 1131 1132 sysfs_attr_init(&cable->attr_state.attr); 1133 cable->attr_state.attr.name = "state"; 1134 cable->attr_state.attr.mode = 0444; 1135 cable->attr_state.show = cable_state_show; 1136 } 1137 1138 return 0; 1139 } 1140 1141 /** 1142 * extcon_alloc_muex() - alloc the mutual exclusive for extcon device 1143 * @edev: extcon device 1144 * 1145 * Returns 0 if success or error number if fail. 1146 */ 1147 static int extcon_alloc_muex(struct extcon_dev *edev) 1148 { 1149 char *name; 1150 int index; 1151 1152 if (!edev) 1153 return -EINVAL; 1154 1155 if (!(edev->max_supported && edev->mutually_exclusive)) 1156 return 0; 1157 1158 /* Count the size of mutually_exclusive array */ 1159 for (index = 0; edev->mutually_exclusive[index]; index++) 1160 ; 1161 1162 edev->attrs_muex = kzalloc_objs(*edev->attrs_muex, index + 1); 1163 if (!edev->attrs_muex) 1164 return -ENOMEM; 1165 1166 edev->d_attrs_muex = kzalloc_objs(*edev->d_attrs_muex, index); 1167 if (!edev->d_attrs_muex) { 1168 kfree(edev->attrs_muex); 1169 return -ENOMEM; 1170 } 1171 1172 for (index = 0; edev->mutually_exclusive[index]; index++) { 1173 name = kasprintf(GFP_KERNEL, "0x%x", 1174 edev->mutually_exclusive[index]); 1175 if (!name) { 1176 for (index--; index >= 0; index--) 1177 kfree(edev->d_attrs_muex[index].attr.name); 1178 1179 kfree(edev->d_attrs_muex); 1180 kfree(edev->attrs_muex); 1181 return -ENOMEM; 1182 } 1183 sysfs_attr_init(&edev->d_attrs_muex[index].attr); 1184 edev->d_attrs_muex[index].attr.name = name; 1185 edev->d_attrs_muex[index].attr.mode = 0000; 1186 edev->attrs_muex[index] = &edev->d_attrs_muex[index].attr; 1187 } 1188 edev->attr_g_muex.name = muex_name; 1189 edev->attr_g_muex.attrs = edev->attrs_muex; 1190 1191 return 0; 1192 } 1193 1194 /** 1195 * extcon_alloc_groups() - alloc the groups for extcon device 1196 * @edev: extcon device 1197 * 1198 * Returns 0 if success or error number if fail. 1199 */ 1200 static int extcon_alloc_groups(struct extcon_dev *edev) 1201 { 1202 int index; 1203 1204 if (!edev) 1205 return -EINVAL; 1206 1207 if (!edev->max_supported) 1208 return 0; 1209 1210 edev->extcon_dev_type.groups = kzalloc_objs(*edev->extcon_dev_type.groups, 1211 edev->max_supported + 2, 1212 GFP_KERNEL); 1213 if (!edev->extcon_dev_type.groups) 1214 return -ENOMEM; 1215 1216 edev->extcon_dev_type.name = dev_name(&edev->dev); 1217 edev->extcon_dev_type.release = dummy_sysfs_dev_release; 1218 1219 for (index = 0; index < edev->max_supported; index++) 1220 edev->extcon_dev_type.groups[index] = &edev->cables[index].attr_g; 1221 1222 if (edev->mutually_exclusive) 1223 edev->extcon_dev_type.groups[index] = &edev->attr_g_muex; 1224 1225 edev->dev.type = &edev->extcon_dev_type; 1226 1227 return 0; 1228 } 1229 1230 /** 1231 * extcon_dev_register() - Register an new extcon device 1232 * @edev: the extcon device to be registered 1233 * 1234 * Among the members of edev struct, please set the "user initializing data" 1235 * do not set the values of "internal data", which are initialized by 1236 * this function. 1237 * 1238 * Note that before calling this funciton, have to allocate the memory 1239 * of an extcon device by using the extcon_dev_allocate(). And the extcon 1240 * dev should include the supported_cable information. 1241 * 1242 * Returns 0 if success or error number if fail. 1243 */ 1244 int extcon_dev_register(struct extcon_dev *edev) 1245 { 1246 int ret, index; 1247 1248 ret = create_extcon_class(); 1249 if (ret < 0) 1250 return ret; 1251 1252 if (!edev || !edev->supported_cable) 1253 return -EINVAL; 1254 1255 for (index = 0; edev->supported_cable[index] != EXTCON_NONE; index++); 1256 1257 edev->max_supported = index; 1258 if (index > SUPPORTED_CABLE_MAX) { 1259 dev_err(&edev->dev, 1260 "exceed the maximum number of supported cables\n"); 1261 return -EINVAL; 1262 } 1263 1264 edev->dev.class = extcon_class; 1265 edev->dev.release = extcon_dev_release; 1266 1267 edev->name = dev_name(edev->dev.parent); 1268 if (IS_ERR_OR_NULL(edev->name)) { 1269 dev_err(&edev->dev, 1270 "extcon device name is null\n"); 1271 return -EINVAL; 1272 } 1273 1274 ret = ida_alloc(&extcon_dev_ids, GFP_KERNEL); 1275 if (ret < 0) 1276 return ret; 1277 1278 edev->id = ret; 1279 1280 ret = extcon_alloc_cables(edev); 1281 if (ret < 0) 1282 goto err_alloc_cables; 1283 1284 ret = extcon_alloc_muex(edev); 1285 if (ret < 0) 1286 goto err_alloc_muex; 1287 1288 ret = extcon_alloc_groups(edev); 1289 if (ret < 0) 1290 goto err_alloc_groups; 1291 1292 spin_lock_init(&edev->lock); 1293 if (edev->max_supported) { 1294 edev->nh = kzalloc_objs(*edev->nh, edev->max_supported); 1295 if (!edev->nh) { 1296 ret = -ENOMEM; 1297 goto err_alloc_nh; 1298 } 1299 } 1300 1301 for (index = 0; index < edev->max_supported; index++) 1302 RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]); 1303 1304 RAW_INIT_NOTIFIER_HEAD(&edev->nh_all); 1305 1306 dev_set_drvdata(&edev->dev, edev); 1307 dev_set_name(&edev->dev, "extcon%d", edev->id); 1308 edev->state = 0; 1309 1310 ret = device_register(&edev->dev); 1311 if (ret) { 1312 put_device(&edev->dev); 1313 goto err_dev; 1314 } 1315 1316 mutex_lock(&extcon_dev_list_lock); 1317 list_add(&edev->entry, &extcon_dev_list); 1318 mutex_unlock(&extcon_dev_list_lock); 1319 1320 return 0; 1321 1322 err_dev: 1323 if (edev->max_supported) 1324 kfree(edev->nh); 1325 err_alloc_nh: 1326 if (edev->max_supported) 1327 kfree(edev->extcon_dev_type.groups); 1328 err_alloc_groups: 1329 if (edev->max_supported && edev->mutually_exclusive) { 1330 for (index = 0; edev->mutually_exclusive[index]; index++) 1331 kfree(edev->d_attrs_muex[index].attr.name); 1332 kfree(edev->d_attrs_muex); 1333 kfree(edev->attrs_muex); 1334 } 1335 err_alloc_muex: 1336 for (index = 0; index < edev->max_supported; index++) 1337 kfree(edev->cables[index].attr_g.name); 1338 if (edev->max_supported) 1339 kfree(edev->cables); 1340 err_alloc_cables: 1341 ida_free(&extcon_dev_ids, edev->id); 1342 1343 return ret; 1344 } 1345 EXPORT_SYMBOL_GPL(extcon_dev_register); 1346 1347 /** 1348 * extcon_dev_unregister() - Unregister the extcon device. 1349 * @edev: the extcon device to be unregistered. 1350 * 1351 * Note that this does not call kfree(edev) because edev was not allocated 1352 * by this class. 1353 */ 1354 void extcon_dev_unregister(struct extcon_dev *edev) 1355 { 1356 int index; 1357 1358 if (!edev) 1359 return; 1360 1361 mutex_lock(&extcon_dev_list_lock); 1362 list_del(&edev->entry); 1363 mutex_unlock(&extcon_dev_list_lock); 1364 1365 if (!get_device(&edev->dev)) { 1366 dev_err(&edev->dev, "Failed to unregister extcon_dev\n"); 1367 return; 1368 } 1369 1370 ida_free(&extcon_dev_ids, edev->id); 1371 1372 device_unregister(&edev->dev); 1373 1374 if (edev->mutually_exclusive && edev->max_supported) { 1375 for (index = 0; edev->mutually_exclusive[index]; 1376 index++) 1377 kfree(edev->d_attrs_muex[index].attr.name); 1378 kfree(edev->d_attrs_muex); 1379 kfree(edev->attrs_muex); 1380 } 1381 1382 for (index = 0; index < edev->max_supported; index++) 1383 kfree(edev->cables[index].attr_g.name); 1384 1385 if (edev->max_supported) { 1386 kfree(edev->extcon_dev_type.groups); 1387 kfree(edev->cables); 1388 kfree(edev->nh); 1389 } 1390 1391 put_device(&edev->dev); 1392 } 1393 EXPORT_SYMBOL_GPL(extcon_dev_unregister); 1394 1395 #ifdef CONFIG_OF 1396 1397 /* 1398 * extcon_find_edev_by_node - Find the extcon device from devicetree. 1399 * @node : OF node identifying edev 1400 * 1401 * Return the pointer of extcon device if success or ERR_PTR(err) if fail. 1402 */ 1403 struct extcon_dev *extcon_find_edev_by_node(struct device_node *node) 1404 { 1405 struct extcon_dev *edev; 1406 1407 mutex_lock(&extcon_dev_list_lock); 1408 list_for_each_entry(edev, &extcon_dev_list, entry) 1409 if (edev->dev.parent && device_match_of_node(edev->dev.parent, node)) 1410 goto out; 1411 edev = ERR_PTR(-EPROBE_DEFER); 1412 out: 1413 mutex_unlock(&extcon_dev_list_lock); 1414 1415 return edev; 1416 } 1417 1418 /* 1419 * extcon_get_edev_by_phandle - Get the extcon device from devicetree. 1420 * @dev : the instance to the given device 1421 * @index : the index into list of extcon_dev 1422 * 1423 * Return the pointer of extcon device if success or ERR_PTR(err) if fail. 1424 */ 1425 struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) 1426 { 1427 struct device_node *node, *np = dev_of_node(dev); 1428 struct extcon_dev *edev; 1429 1430 if (!np) { 1431 dev_dbg(dev, "device does not have a device node entry\n"); 1432 return ERR_PTR(-EINVAL); 1433 } 1434 1435 node = of_parse_phandle(np, "extcon", index); 1436 if (!node) { 1437 dev_dbg(dev, "failed to get phandle in %pOF node\n", np); 1438 return ERR_PTR(-ENODEV); 1439 } 1440 1441 edev = extcon_find_edev_by_node(node); 1442 of_node_put(node); 1443 1444 return edev; 1445 } 1446 1447 #else 1448 1449 struct extcon_dev *extcon_find_edev_by_node(struct device_node *node) 1450 { 1451 return ERR_PTR(-ENOSYS); 1452 } 1453 1454 struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) 1455 { 1456 return ERR_PTR(-ENOSYS); 1457 } 1458 1459 #endif /* CONFIG_OF */ 1460 1461 EXPORT_SYMBOL_GPL(extcon_find_edev_by_node); 1462 EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle); 1463 1464 /** 1465 * extcon_get_edev_name() - Get the name of the extcon device. 1466 * @edev: the extcon device 1467 */ 1468 const char *extcon_get_edev_name(struct extcon_dev *edev) 1469 { 1470 return !edev ? NULL : edev->name; 1471 } 1472 EXPORT_SYMBOL_GPL(extcon_get_edev_name); 1473 1474 static int __init extcon_class_init(void) 1475 { 1476 return create_extcon_class(); 1477 } 1478 module_init(extcon_class_init); 1479 1480 static void __exit extcon_class_exit(void) 1481 { 1482 class_destroy(extcon_class); 1483 } 1484 module_exit(extcon_class_exit); 1485 1486 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); 1487 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 1488 MODULE_DESCRIPTION("External Connector (extcon) framework"); 1489 MODULE_LICENSE("GPL v2"); 1490