diff mbox

[v6,1/5] Extcon (external connector): import Android's switch class and modify.

Message ID 1330344939-18394-2-git-send-email-myungjoo.ham@samsung.com
State New
Headers show

Commit Message

MyungJoo Ham Feb. 27, 2012, 12:15 p.m. UTC
External connector class (extcon) is based on and an extension of
Android kernel's switch class located at linux/drivers/switch/.

This patch provides the before-extension switch class moved to the
location where the extcon will be located (linux/drivers/extcon/) and
updates to handle class properly.

The before-extension class, switch class of Android kernel, commits
imported are:

switch: switch class and GPIO drivers. (splitted)
Author: Mike Lockwood <lockwood@android.com>

switch: Use device_create instead of device_create_drvdata.
Author: Arve Hjønnevåg <arve@android.com>

In this patch, upon the commits of Android kernel, we have added:
- Relocated and renamed for extcon.
- Comments, module name, and author information are updated
- Code clean for successing patches
- Bugfix: enabling write access without write functions
- Class/device/sysfs create/remove handling
- Added comments about uevents
- Format changes for extcon_dev_register() to have a parent dev.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>

--
Changes from v5
- Split the patch
- Style fixes
- "Android-compatible" mode is enabled by Kconfig option.

Changes from v2
- Updated name_show
- Sysfs entries are handled by class itself.
- Updated the method to add/remove devices for the class
- Comments on uevent send
- Able to become a module
- Compatible with Android platform

Changes from RFC
- Renamed to extcon (external connector) from multistate switch
- Added a seperated directory (drivers/extcon)
- Added kerneldoc comments
- Removed unused variables from extcon_gpio.c
- Added ABI Documentation.
---
 Documentation/ABI/testing/sysfs-class-extcon |   26 +++
 drivers/Kconfig                              |    2 +
 drivers/Makefile                             |    1 +
 drivers/extcon/Kconfig                       |   28 ++++
 drivers/extcon/Makefile                      |    5 +
 drivers/extcon/extcon_class.c                |  226 ++++++++++++++++++++++++++
 include/linux/extcon.h                       |   82 ++++++++++
 7 files changed, 370 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-class-extcon
 create mode 100644 drivers/extcon/Kconfig
 create mode 100644 drivers/extcon/Makefile
 create mode 100644 drivers/extcon/extcon_class.c
 create mode 100644 include/linux/extcon.h

Comments

Mark Brown March 9, 2012, 12:41 p.m. UTC | #1
On Mon, Feb 27, 2012 at 09:15:35PM +0900, MyungJoo Ham wrote:

> +#ifdef CONFIG_ANDROID
> +		extcon_class = class_create(THIS_MODULE, "switch");
> +#else /* !CONFIG_ANDROID */
> +		extcon_class = class_create(THIS_MODULE, "extcon");
> +#endif /* CONFIG_ANDROID */

This seems somewhat sad - if ANDROID is turned on the standard ABI
vanishes.  It'd be much nicer to do this with a symlink (or with
symlinks within the android directory if the driver core doesn't support
that).  That way userspace code can be written to the new ABI and will
work on Android systems without ifdefery.
MyungJoo Ham March 12, 2012, 8:06 a.m. UTC | #2
On Fri, Mar 9, 2012 at 9:41 PM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Mon, Feb 27, 2012 at 09:15:35PM +0900, MyungJoo Ham wrote:
>
>> +#ifdef CONFIG_ANDROID
>> +             extcon_class = class_create(THIS_MODULE, "switch");
>> +#else /* !CONFIG_ANDROID */
>> +             extcon_class = class_create(THIS_MODULE, "extcon");
>> +#endif /* CONFIG_ANDROID */
>
> This seems somewhat sad - if ANDROID is turned on the standard ABI
> vanishes.  It'd be much nicer to do this with a symlink (or with
> symlinks within the android directory if the driver core doesn't support
> that).  That way userspace code can be written to the new ABI and will
> work on Android systems without ifdefery.

Yes, this was the itching part.

