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