I'll first look into creating symlinks (either /sys/class/switch -->
/sys/class/extcon or /sys/class/switch/* --> /sys/class/extcon/*).
However, I think this symbolic links are better created selectively w/
CONFIG_ANDROID.

Thanks.


Cheers!
MyungJoo.
Erik Gilling March 29, 2012, 10:27 p.m. UTC | #3
On Fri, Mar 9, 2012 at 4:41 AM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Mon, Feb 27, 2012 at 09:15:35PM +0900, MyungJoo Ham wrote:
>
>> +#ifdef CONFIG_ANDROID
>> +             extcon_class = class_create(THIS_MODULE, "switch");
>> +#else /* !CONFIG_ANDROID */
>> +             extcon_class = class_create(THIS_MODULE, "extcon");
>> +#endif /* CONFIG_ANDROID */
>
> This seems somewhat sad - if ANDROID is turned on the standard ABI
> vanishes.  It'd be much nicer to do this with a symlink (or with
> symlinks within the android directory if the driver core doesn't support
> that).  That way userspace code can be written to the new ABI and will
> work on Android systems without ifdefery.

This won't work if userspace code is receiving uevents through netlink
and comparing based on the device name which it does in android.  Why
change the name at all?  Extcon is much more specific than "switch."
A switch can can be used for more than just external connections such
as availability of HMDI audio (which is only available once a HDMI
mode is chosen and the interface is enabled.)

-Erik
MyungJoo Ham March 30, 2012, 8:56 a.m. UTC | #4
On Fri, Mar 30, 2012 at 7:27 AM, Erik Gilling <konkers@google.com> wrote:
> On Fri, Mar 9, 2012 at 4:41 AM, Mark Brown
> <broonie@opensource.wolfsonmicro.com> wrote:
>> On Mon, Feb 27, 2012 at 09:15:35PM +0900, MyungJoo Ham wrote:
>>
>>> +#ifdef CONFIG_ANDROID
>>> +             extcon_class = class_create(THIS_MODULE, "switch");
>>> +#else /* !CONFIG_ANDROID */
>>> +             extcon_class = class_create(THIS_MODULE, "extcon");
>>> +#endif /* CONFIG_ANDROID */
>>
>> This seems somewhat sad - if ANDROID is turned on the standard ABI
>> vanishes.  It'd be much nicer to do this with a symlink (or with
>> symlinks within the android directory if the driver core doesn't support
>> that).  That way userspace code can be written to the new ABI and will
>> work on Android systems without ifdefery.
>
> This won't work if userspace code is receiving uevents through netlink
> and comparing based on the device name which it does in android.  Why
> change the name at all?  Extcon is much more specific than "switch."
> A switch can can be used for more than just external connections such
> as availability of HMDI audio (which is only available once a HDMI
> mode is chosen and the interface is enabled.)
>
> -Erik

With class_compat as in patchset v7, (this thread is w/ v6) does the
issue (missing link from device name directory) still exist? (I don't
think so)

In the earlier iteration of dicussion, the name "switch" was dropped
as "switch" may mislead the concept.
https://lkml.org/lkml/2011/11/29/299

For HDMI and HDMI-audio, although HDMI-audio is not physically
seperated from HDMI-cable and it is available after HDMI-cable is
"attached", HDMI-audio is still an external connection to the kernel
and its device drivers, isn' it?

Cheers!
MyungJoo.
Mark Brown March 30, 2012, 10:07 a.m. UTC | #5
On Thu, Mar 29, 2012 at 03:27:01PM -0700, Erik Gilling wrote:
> On Fri, Mar 9, 2012 at 4:41 AM, Mark Brown
> <broonie@opensource.wolfsonmicro.com> wrote:
> > On Mon, Feb 27, 2012 at 09:15:35PM +0900, MyungJoo Ham wrote:

> >> +#ifdef CONFIG_ANDROID
> >> +             extcon_class = class_create(THIS_MODULE, "switch");
> >> +#else /* !CONFIG_ANDROID */
> >> +             extcon_class = class_create(THIS_MODULE, "extcon");
> >> +#endif /* CONFIG_ANDROID */

> > This seems somewhat sad - if ANDROID is turned on the standard ABI
> > vanishes.  It'd be much nicer to do this with a symlink (or with
> > symlinks within the android directory if the driver core doesn't support
> > that).  That way userspace code can be written to the new ABI and will
> > work on Android systems without ifdefery.

> This won't work if userspace code is receiving uevents through netlink
> and comparing based on the device name which it does in android.  Why

That's not really the point here - the point is that the new ABI
vanishes as soon as you turn on the legacy Android ABI.  You're right
that the particular fix I suggested has issues but the overall problem
exists and should be dealt with more sensibly.

> change the name at all?  Extcon is much more specific than "switch."
> A switch can can be used for more than just external connections such
> as availability of HMDI audio (which is only available once a HDMI
> mode is chosen and the interface is enabled.)

I don't know myself, it was called extcon when first proposed for
mainline.  Renaming does have the advantage of indicating to userspace
that this is the mainline, reviewed version and that things might be a
bit different as a result of that review.

Things like the HDMI audio example you cite do seem close enough to the
term to still be useful, they're related to an external connection and
it's state.  If you were really worrying about it you might expect HDMI
audio to be reported via something like the ALSA APIs rather than a
totally unrelated ABI like this.
Mark Brown March 30, 2012, 10:14 a.m. UTC | #6
On Fri, Mar 30, 2012 at 05:56:01PM +0900, MyungJoo Ham wrote:

> With class_compat as in patchset v7, (this thread is w/ v6) does the
> issue (missing link from device name directory) still exist? (I don't
> think so)

Not unless the uevents are issued with both names.
Erik Gilling March 30, 2012, 5:29 p.m. UTC | #7
On Fri, Mar 30, 2012 at 3:07 AM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Thu, Mar 29, 2012 at 03:27:01PM -0700, Erik Gilling wrote:
>> On Fri, Mar 9, 2012 at 4:41 AM, Mark Brown
>
>> > This seems somewhat sad - if ANDROID is turned on the standard ABI
>> > vanishes.  It'd be much nicer to do this with a symlink (or with
>> > symlinks within the android directory if the driver core doesn't support
>> > that).  That way userspace code can be written to the new ABI and will
>> > work on Android systems without ifdefery.
>
>> This won't work if userspace code is receiving uevents through netlink
>> and comparing based on the device name which it does in android.  Why
>
> That's not really the point here - the point is that the new ABI
> vanishes as soon as you turn on the legacy Android ABI.  You're right
> that the particular fix I suggested has issues but the overall problem
> exists and should be dealt with more sensibly.

I'm also not in favor of having functionality conditionally compiled
based on CONFIG_ANDROID.  If fact, going through the patch stack
there's much more that changes the ABI from the switch driver than
just the name.  Android asumes that there is a single "switch" for
each logical entity (called cable types in extcon) each with a binary
state (0,1).  Here things have changed to have a single extcon
instance that can have a bitmask of states which are sent as strings
in the uevent.

As it stands, this patch does not solve the cases where we use switch
today and we'll probably continue to carry the switch driver in the
common android tree.  If, instead, we got rid of the idea of multiple
states and mutual exclusivity and relied on the driver that uses
extcon to have multiple instances for each logical entity and deal
with mutual exclusion itself, we'd have a driver that would be pretty
easy to support in android.

-Erik
Dima Zavin March 30, 2012, 5:38 p.m. UTC | #8
On Fri, Mar 30, 2012 at 10:29 AM, Erik Gilling <konkers@google.com> wrote:
> On Fri, Mar 30, 2012 at 3:07 AM, Mark Brown
> <broonie@opensource.wolfsonmicro.com> wrote:
>> On Thu, Mar 29, 2012 at 03:27:01PM -0700, Erik Gilling wrote:
>>> On Fri, Mar 9, 2012 at 4:41 AM, Mark Brown
>>
>>> > This seems somewhat sad - if ANDROID is turned on the standard ABI
>>> > vanishes.  It'd be much nicer to do this with a symlink (or with
>>> > symlinks within the android directory if the driver core doesn't support
>>> > that).  That way userspace code can be written to the new ABI and will
>>> > work on Android systems without ifdefery.
>>
>>> This won't work if userspace code is receiving uevents through netlink
>>> and comparing based on the device name which it does in android.  Why
>>
>> That's not really the point here - the point is that the new ABI
>> vanishes as soon as you turn on the legacy Android ABI.  You're right
>> that the particular fix I suggested has issues but the overall problem
>> exists and should be dealt with more sensibly.
>
> I'm also not in favor of having functionality conditionally compiled
> based on CONFIG_ANDROID.  If fact, going through the patch stack
> there's much more that changes the ABI from the switch driver than
> just the name.  Android asumes that there is a single "switch" for
> each logical entity (called cable types in extcon) each with a binary
> state (0,1).  Here things have changed to have a single extcon
> instance that can have a bitmask of states which are sent as strings
> in the uevent.

In addition to all this added complexity, the fact that you now have
to white-list the possible "cable types" is also undesirable. If I
wanted to expose a new cable type, I now have to modify the extcon.h
file and the extcon.c file and I don't see what that white-list buys
me. The class device itself should not care for which cable types can
be registered, nor how they relate to each other. Let the client
drivers decide, just enforce uniqueness.

--Dima

>
> As it stands, this patch does not solve the cases where we use switch
> today and we'll probably continue to carry the switch driver in the
> common android tree.  If, instead, we got rid of the idea of multiple
> states and mutual exclusivity and relied on the driver that uses
> extcon to have multiple instances for each logical entity and deal
> with mutual exclusion itself, we'd have a driver that would be pretty
> easy to support in android.
>
> -Erik
Mark Brown March 31, 2012, 10:19 a.m. UTC | #9
On Fri, Mar 30, 2012 at 10:29:27AM -0700, Erik Gilling wrote:

> I'm also not in favor of having functionality conditionally compiled
> based on CONFIG_ANDROID.  If fact, going through the patch stack
> there's much more that changes the ABI from the switch driver than
> just the name.  Android asumes that there is a single "switch" for
> each logical entity (called cable types in extcon) each with a binary
> state (0,1).  Here things have changed to have a single extcon
> instance that can have a bitmask of states which are sent as strings
> in the uevent.

The binary status thing isn't true for the original Android switch API,
at least not in all cases - for headsets it's a tristate indicating if
there's nothing, a headphone or headset plugged in.  This does wind up
being a bitmask because the numbers are 0, 1 and 2 but it isn't really
clear to me if this is intentional or just an effect of counting.

> As it stands, this patch does not solve the cases where we use switch
> today and we'll probably continue to carry the switch driver in the
> common android tree.  If, instead, we got rid of the idea of multiple
> states and mutual exclusivity and relied on the driver that uses
> extcon to have multiple instances for each logical entity and deal
> with mutual exclusion itself, we'd have a driver that would be pretty
> easy to support in android.

What's the advantage in not having information about mutual exclusion in
the core, and why would a userspace that isn't interested in this care?  
It seems like this could be used by userspace to do interesting things,
and I rather suspect you'll find some vendors have added features along
those lines in their Android devices.  For example, having different
configurations for desk docks and car docks even if both end up
connecting the same things up.

Even if the userspace ABI doesn't expose the information it seems
sensible to factor out the code for handling this into the core so
there's less work to do in individual drivers.
MyungJoo Ham April 2, 2012, 5:09 a.m. UTC | #10
On Sat, Mar 31, 2012 at 2:38 AM, Dima Zavin <dima@android.com> wrote:
> On Fri, Mar 30, 2012 at 10:29 AM, Erik Gilling <konkers@google.com> wrote:
>> On Fri, Mar 30, 2012 at 3:07 AM, Mark Brown
>> <broonie@opensource.wolfsonmicro.com> wrote:
>>> On Thu, Mar 29, 2012 at 03:27:01PM -0700, Erik Gilling wrote:
>>>> On Fri, Mar 9, 2012 at 4:41 AM, Mark Brown
>>>
>>>> > This seems somewhat sad - if ANDROID is turned on the standard ABI
>>>> > vanishes.  It'd be much nicer to do this with a symlink (or with
>>>> > symlinks within the android directory if the driver core doesn't support
>>>> > that).  That way userspace code can be written to the new ABI and will
>>>> > work on Android systems without ifdefery.
>>>
>>>> This won't work if userspace code is receiving uevents through netlink
>>>> and comparing based on the device name which it does in android.  Why
>>>
>>> That's not really the point here - the point is that the new ABI
>>> vanishes as soon as you turn on the legacy Android ABI.  You're right
>>> that the particular fix I suggested has issues but the overall problem
>>> exists and should be dealt with more sensibly.
>>
>> I'm also not in favor of having functionality conditionally compiled
>> based on CONFIG_ANDROID.  If fact, going through the patch stack
>> there's much more that changes the ABI from the switch driver than
>> just the name.  Android asumes that there is a single "switch" for
>> each logical entity (called cable types in extcon) each with a binary
>> state (0,1).  Here things have changed to have a single extcon
>> instance that can have a bitmask of states which are sent as strings
>> in the uevent.
>
> In addition to all this added complexity, the fact that you now have
> to white-list the possible "cable types" is also undesirable. If I
> wanted to expose a new cable type, I now have to modify the extcon.h
> file and the extcon.c file and I don't see what that white-list buys
> me. The class device itself should not care for which cable types can
> be registered, nor how they relate to each other. Let the client
> drivers decide, just enforce uniqueness.
>
> --Dima


They are not a white-list that shows the possible cable types.

It is a suggestion so that different device drivers may use the same
cable names for common cable types.

Any device drivers can still use their own "new" names without any
modifications to extcon_class.c./extcon.h. Especially as long as they
are "new", "rare", or "uncommon" cable types, the device drivers
should be able to use their own created names.



Cheers!
MyungJoo.

>
>>
>> As it stands, this patch does not solve the cases where we use switch
>> today and we'll probably continue to carry the switch driver in the
>> common android tree.  If, instead, we got rid of the idea of multiple
>> states and mutual exclusivity and relied on the driver that uses
>> extcon to have multiple instances for each logical entity and deal
>> with mutual exclusion itself, we'd have a driver that would be pretty
>> easy to support in android.
>>
>> -Erik
diff mbox

Patch

diff --git a/Documentation/ABI/testing/sysfs-class-extcon b/Documentation/ABI/testing/sysfs-class-extcon
new file mode 100644
index 0000000..59a4b1c
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-extcon
@@ -0,0 +1,26 @@ 
+What:		/sys/class/extcon/.../
+Date:		December 2011
+Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+		Provide a place in sysfs for the extcon objects.
+		This allows accessing extcon specific variables.
+		The name of extcon object denoted as ... is the name given
+		with extcon_dev_register.
+
+What:		/sys/class/extcon/.../name
+Date:		December 2011
+Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+		The /sys/class/extcon/.../name shows the name of the extcon
+		object. If the extcon object has an optional callback
+		"show_name" defined, the callback will provide the name with
+		this sysfs node.
+
+What:		/sys/class/extcon/.../state
+Date:		December 2011
+Contact:	MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+		The /sys/class/extcon/.../state shows the cable attach/detach
+		information of the corresponding extcon object. If the extcon
+		objecct has an optional callback "show_state" defined, the
+		callback will provide the name with this sysfs node.
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 5afe5d1..537d126 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -136,4 +136,6 @@  source "drivers/virt/Kconfig"
 
 source "drivers/devfreq/Kconfig"
 
+source "drivers/extcon/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index c07be02..6faceab 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -132,3 +132,4 @@  obj-$(CONFIG_VIRT_DRIVERS)	+= virt/
 obj-$(CONFIG_HYPERV)		+= hv/
 
 obj-$(CONFIG_PM_DEVFREQ)	+= devfreq/
+obj-$(CONFIG_EXTCON)		+= extcon/
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
new file mode 100644
index 0000000..11db865
--- /dev/null
+++ b/drivers/extcon/Kconfig
@@ -0,0 +1,28 @@ 
+menuconfig EXTCON
+	tristate "External Connector Class (extcon) support"
+	help
+	  Say Y here to enable external connector class (extcon) support.
+	  This allows monitoring external connectors by userspace
+	  via sysfs and uevent and supports external connectors with
+	  multiple states; i.e., an extcon that may have multiple
+	  cables attached. For example, an external connector of a device
+	  may be used to connect an HDMI cable and a AC adaptor, and to
+	  host USB ports. Many of 30-pin connectors including PDMI are
+	  also good examples.
+
+if EXTCON
+
+comment "Extcon Class Configuration"
+
+config EXTCON_ANDROID_COMPATIBLE
+	bool "Class name uses 'switch' to be compatible with Android kernel"
+	depends on ANDROID
+	help
+	  The class name of extcon device drivers are set 'switch' in order
+	  to be compatible with Android kernel switch framework. With this
+	  option enabled, Android userspace platform may use extcon device
+	  drivers as if they are switch device drivers.
+
+comment "Extcon Device Drivers"
+
+endif # MULTISTATE_SWITCH
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
new file mode 100644
index 0000000..6bc6921
--- /dev/null
+++ b/drivers/extcon/Makefile
@@ -0,0 +1,5 @@ 
+#
+# Makefile for external connector class (extcon) devices
+#
+
+obj-$(CONFIG_EXTCON)		+= extcon_class.o
diff --git a/drivers/extcon/extcon_class.c b/drivers/extcon/extcon_class.c
new file mode 100644
index 0000000..9bc062b
--- /dev/null
+++ b/drivers/extcon/extcon_class.c
@@ -0,0 +1,226 @@ 
+/*
+ *  drivers/extcon/extcon_class.c
+ *
+ *  External connector (extcon) class driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Donggeun Kim <dg77.kim@samsung.com>
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * based on android/drivers/switch/switch_class.c
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/slab.h>
+
+struct class *extcon_class;
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	if (edev->print_state) {
+		int ret = edev->print_state(edev, buf);
+
+		if (ret >= 0)
+			return ret;
+		/* Use default if failed */
+	}
+	return sprintf(buf, "%u\n", edev->state);
+}
+
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	/* Optional callback given by the user */
+	if (edev->print_name) {
+		int ret = edev->print_name(edev, buf);
+		if (ret >= 0)
+			return ret;
+	}
+
+	return sprintf(buf, "%s\n", dev_name(edev->dev));
+}
+
+/**
+ * extcon_set_state() - Set the cable attach states of the extcon device.
+ * @edev:	the extcon device
+ * @state:	new cable attach status for @edev
+ *
+ * Changing the state sends uevent with environment variable containing
+ * the name of extcon device (envp[0]) and the state output (envp[1]).
+ * Tizen uses this format for extcon device to get events from ports.
+ * Android uses this format as well.
+ */
+void extcon_set_state(struct extcon_dev *edev, u32 state)
+{
+	char name_buf[120];
+	char state_buf[120];
+	char *prop_buf;
+	char *envp[3];
+	int env_offset = 0;
+	int length;
+
+	if (edev->state != state) {
+		edev->state = state;
+
+		prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
+		if (prop_buf) {
+			length = name_show(edev->dev, NULL, prop_buf);
+			if (length > 0) {
+				if (prop_buf[length - 1] == '\n')
+					prop_buf[length - 1] = 0;
+				snprintf(name_buf, sizeof(name_buf),
+					"SWITCH_NAME=%s", prop_buf);
+				envp[env_offset++] = name_buf;
+			}
+			length = state_show(edev->dev, NULL, prop_buf);
+			if (length > 0) {
+				if (prop_buf[length - 1] == '\n')
+					prop_buf[length - 1] = 0;
+				snprintf(state_buf, sizeof(state_buf),
+					"SWITCH_STATE=%s", prop_buf);
+				envp[env_offset++] = state_buf;
+			}
+			envp[env_offset] = NULL;
+			kobject_uevent_env(&edev->dev->kobj, KOBJ_CHANGE, envp);
+			free_page((unsigned long)prop_buf);
+		} else {
+			dev_err(edev->dev, "out of memory in extcon_set_state\n");
+			kobject_uevent(&edev->dev->kobj, KOBJ_CHANGE);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(extcon_set_state);
+
+static struct device_attribute extcon_attrs[] = {
+	__ATTR_RO(state),
+	__ATTR_RO(name),
+};
+
+static int create_extcon_class(void)
+{
+	if (!extcon_class) {
+#ifdef CONFIG_ANDROID
+		extcon_class = class_create(THIS_MODULE, "switch");
+#else /* !CONFIG_ANDROID */
+		extcon_class = class_create(THIS_MODULE, "extcon");
+#endif /* CONFIG_ANDROID */
+		if (IS_ERR(extcon_class))
+			return PTR_ERR(extcon_class);
+		extcon_class->dev_attrs = extcon_attrs;
+	}
+
+	return 0;
+}
+
+static void extcon_cleanup(struct extcon_dev *edev, bool skip)
+{
+	if (!skip && get_device(edev->dev)) {
+		device_unregister(edev->dev);
+		put_device(edev->dev);
+	}
+
+	kfree(edev->dev);
+}
+
+static void extcon_dev_release(struct device *dev)
+{
+	struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+	extcon_cleanup(edev, true);
+}
+
+/**
+ * extcon_dev_register() - Register a new extcon device
+ * @edev	: the new extcon device (should be allocated before calling)
+ * @dev		: the parent device for this extcon device.
+ *
+ * Among the members of edev struct, please set the "user initializing data"
+ * in any case and set the "optional callbacks" if required. However, please
+ * do not set the values of "internal data", which are initialized by
+ * this function.
+ */
+int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
+{
+	int ret;
+
+	if (!extcon_class) {
+		ret = create_extcon_class();
+		if (ret < 0)
+			return ret;
+	}
+
+	edev->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+	edev->dev->parent = dev;
+	edev->dev->class = extcon_class;
+	edev->dev->release = extcon_dev_release;
+
+	dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev));
+	ret = device_register(edev->dev);
+	if (ret) {
+		put_device(edev->dev);
+		goto err_dev;
+	}
+
+	dev_set_drvdata(edev->dev, edev);
+	edev->state = 0;
+	return 0;
+
+err_dev:
+	kfree(edev->dev);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(extcon_dev_register);
+
+/**
+ * extcon_dev_unregister() - Unregister the extcon device.
+ * @edev:	the extcon device instance to be unregitered.
+ *
+ * Note that this does not call kfree(edev) because edev was not allocated
+ * by this class.
+ */
+void extcon_dev_unregister(struct extcon_dev *edev)
+{
+	extcon_cleanup(edev, false);
+}
+EXPORT_SYMBOL_GPL(extcon_dev_unregister);
+
+static int __init extcon_class_init(void)
+{
+	return create_extcon_class();
+}
+module_init(extcon_class_init);
+
+static void __exit extcon_class_exit(void)
+{
+	class_destroy(extcon_class);
+}
+module_exit(extcon_class_exit);
+
+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("External connector (extcon) class driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
new file mode 100644
index 0000000..cd732ab
--- /dev/null
+++ b/include/linux/extcon.h
@@ -0,0 +1,82 @@ 
+/*
+ *  External connector (extcon) class driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Donggeun Kim <dg77.kim@samsung.com>
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * based on switch class driver
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#ifndef __LINUX_EXTCON_H__
+#define __LINUX_EXTCON_H__
+
+/**
+ * struct extcon_dev - An extcon device represents one external connector.
+ * @name	The name of this extcon device. Parent device name is used
+ *		if NULL.
+ * @print_name	An optional callback to override the method to print the
+ *		name of the extcon device.
+ * @print_state	An optional callback to override the method to print the
+ *		status of the extcon device.
+ * @dev		Device of this extcon. Do not provide at register-time.
+ * @state	Attach/detach state of this extcon. Do not provide at
+ *		register-time
+ *
+ * In most cases, users only need to provide "User initializing data" of
+ * this struct when registering an extcon. In some exceptional cases,
+ * optional callbacks may be needed. However, the values in "internal data"
+ * are overwritten by register function.
+ */
+struct extcon_dev {
+	/* --- Optional user initializing data --- */
+	const char	*name;
+
+	/* --- Optional callbacks to override class functions --- */
+	ssize_t	(*print_name)(struct extcon_dev *edev, char *buf);
+	ssize_t	(*print_state)(struct extcon_dev *edev, char *buf);
+
+	/* --- Internal data. Please do not set. --- */
+	struct device	*dev;
+	u32		state;
+};
+
+#ifdef CONFIG_EXTCON
+extern int extcon_dev_register(struct extcon_dev *edev, struct device *dev);
+extern void extcon_dev_unregister(struct extcon_dev *edev);
+
+static inline u32 extcon_get_state(struct extcon_dev *edev)
+{
+	return edev->state;
+}
+
+extern void extcon_set_state(struct extcon_dev *edev, u32 state);
+#else /* CONFIG_EXTCON */
+static inline int extcon_dev_register(struct extcon_dev *edev,
+				      struct device *dev)
+{
+	return 0;
+}
+
+static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
+
+static inline u32 extcon_get_state(struct extcon_dev *edev)
+{
+	return 0;
+}
+
+static inline void extcon_set_state(struct extcon_dev *edev, u32 state) { }
+#endif /* CONFIG_EXTCON */
+#endif /* __LINUX_EXTCON_H__ */