zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/88pm860x_onkey.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/88pm860x_onkey.c
new file mode 100644
index 0000000..f9ce183
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/88pm860x_onkey.c
@@ -0,0 +1,170 @@
+/*
+ * 88pm860x_onkey.c - Marvell 88PM860x ONKEY driver
+ *
+ * Copyright (C) 2009-2010 Marvell International Ltd.
+ *      Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/88pm860x.h>
+#include <linux/slab.h>
+
+#define PM8607_WAKEUP		0x0b
+
+#define LONG_ONKEY_EN		(1 << 1)
+#define ONKEY_STATUS		(1 << 0)
+
+struct pm860x_onkey_info {
+	struct input_dev	*idev;
+	struct pm860x_chip	*chip;
+	struct i2c_client	*i2c;
+	struct device		*dev;
+	int			irq;
+};
+
+/* 88PM860x gives us an interrupt when ONKEY is held */
+static irqreturn_t pm860x_onkey_handler(int irq, void *data)
+{
+	struct pm860x_onkey_info *info = data;
+	int ret;
+
+	ret = pm860x_reg_read(info->i2c, PM8607_STATUS_2);
+	ret &= ONKEY_STATUS;
+	input_report_key(info->idev, KEY_POWER, ret);
+	input_sync(info->idev);
+
+	/* Enable 8-second long onkey detection */
+	pm860x_set_bits(info->i2c, PM8607_WAKEUP, 3, LONG_ONKEY_EN);
+	return IRQ_HANDLED;
+}
+
+static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
+{
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+	struct pm860x_onkey_info *info;
+	int irq, ret;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "No IRQ resource!\n");
+		return -EINVAL;
+	}
+
+	info = kzalloc(sizeof(struct pm860x_onkey_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+	info->chip = chip;
+	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
+	info->dev = &pdev->dev;
+	info->irq = irq;
+
+	info->idev = input_allocate_device();
+	if (!info->idev) {
+		dev_err(chip->dev, "Failed to allocate input dev\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	info->idev->name = "88pm860x_on";
+	info->idev->phys = "88pm860x_on/input0";
+	info->idev->id.bustype = BUS_I2C;
+	info->idev->dev.parent = &pdev->dev;
+	info->idev->evbit[0] = BIT_MASK(EV_KEY);
+	info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+
+	ret = input_register_device(info->idev);
+	if (ret) {
+		dev_err(chip->dev, "Can't register input device: %d\n", ret);
+		goto out_reg;
+	}
+
+	ret = request_threaded_irq(info->irq, NULL, pm860x_onkey_handler,
+				   IRQF_ONESHOT, "onkey", info);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+			info->irq, ret);
+		goto out_irq;
+	}
+
+	platform_set_drvdata(pdev, info);
+	device_init_wakeup(&pdev->dev, 1);
+
+	return 0;
+
+out_irq:
+	input_unregister_device(info->idev);
+	kfree(info);
+	return ret;
+
+out_reg:
+	input_free_device(info->idev);
+out:
+	kfree(info);
+	return ret;
+}
+
+static int __devexit pm860x_onkey_remove(struct platform_device *pdev)
+{
+	struct pm860x_onkey_info *info = platform_get_drvdata(pdev);
+
+	free_irq(info->irq, info);
+	input_unregister_device(info->idev);
+	kfree(info);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_onkey_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev))
+		chip->wakeup_flag |= 1 << PM8607_IRQ_ONKEY;
+	return 0;
+}
+static int pm860x_onkey_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev))
+		chip->wakeup_flag &= ~(1 << PM8607_IRQ_ONKEY);
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops, pm860x_onkey_suspend, pm860x_onkey_resume);
+
+static struct platform_driver pm860x_onkey_driver = {
+	.driver		= {
+		.name	= "88pm860x-onkey",
+		.owner	= THIS_MODULE,
+		.pm	= &pm860x_onkey_pm_ops,
+	},
+	.probe		= pm860x_onkey_probe,
+	.remove		= __devexit_p(pm860x_onkey_remove),
+};
+module_platform_driver(pm860x_onkey_driver);
+
+MODULE_DESCRIPTION("Marvell 88PM860x ONKEY driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/Kconfig b/ap/os/linux/linux-3.4.x/drivers/input/misc/Kconfig
new file mode 100644
index 0000000..e4706db
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/Kconfig
@@ -0,0 +1,619 @@
+#
+# Input misc drivers configuration
+#
+menuconfig INPUT_MISC
+	bool "Miscellaneous devices"
+	help
+	  Say Y here, and a list of miscellaneous input drivers will be displayed.
+	  Everything that didn't fit into the other categories is here. This option
+	  doesn't affect the kernel.
+
+	  If unsure, say Y.
+
+if INPUT_MISC
+
+config INPUT_88PM860X_ONKEY
+	tristate "88PM860x ONKEY support"
+	depends on MFD_88PM860X
+	help
+	  Support the ONKEY of Marvell 88PM860x PMICs as an input device
+	  reporting power button status.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called 88pm860x_onkey.
+
+config INPUT_AB8500_PONKEY
+	tristate "AB8500 Pon (PowerOn) Key"
+	depends on AB8500_CORE
+	help
+	  Say Y here to use the PowerOn Key for ST-Ericsson's AB8500
+	  Mix-Sig PMIC.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called ab8500-ponkey.
+
+config INPUT_AD714X
+	tristate "Analog Devices AD714x Capacitance Touch Sensor"
+	help
+	  Say Y here if you want to support an AD7142/3/7/8/7A touch sensor.
+
+	  You should select a bus connection too.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad714x.
+
+config INPUT_AD714X_I2C
+	tristate "support I2C bus connection"
+	depends on INPUT_AD714X && I2C
+	default y
+	help
+	  Say Y here if you have AD7142/AD7147 hooked to an I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad714x-i2c.
+
+config INPUT_AD714X_SPI
+	tristate "support SPI bus connection"
+	depends on INPUT_AD714X && SPI
+	default y
+	help
+	  Say Y here if you have AD7142/AD7147 hooked to a SPI bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad714x-spi.
+
+config INPUT_BMA150
+	tristate "BMA150/SMB380 acceleration sensor support"
+	depends on I2C
+	select INPUT_POLLDEV
+	help
+	  Say Y here if you have Bosch Sensortec's BMA150 or SMB380
+	  acceleration sensor hooked to an I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bma150.
+
+config INPUT_PCSPKR
+	tristate "PC Speaker support"
+	depends on PCSPKR_PLATFORM
+	help
+	  Say Y here if you want the standard PC Speaker to be used for
+	  bells and whistles.
+
+	  If unsure, say Y.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pcspkr.
+
+config INPUT_PM8XXX_VIBRATOR
+	tristate "Qualcomm PM8XXX vibrator support"
+	depends on MFD_PM8XXX
+	select INPUT_FF_MEMLESS
+	help
+	  This option enables device driver support for the vibrator
+	  on Qualcomm PM8xxx chip. This driver supports ff-memless interface
+	  from input framework.
+
+	  To compile this driver as module, choose M here: the
+	  module will be called pm8xxx-vibrator.
+
+config INPUT_PMIC8XXX_PWRKEY
+	tristate "PMIC8XXX power key support"
+	depends on MFD_PM8XXX
+	help
+	  Say Y here if you want support for the PMIC8XXX power key.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pmic8xxx-pwrkey.
+
+config INPUT_SPARCSPKR
+	tristate "SPARC Speaker support"
+	depends on PCI && SPARC64
+	help
+	  Say Y here if you want the standard Speaker on Sparc PCI systems
+	  to be used for bells and whistles.
+
+	  If unsure, say Y.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sparcspkr.
+
+config INPUT_M68K_BEEP
+	tristate "M68k Beeper support"
+	depends on M68K
+
+config INPUT_MAX8925_ONKEY
+	tristate "MAX8925 ONKEY support"
+	depends on MFD_MAX8925
+	help
+	  Support the ONKEY of MAX8925 PMICs as an input device
+	  reporting power button status.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called max8925_onkey.
+
+config INPUT_MAX8997_HAPTIC
+	tristate "MAXIM MAX8997 haptic controller support"
+	depends on HAVE_PWM && MFD_MAX8997
+	select INPUT_FF_MEMLESS
+	help
+	  This option enables device driver support for the haptic controller
+	  on MAXIM MAX8997 chip. This driver supports ff-memless interface
+	  from input framework.
+
+	  To compile this driver as module, choose M here: the
+	  module will be called max8997-haptic.
+
+config INPUT_MC13783_PWRBUTTON
+	tristate "MC13783 ON buttons"
+	depends on MFD_MC13783
+	help
+	  Support the ON buttons of MC13783 PMIC as an input device
+	  reporting power button status.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mc13783-pwrbutton.
+
+config INPUT_MMA8450
+	tristate "MMA8450 - Freescale's 3-Axis, 8/12-bit Digital Accelerometer"
+	depends on I2C
+	select INPUT_POLLDEV
+	help
+	  Say Y here if you want to support Freescale's MMA8450 Accelerometer
+	  through I2C interface.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mma8450.
+
+config INPUT_MPU3050
+	tristate "MPU3050 Triaxial gyroscope sensor"
+	depends on I2C
+	help
+	  Say Y here if you want to support InvenSense MPU3050
+	  connected via an I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mpu3050.
+
+config INPUT_APANEL
+	tristate "Fujitsu Lifebook Application Panel buttons"
+	depends on X86 && I2C && LEDS_CLASS
+	select INPUT_POLLDEV
+	select CHECK_SIGNATURE
+	help
+	 Say Y here for support of the Application Panel buttons, used on
+	 Fujitsu Lifebook. These are attached to the mainboard through
+	 an SMBus interface managed by the I2C Intel ICH (i801) driver,
+	 which you should also build for this kernel.
+
+	 To compile this driver as a module, choose M here: the module will
+	 be called apanel.
+
+config INPUT_GP2A
+	tristate "Sharp GP2AP002A00F I2C Proximity/Opto sensor driver"
+	depends on I2C
+	depends on GENERIC_GPIO
+	help
+	  Say Y here if you have a Sharp GP2AP002A00F proximity/als combo-chip
+	  hooked to an I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gp2ap002a00f.
+
+config INPUT_GPIO_TILT_POLLED
+	tristate "Polled GPIO tilt switch"
+	depends on GENERIC_GPIO
+	select INPUT_POLLDEV
+	help
+	  This driver implements support for tilt switches connected
+	  to GPIO pins that are not capable of generating interrupts.
+
+	  The list of gpios to use and the mapping of their states
+	  to specific angles is done via platform data.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gpio_tilt_polled.
+
+config INPUT_IXP4XX_BEEPER
+	tristate "IXP4XX Beeper support"
+	depends on ARCH_IXP4XX
+	help
+	  If you say yes here, you can connect a beeper to the
+	  ixp4xx gpio pins. This is used by the LinkSys NSLU2.
+
+	  If unsure, say Y.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ixp4xx-beeper.
+
+config INPUT_COBALT_BTNS
+	tristate "Cobalt button interface"
+	depends on MIPS_COBALT
+	select INPUT_POLLDEV
+	help
+	  Say Y here if you want to support MIPS Cobalt button interface.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cobalt_btns.
+
+config INPUT_WISTRON_BTNS
+	tristate "x86 Wistron laptop button interface"
+	depends on X86 && !X86_64
+	select INPUT_POLLDEV
+	select INPUT_SPARSEKMAP
+	select NEW_LEDS
+	select LEDS_CLASS
+	select CHECK_SIGNATURE
+	help
+	  Say Y here for support of Wistron laptop button interfaces, used on
+	  laptops of various brands, including Acer and Fujitsu-Siemens. If
+	  available, mail and wifi LEDs will be controllable via /sys/class/leds.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called wistron_btns.
+
+config INPUT_ATLAS_BTNS
+	tristate "x86 Atlas button interface"
+	depends on X86 && ACPI
+	help
+	  Say Y here for support of Atlas wallmount touchscreen buttons.
+	  The events will show up as scancodes F1 through F9 via evdev.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called atlas_btns.
+
+config INPUT_ATI_REMOTE2
+	tristate "ATI / Philips USB RF remote control"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to use an ATI or Philips USB RF remote control.
+	  These are RF remotes with USB receivers.
+	  ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards
+	  and is also available as a separate product.
+	  This driver provides mouse pointer, left and right mouse buttons,
+	  and maps all the other remote buttons to keypress events.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called ati_remote2.
+
+config INPUT_KEYCHORD
+	tristate "Key chord input driver support"
+	help
+	  Say Y here if you want to enable the key chord driver
+	  accessible at /dev/keychord.  This driver can be used
+	  for receiving notifications when client specified key
+	  combinations are pressed.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called keychord.
+
+config INPUT_KEYSPAN_REMOTE
+	tristate "Keyspan DMR USB remote control (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to use a Keyspan DMR USB remote control.
+	  Currently only the UIA-11 type of receiver has been tested.  The tag
+	  on the receiver that connects to the USB port should have a P/N that
+	  will tell you what type of DMR you have.  The UIA-10 type is not
+	  supported at this time.  This driver maps all buttons to keypress
+	  events.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called keyspan_remote.
+
+config INPUT_KXTJ9
+	tristate "Kionix KXTJ9 tri-axis digital accelerometer"
+	depends on I2C
+	help
+	  Say Y here to enable support for the Kionix KXTJ9 digital tri-axis
+	  accelerometer.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called kxtj9.
+
+config INPUT_KXTJ9_POLLED_MODE
+	bool "Enable polling mode support"
+	depends on INPUT_KXTJ9
+	select INPUT_POLLDEV
+	help
+	  Say Y here if you need accelerometer to work in polling mode.
+
+config INPUT_POWERMATE
+	tristate "Griffin PowerMate and Contour Jog support"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to use Griffin PowerMate or Contour Jog devices.
+	  These are aluminum dials which can measure clockwise and anticlockwise
+	  rotation.  The dial also acts as a pushbutton.  The base contains an LED
+	  which can be instructed to pulse or to switch to a particular intensity.
+
+	  You can download userspace tools from
+	  <http://sowerbutts.com/powermate/>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called powermate.
+
+config INPUT_YEALINK
+	tristate "Yealink usb-p1k voip phone"
+	depends on EXPERIMENTAL
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to enable keyboard and LCD functions of the
+	  Yealink usb-p1k usb phones. The audio part is enabled by the generic
+	  usb sound driver, so you might want to enable that as well.
+
+	  For information about how to use these additional functions, see
+	  <file:Documentation/input/yealink.txt>.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called yealink.
+
+config INPUT_CM109
+	tristate "C-Media CM109 USB I/O Controller"
+	depends on EXPERIMENTAL
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to enable keyboard and buzzer functions of the
+	  C-Media CM109 usb phones. The audio part is enabled by the generic
+	  usb sound driver, so you might want to enable that as well.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called cm109.
+
+config INPUT_TWL4030_PWRBUTTON
+	tristate "TWL4030 Power button Driver"
+	depends on TWL4030_CORE
+	help
+	  Say Y here if you want to enable power key reporting via the
+	  TWL4030 family of chips.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called twl4030_pwrbutton.
+
+config INPUT_TWL4030_VIBRA
+	tristate "Support for TWL4030 Vibrator"
+	depends on TWL4030_CORE
+	select MFD_TWL4030_AUDIO
+	select INPUT_FF_MEMLESS
+	help
+	  This option enables support for TWL4030 Vibrator Driver.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called twl4030_vibra.
+
+config INPUT_TWL6040_VIBRA
+	tristate "Support for TWL6040 Vibrator"
+	depends on TWL6040_CORE
+	select INPUT_FF_MEMLESS
+	help
+	  This option enables support for TWL6040 Vibrator Driver.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called twl6040_vibra.
+
+config INPUT_UINPUT
+	tristate "User level driver support"
+	help
+	  Say Y here if you want to support user level drivers for input
+	  subsystem accessible under char device 10:223 - /dev/input/uinput.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called uinput.
+
+config INPUT_SGI_BTNS
+	tristate "SGI Indy/O2 volume button interface"
+	depends on SGI_IP22 || SGI_IP32
+	select INPUT_POLLDEV
+	help
+	  Say Y here if you want to support SGI Indy/O2 volume button interface.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sgi_btns.
+
+config INPUT_GPIO
+	tristate "GPIO driver support"
+	help
+	  Say Y here if you want to support gpio based keys, wheels etc...
+
+config HP_SDC_RTC
+	tristate "HP SDC Real Time Clock"
+	depends on (GSC || HP300) && SERIO
+	select HP_SDC
+	help
+	  Say Y here if you want to support the built-in real time clock
+	  of the HP SDC controller.
+
+config INPUT_PCF50633_PMU
+	tristate "PCF50633 PMU events"
+	depends on MFD_PCF50633
+	help
+	 Say Y to include support for delivering  PMU events via  input
+	 layer on NXP PCF50633.
+
+config INPUT_PCF8574
+	tristate "PCF8574 Keypad input device"
+	depends on I2C && EXPERIMENTAL
+	help
+	  Say Y here if you want to support a keypad connected via I2C
+	  with a PCF8574.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pcf8574_keypad.
+
+config INPUT_PWM_BEEPER
+	tristate "PWM beeper support"
+	depends on HAVE_PWM
+	help
+	  Say Y here to get support for PWM based beeper devices.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called pwm-beeper.
+
+config INPUT_GPIO_ROTARY_ENCODER
+	tristate "Rotary encoders connected to GPIO pins"
+	depends on GPIOLIB && GENERIC_GPIO
+	help
+	  Say Y here to add support for rotary encoders connected to GPIO lines.
+	  Check file:Documentation/input/rotary-encoder.txt for more
+	  information.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rotary_encoder.
+
+config INPUT_RB532_BUTTON
+	tristate "Mikrotik Routerboard 532 button interface"
+	depends on MIKROTIK_RB532
+	depends on GPIOLIB && GENERIC_GPIO
+	select INPUT_POLLDEV
+	help
+	  Say Y here if you want support for the S1 button built into
+	  Mikrotik's Routerboard 532.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rb532_button.
+
+config INPUT_DA9052_ONKEY
+	tristate "Dialog DA9052/DA9053 Onkey"
+	depends on PMIC_DA9052
+	help
+	  Support the ONKEY of Dialog DA9052 PMICs as an input device
+	  reporting power button status.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called da9052_onkey.
+
+config INPUT_DM355EVM
+	tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
+	depends on MFD_DM355EVM_MSP
+	select INPUT_SPARSEKMAP
+	help
+	  Supports the pushbuttons and IR remote used with
+	  the DM355 EVM board.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dm355evm_keys.
+
+config INPUT_BFIN_ROTARY
+	tristate "Blackfin Rotary support"
+	depends on BF54x || BF52x
+	help
+	  Say Y here if you want to use the Blackfin Rotary.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bfin-rotary.
+
+config INPUT_WM831X_ON
+	tristate "WM831X ON pin"
+	depends on MFD_WM831X
+	help
+	  Support the ON pin of WM831X PMICs as an input device
+	  reporting power button status.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called wm831x_on.
+
+config INPUT_PCAP
+	tristate "Motorola EZX PCAP misc input events"
+	depends on EZX_PCAP
+	help
+	  Say Y here if you want to use Power key and Headphone button
+	  on Motorola EZX phones.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pcap_keys.
+
+config INPUT_ADXL34X
+	tristate "Analog Devices ADXL34x Three-Axis Digital Accelerometer"
+	default n
+	help
+	  Say Y here if you have a Accelerometer interface using the
+	  ADXL345/6 controller, and your board-specific initialization
+	  code includes that in its table of devices.
+
+	  This driver can use either I2C or SPI communication to the
+	  ADXL345/6 controller.  Select the appropriate method for
+	  your system.
+
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adxl34x.
+
+config INPUT_ADXL34X_I2C
+	tristate "support I2C bus connection"
+	depends on INPUT_ADXL34X && I2C
+	default y
+	help
+	  Say Y here if you have ADXL345/6 hooked to an I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adxl34x-i2c.
+
+config INPUT_ADXL34X_SPI
+	tristate "support SPI bus connection"
+	depends on INPUT_ADXL34X && SPI
+	default y
+	help
+	  Say Y here if you have ADXL345/6 hooked to a SPI bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adxl34x-spi.
+
+config INPUT_CMA3000
+	tristate "VTI CMA3000 Tri-axis accelerometer"
+	help
+	  Say Y here if you want to use VTI CMA3000_D0x Accelerometer
+	  driver
+
+	  This driver currently only supports I2C interface to the
+	  controller. Also select the I2C method.
+
+	  If unsure, say N
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cma3000_d0x.
+
+config INPUT_CMA3000_I2C
+	tristate "Support I2C bus connection"
+	depends on INPUT_CMA3000 && I2C
+	help
+	  Say Y here if you want to use VTI CMA3000_D0x Accelerometer
+	  through I2C interface.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cma3000_d0x_i2c.
+
+config INPUT_XEN_KBDDEV_FRONTEND
+	tristate "Xen virtual keyboard and mouse support"
+	depends on XEN
+	default y
+	select XEN_XENBUS_FRONTEND
+	help
+	  This driver implements the front-end of the Xen virtual
+	  keyboard and mouse device driver.  It communicates with a back-end
+	  in another domain.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called xen-kbdfront.
+
+config INPUT_MIR3DA
+	tristate "MIR3DA tri-axis digital accelerometer"
+	depends on I2C
+	default n	
+	help
+	  Say Y here to enable support for the MIR3DA digital tri-axis
+	  accelerometer.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called MIR3DA.
+endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/Makefile b/ap/os/linux/linux-3.4.x/drivers/input/misc/Makefile
new file mode 100644
index 0000000..e3afdc1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/Makefile
@@ -0,0 +1,60 @@
+#
+# Makefile for the input misc drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_INPUT_88PM860X_ONKEY)	+= 88pm860x_onkey.o
+obj-$(CONFIG_INPUT_AB8500_PONKEY)	+= ab8500-ponkey.o
+obj-$(CONFIG_INPUT_AD714X)		+= ad714x.o
+obj-$(CONFIG_INPUT_AD714X_I2C)		+= ad714x-i2c.o
+obj-$(CONFIG_INPUT_AD714X_SPI)		+= ad714x-spi.o
+obj-$(CONFIG_INPUT_ADXL34X)		+= adxl34x.o
+obj-$(CONFIG_INPUT_ADXL34X_I2C)		+= adxl34x-i2c.o
+obj-$(CONFIG_INPUT_ADXL34X_SPI)		+= adxl34x-spi.o
+obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
+obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
+obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
+obj-$(CONFIG_INPUT_BFIN_ROTARY)		+= bfin_rotary.o
+obj-$(CONFIG_INPUT_BMA150)		+= bma150.o
+obj-$(CONFIG_INPUT_CM109)		+= cm109.o
+obj-$(CONFIG_INPUT_CMA3000)		+= cma3000_d0x.o
+obj-$(CONFIG_INPUT_CMA3000_I2C)		+= cma3000_d0x_i2c.o
+obj-$(CONFIG_INPUT_COBALT_BTNS)		+= cobalt_btns.o
+obj-$(CONFIG_INPUT_DA9052_ONKEY)	+= da9052_onkey.o
+obj-$(CONFIG_INPUT_DM355EVM)		+= dm355evm_keys.o
+obj-$(CONFIG_INPUT_GP2A)		+= gp2ap002a00f.o
+obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)	+= gpio_tilt_polled.o
+obj-$(CONFIG_INPUT_GPIO)		+= gpio_event.o gpio_matrix.o gpio_input.o gpio_output.o gpio_axis.o
+obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
+obj-$(CONFIG_INPUT_IXP4XX_BEEPER)	+= ixp4xx-beeper.o
+obj-$(CONFIG_INPUT_KEYCHORD)		+= keychord.o
+obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
+obj-$(CONFIG_INPUT_KXTJ9)		+= kxtj9.o
+obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
+obj-$(CONFIG_INPUT_MAX8925_ONKEY)	+= max8925_onkey.o
+obj-$(CONFIG_INPUT_MAX8997_HAPTIC)	+= max8997_haptic.o
+obj-$(CONFIG_INPUT_MC13783_PWRBUTTON)	+= mc13783-pwrbutton.o
+obj-$(CONFIG_INPUT_MMA8450)		+= mma8450.o
+obj-$(CONFIG_INPUT_MPU3050)		+= mpu3050.o
+obj-$(CONFIG_INPUT_PCAP)		+= pcap_keys.o
+obj-$(CONFIG_INPUT_PCF50633_PMU)	+= pcf50633-input.o
+obj-$(CONFIG_INPUT_PCF8574)		+= pcf8574_keypad.o
+obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o
+obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR)	+= pm8xxx-vibrator.o
+obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)	+= pmic8xxx-pwrkey.o
+obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
+obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o
+obj-$(CONFIG_INPUT_RB532_BUTTON)	+= rb532_button.o
+obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)	+= rotary_encoder.o
+obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o
+obj-$(CONFIG_INPUT_SPARCSPKR)		+= sparcspkr.o
+obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON)	+= twl4030-pwrbutton.o
+obj-$(CONFIG_INPUT_TWL4030_VIBRA)	+= twl4030-vibra.o
+obj-$(CONFIG_INPUT_TWL6040_VIBRA)	+= twl6040-vibra.o
+obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
+obj-$(CONFIG_INPUT_WISTRON_BTNS)	+= wistron_btns.o
+obj-$(CONFIG_INPUT_WM831X_ON)		+= wm831x-on.o
+obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)	+= xen-kbdfront.o
+obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
+obj-$(CONFIG_INPUT_MIR3DA)	+= mir3da/
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/ab8500-ponkey.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/ab8500-ponkey.c
new file mode 100644
index 0000000..350fd0c
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/ab8500-ponkey.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ * AB8500 Power-On Key handler
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/slab.h>
+
+/**
+ * struct ab8500_ponkey - ab8500 ponkey information
+ * @input_dev: pointer to input device
+ * @ab8500: ab8500 parent
+ * @irq_dbf: irq number for falling transition
+ * @irq_dbr: irq number for rising transition
+ */
+struct ab8500_ponkey {
+	struct input_dev	*idev;
+	struct ab8500		*ab8500;
+	int			irq_dbf;
+	int			irq_dbr;
+};
+
+/* AB8500 gives us an interrupt when ONKEY is held */
+static irqreturn_t ab8500_ponkey_handler(int irq, void *data)
+{
+	struct ab8500_ponkey *ponkey = data;
+
+	if (irq == ponkey->irq_dbf)
+		input_report_key(ponkey->idev, KEY_POWER, true);
+	else if (irq == ponkey->irq_dbr)
+		input_report_key(ponkey->idev, KEY_POWER, false);
+
+	input_sync(ponkey->idev);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit ab8500_ponkey_probe(struct platform_device *pdev)
+{
+	struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+	struct ab8500_ponkey *ponkey;
+	struct input_dev *input;
+	int irq_dbf, irq_dbr;
+	int error;
+
+	irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF");
+	if (irq_dbf < 0) {
+		dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf);
+		return irq_dbf;
+	}
+
+	irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR");
+	if (irq_dbr < 0) {
+		dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr);
+		return irq_dbr;
+	}
+
+	ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!ponkey || !input) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ponkey->idev = input;
+	ponkey->ab8500 = ab8500;
+	ponkey->irq_dbf = irq_dbf;
+	ponkey->irq_dbr = irq_dbr;
+
+	input->name = "AB8500 POn(PowerOn) Key";
+	input->dev.parent = &pdev->dev;
+
+	input_set_capability(input, EV_KEY, KEY_POWER);
+
+	error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler,
+					0, "ab8500-ponkey-dbf", ponkey);
+	if (error < 0) {
+		dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
+			ponkey->irq_dbf, error);
+		goto err_free_mem;
+	}
+
+	error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler,
+					0, "ab8500-ponkey-dbr", ponkey);
+	if (error < 0) {
+		dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
+			ponkey->irq_dbr, error);
+		goto err_free_dbf_irq;
+	}
+
+	error = input_register_device(ponkey->idev);
+	if (error) {
+		dev_err(ab8500->dev, "Can't register input device: %d\n", error);
+		goto err_free_dbr_irq;
+	}
+
+	platform_set_drvdata(pdev, ponkey);
+	return 0;
+
+err_free_dbr_irq:
+	free_irq(ponkey->irq_dbr, ponkey);
+err_free_dbf_irq:
+	free_irq(ponkey->irq_dbf, ponkey);
+err_free_mem:
+	input_free_device(input);
+	kfree(ponkey);
+
+	return error;
+}
+
+static int __devexit ab8500_ponkey_remove(struct platform_device *pdev)
+{
+	struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev);
+
+	free_irq(ponkey->irq_dbf, ponkey);
+	free_irq(ponkey->irq_dbr, ponkey);
+	input_unregister_device(ponkey->idev);
+	kfree(ponkey);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver ab8500_ponkey_driver = {
+	.driver		= {
+		.name	= "ab8500-poweron-key",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ab8500_ponkey_probe,
+	.remove		= __devexit_p(ab8500_ponkey_remove),
+};
+module_platform_driver(ab8500_ponkey_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("ST-Ericsson AB8500 Power-ON(Pon) Key driver");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x-i2c.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x-i2c.c
new file mode 100644
index 0000000..c8a7901
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x-i2c.c
@@ -0,0 +1,123 @@
+/*
+ * AD714X CapTouch Programmable Controller driver (I2C bus)
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_I2C */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pm.h>
+#include "ad714x.h"
+
+#ifdef CONFIG_PM
+static int ad714x_i2c_suspend(struct device *dev)
+{
+	return ad714x_disable(i2c_get_clientdata(to_i2c_client(dev)));
+}
+
+static int ad714x_i2c_resume(struct device *dev)
+{
+	return ad714x_enable(i2c_get_clientdata(to_i2c_client(dev)));
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ad714x_i2c_pm, ad714x_i2c_suspend, ad714x_i2c_resume);
+
+static int ad714x_i2c_write(struct ad714x_chip *chip,
+			    unsigned short reg, unsigned short data)
+{
+	struct i2c_client *client = to_i2c_client(chip->dev);
+	int error;
+
+	chip->xfer_buf[0] = cpu_to_be16(reg);
+	chip->xfer_buf[1] = cpu_to_be16(data);
+
+	error = i2c_master_send(client, (u8 *)chip->xfer_buf,
+				2 * sizeof(*chip->xfer_buf));
+	if (unlikely(error < 0)) {
+		dev_err(&client->dev, "I2C write error: %d\n", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int ad714x_i2c_read(struct ad714x_chip *chip,
+			   unsigned short reg, unsigned short *data, size_t len)
+{
+	struct i2c_client *client = to_i2c_client(chip->dev);
+	int i;
+	int error;
+
+	chip->xfer_buf[0] = cpu_to_be16(reg);
+
+	error = i2c_master_send(client, (u8 *)chip->xfer_buf,
+				sizeof(*chip->xfer_buf));
+	if (error >= 0)
+		error = i2c_master_recv(client, (u8 *)chip->xfer_buf,
+					len * sizeof(*chip->xfer_buf));
+
+	if (unlikely(error < 0)) {
+		dev_err(&client->dev, "I2C read error: %d\n", error);
+		return error;
+	}
+
+	for (i = 0; i < len; i++)
+		data[i] = be16_to_cpu(chip->xfer_buf[i]);
+
+	return 0;
+}
+
+static int __devinit ad714x_i2c_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct ad714x_chip *chip;
+
+	chip = ad714x_probe(&client->dev, BUS_I2C, client->irq,
+			    ad714x_i2c_read, ad714x_i2c_write);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+
+	i2c_set_clientdata(client, chip);
+
+	return 0;
+}
+
+static int __devexit ad714x_i2c_remove(struct i2c_client *client)
+{
+	struct ad714x_chip *chip = i2c_get_clientdata(client);
+
+	ad714x_remove(chip);
+
+	return 0;
+}
+
+static const struct i2c_device_id ad714x_id[] = {
+	{ "ad7142_captouch", 0 },
+	{ "ad7143_captouch", 0 },
+	{ "ad7147_captouch", 0 },
+	{ "ad7147a_captouch", 0 },
+	{ "ad7148_captouch", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ad714x_id);
+
+static struct i2c_driver ad714x_i2c_driver = {
+	.driver = {
+		.name = "ad714x_captouch",
+		.pm   = &ad714x_i2c_pm,
+	},
+	.probe    = ad714x_i2c_probe,
+	.remove   = __devexit_p(ad714x_i2c_remove),
+	.id_table = ad714x_id,
+};
+
+module_i2c_driver(ad714x_i2c_driver);
+
+MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor I2C Bus Driver");
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x-spi.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x-spi.c
new file mode 100644
index 0000000..75f6136
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x-spi.c
@@ -0,0 +1,130 @@
+/*
+ * AD714X CapTouch Programmable Controller driver (SPI bus)
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_SPI */
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/pm.h>
+#include <linux/types.h>
+#include "ad714x.h"
+
+#define AD714x_SPI_CMD_PREFIX      0xE000   /* bits 15:11 */
+#define AD714x_SPI_READ            BIT(10)
+
+#ifdef CONFIG_PM
+static int ad714x_spi_suspend(struct device *dev)
+{
+	return ad714x_disable(spi_get_drvdata(to_spi_device(dev)));
+}
+
+static int ad714x_spi_resume(struct device *dev)
+{
+	return ad714x_enable(spi_get_drvdata(to_spi_device(dev)));
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ad714x_spi_pm, ad714x_spi_suspend, ad714x_spi_resume);
+
+static int ad714x_spi_read(struct ad714x_chip *chip,
+			   unsigned short reg, unsigned short *data, size_t len)
+{
+	struct spi_device *spi = to_spi_device(chip->dev);
+	struct spi_message message;
+	struct spi_transfer xfer[2];
+	int i;
+	int error;
+
+	spi_message_init(&message);
+	memset(xfer, 0, sizeof(xfer));
+
+	chip->xfer_buf[0] = cpu_to_be16(AD714x_SPI_CMD_PREFIX |
+					AD714x_SPI_READ | reg);
+	xfer[0].tx_buf = &chip->xfer_buf[0];
+	xfer[0].len = sizeof(chip->xfer_buf[0]);
+	spi_message_add_tail(&xfer[0], &message);
+
+	xfer[1].rx_buf = &chip->xfer_buf[1];
+	xfer[1].len = sizeof(chip->xfer_buf[1]) * len;
+	spi_message_add_tail(&xfer[1], &message);
+
+	error = spi_sync(spi, &message);
+	if (unlikely(error)) {
+		dev_err(chip->dev, "SPI read error: %d\n", error);
+		return error;
+	}
+
+	for (i = 0; i < len; i++)
+		data[i] = be16_to_cpu(chip->xfer_buf[i + 1]);
+
+	return 0;
+}
+
+static int ad714x_spi_write(struct ad714x_chip *chip,
+			    unsigned short reg, unsigned short data)
+{
+	struct spi_device *spi = to_spi_device(chip->dev);
+	int error;
+
+	chip->xfer_buf[0] = cpu_to_be16(AD714x_SPI_CMD_PREFIX | reg);
+	chip->xfer_buf[1] = cpu_to_be16(data);
+
+	error = spi_write(spi, (u8 *)chip->xfer_buf,
+			  2 * sizeof(*chip->xfer_buf));
+	if (unlikely(error)) {
+		dev_err(chip->dev, "SPI write error: %d\n", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int __devinit ad714x_spi_probe(struct spi_device *spi)
+{
+	struct ad714x_chip *chip;
+	int err;
+
+	spi->bits_per_word = 8;
+	err = spi_setup(spi);
+	if (err < 0)
+		return err;
+
+	chip = ad714x_probe(&spi->dev, BUS_SPI, spi->irq,
+			    ad714x_spi_read, ad714x_spi_write);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+
+	spi_set_drvdata(spi, chip);
+
+	return 0;
+}
+
+static int __devexit ad714x_spi_remove(struct spi_device *spi)
+{
+	struct ad714x_chip *chip = spi_get_drvdata(spi);
+
+	ad714x_remove(chip);
+	spi_set_drvdata(spi, NULL);
+
+	return 0;
+}
+
+static struct spi_driver ad714x_spi_driver = {
+	.driver = {
+		.name	= "ad714x_captouch",
+		.owner	= THIS_MODULE,
+		.pm	= &ad714x_spi_pm,
+	},
+	.probe		= ad714x_spi_probe,
+	.remove		= __devexit_p(ad714x_spi_remove),
+};
+
+module_spi_driver(ad714x_spi_driver);
+
+MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor SPI Bus Driver");
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x.c
new file mode 100644
index 0000000..0ac75bb
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x.c
@@ -0,0 +1,1259 @@
+/*
+ * AD714X CapTouch Programmable Controller driver supporting AD7142/3/7/8/7A
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/input/ad714x.h>
+#include <linux/module.h>
+#include "ad714x.h"
+
+#define AD714X_PWR_CTRL           0x0
+#define AD714X_STG_CAL_EN_REG     0x1
+#define AD714X_AMB_COMP_CTRL0_REG 0x2
+#define AD714X_PARTID_REG         0x17
+#define AD7142_PARTID             0xE620
+#define AD7143_PARTID             0xE630
+#define AD7147_PARTID             0x1470
+#define AD7148_PARTID             0x1480
+#define AD714X_STAGECFG_REG       0x80
+#define AD714X_SYSCFG_REG         0x0
+
+#define STG_LOW_INT_EN_REG     0x5
+#define STG_HIGH_INT_EN_REG    0x6
+#define STG_COM_INT_EN_REG     0x7
+#define STG_LOW_INT_STA_REG    0x8
+#define STG_HIGH_INT_STA_REG   0x9
+#define STG_COM_INT_STA_REG    0xA
+
+#define CDC_RESULT_S0          0xB
+#define CDC_RESULT_S1          0xC
+#define CDC_RESULT_S2          0xD
+#define CDC_RESULT_S3          0xE
+#define CDC_RESULT_S4          0xF
+#define CDC_RESULT_S5          0x10
+#define CDC_RESULT_S6          0x11
+#define CDC_RESULT_S7          0x12
+#define CDC_RESULT_S8          0x13
+#define CDC_RESULT_S9          0x14
+#define CDC_RESULT_S10         0x15
+#define CDC_RESULT_S11         0x16
+
+#define STAGE0_AMBIENT		0xF1
+#define STAGE1_AMBIENT		0x115
+#define STAGE2_AMBIENT		0x139
+#define STAGE3_AMBIENT		0x15D
+#define STAGE4_AMBIENT		0x181
+#define STAGE5_AMBIENT		0x1A5
+#define STAGE6_AMBIENT		0x1C9
+#define STAGE7_AMBIENT		0x1ED
+#define STAGE8_AMBIENT		0x211
+#define STAGE9_AMBIENT		0x234
+#define STAGE10_AMBIENT		0x259
+#define STAGE11_AMBIENT		0x27D
+
+#define PER_STAGE_REG_NUM      36
+#define STAGE_CFGREG_NUM       8
+#define SYS_CFGREG_NUM         8
+
+/*
+ * driver information which will be used to maintain the software flow
+ */
+enum ad714x_device_state { IDLE, JITTER, ACTIVE, SPACE };
+
+struct ad714x_slider_drv {
+	int highest_stage;
+	int abs_pos;
+	int flt_pos;
+	enum ad714x_device_state state;
+	struct input_dev *input;
+};
+
+struct ad714x_wheel_drv {
+	int abs_pos;
+	int flt_pos;
+	int pre_highest_stage;
+	int highest_stage;
+	enum ad714x_device_state state;
+	struct input_dev *input;
+};
+
+struct ad714x_touchpad_drv {
+	int x_highest_stage;
+	int x_flt_pos;
+	int x_abs_pos;
+	int y_highest_stage;
+	int y_flt_pos;
+	int y_abs_pos;
+	int left_ep;
+	int left_ep_val;
+	int right_ep;
+	int right_ep_val;
+	int top_ep;
+	int top_ep_val;
+	int bottom_ep;
+	int bottom_ep_val;
+	enum ad714x_device_state state;
+	struct input_dev *input;
+};
+
+struct ad714x_button_drv {
+	enum ad714x_device_state state;
+	/*
+	 * Unlike slider/wheel/touchpad, all buttons point to
+	 * same input_dev instance
+	 */
+	struct input_dev *input;
+};
+
+struct ad714x_driver_data {
+	struct ad714x_slider_drv *slider;
+	struct ad714x_wheel_drv *wheel;
+	struct ad714x_touchpad_drv *touchpad;
+	struct ad714x_button_drv *button;
+};
+
+/*
+ * information to integrate all things which will be private data
+ * of spi/i2c device
+ */
+
+static void ad714x_use_com_int(struct ad714x_chip *ad714x,
+				int start_stage, int end_stage)
+{
+	unsigned short data;
+	unsigned short mask;
+
+	mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
+
+	ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
+	data |= 1 << end_stage;
+	ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
+
+	ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
+	data &= ~mask;
+	ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
+}
+
+static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
+				int start_stage, int end_stage)
+{
+	unsigned short data;
+	unsigned short mask;
+
+	mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
+
+	ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
+	data &= ~(1 << end_stage);
+	ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
+
+	ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
+	data |= mask;
+	ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
+}
+
+static int ad714x_cal_highest_stage(struct ad714x_chip *ad714x,
+					int start_stage, int end_stage)
+{
+	int max_res = 0;
+	int max_idx = 0;
+	int i;
+
+	for (i = start_stage; i <= end_stage; i++) {
+		if (ad714x->sensor_val[i] > max_res) {
+			max_res = ad714x->sensor_val[i];
+			max_idx = i;
+		}
+	}
+
+	return max_idx;
+}
+
+static int ad714x_cal_abs_pos(struct ad714x_chip *ad714x,
+				int start_stage, int end_stage,
+				int highest_stage, int max_coord)
+{
+	int a_param, b_param;
+
+	if (highest_stage == start_stage) {
+		a_param = ad714x->sensor_val[start_stage + 1];
+		b_param = ad714x->sensor_val[start_stage] +
+			ad714x->sensor_val[start_stage + 1];
+	} else if (highest_stage == end_stage) {
+		a_param = ad714x->sensor_val[end_stage] *
+			(end_stage - start_stage) +
+			ad714x->sensor_val[end_stage - 1] *
+			(end_stage - start_stage - 1);
+		b_param = ad714x->sensor_val[end_stage] +
+			ad714x->sensor_val[end_stage - 1];
+	} else {
+		a_param = ad714x->sensor_val[highest_stage] *
+			(highest_stage - start_stage) +
+			ad714x->sensor_val[highest_stage - 1] *
+			(highest_stage - start_stage - 1) +
+			ad714x->sensor_val[highest_stage + 1] *
+			(highest_stage - start_stage + 1);
+		b_param = ad714x->sensor_val[highest_stage] +
+			ad714x->sensor_val[highest_stage - 1] +
+			ad714x->sensor_val[highest_stage + 1];
+	}
+
+	return (max_coord / (end_stage - start_stage)) * a_param / b_param;
+}
+
+/*
+ * One button can connect to multi positive and negative of CDCs
+ * Multi-buttons can connect to same positive/negative of one CDC
+ */
+static void ad714x_button_state_machine(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_button_plat *hw = &ad714x->hw->button[idx];
+	struct ad714x_button_drv *sw = &ad714x->sw->button[idx];
+
+	switch (sw->state) {
+	case IDLE:
+		if (((ad714x->h_state & hw->h_mask) == hw->h_mask) &&
+		    ((ad714x->l_state & hw->l_mask) == hw->l_mask)) {
+			dev_dbg(ad714x->dev, "button %d touched\n", idx);
+			input_report_key(sw->input, hw->keycode, 1);
+			input_sync(sw->input);
+			sw->state = ACTIVE;
+		}
+		break;
+
+	case ACTIVE:
+		if (((ad714x->h_state & hw->h_mask) != hw->h_mask) ||
+		    ((ad714x->l_state & hw->l_mask) != hw->l_mask)) {
+			dev_dbg(ad714x->dev, "button %d released\n", idx);
+			input_report_key(sw->input, hw->keycode, 0);
+			input_sync(sw->input);
+			sw->state = IDLE;
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+/*
+ * The response of a sensor is defined by the absolute number of codes
+ * between the current CDC value and the ambient value.
+ */
+static void ad714x_slider_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
+	int i;
+
+	ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
+			&ad714x->adc_reg[hw->start_stage],
+			hw->end_stage - hw->start_stage + 1);
+
+	for (i = hw->start_stage; i <= hw->end_stage; i++) {
+		ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+				&ad714x->amb_reg[i], 1);
+
+		ad714x->sensor_val[i] =
+			abs(ad714x->adc_reg[i] - ad714x->amb_reg[i]);
+	}
+}
+
+static void ad714x_slider_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
+	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
+
+	sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage,
+			hw->end_stage);
+
+	dev_dbg(ad714x->dev, "slider %d highest_stage:%d\n", idx,
+		sw->highest_stage);
+}
+
+/*
+ * The formulae are very straight forward. It uses the sensor with the
+ * highest response and the 2 adjacent ones.
+ * When Sensor 0 has the highest response, only sensor 0 and sensor 1
+ * are used in the calculations. Similarly when the last sensor has the
+ * highest response, only the last sensor and the second last sensors
+ * are used in the calculations.
+ *
+ * For i= idx_of_peak_Sensor-1 to i= idx_of_peak_Sensor+1
+ *         v += Sensor response(i)*i
+ *         w += Sensor response(i)
+ * POS=(Number_of_Positions_Wanted/(Number_of_Sensors_Used-1)) *(v/w)
+ */
+static void ad714x_slider_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
+	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
+
+	sw->abs_pos = ad714x_cal_abs_pos(ad714x, hw->start_stage, hw->end_stage,
+		sw->highest_stage, hw->max_coord);
+
+	dev_dbg(ad714x->dev, "slider %d absolute position:%d\n", idx,
+		sw->abs_pos);
+}
+
+/*
+ * To minimise the Impact of the noise on the algorithm, ADI developed a
+ * routine that filters the CDC results after they have been read by the
+ * host processor.
+ * The filter used is an Infinite Input Response(IIR) filter implemented
+ * in firmware and attenuates the noise on the CDC results after they've
+ * been read by the host processor.
+ * Filtered_CDC_result = (Filtered_CDC_result * (10 - Coefficient) +
+ *				Latest_CDC_result * Coefficient)/10
+ */
+static void ad714x_slider_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
+
+	sw->flt_pos = (sw->flt_pos * (10 - 4) +
+			sw->abs_pos * 4)/10;
+
+	dev_dbg(ad714x->dev, "slider %d filter position:%d\n", idx,
+		sw->flt_pos);
+}
+
+static void ad714x_slider_use_com_int(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
+
+	ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage);
+}
+
+static void ad714x_slider_use_thr_int(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
+
+	ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage);
+}
+
+static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
+	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
+	unsigned short h_state, c_state;
+	unsigned short mask;
+
+	mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1);
+
+	h_state = ad714x->h_state & mask;
+	c_state = ad714x->c_state & mask;
+
+	switch (sw->state) {
+	case IDLE:
+		if (h_state) {
+			sw->state = JITTER;
+			/* In End of Conversion interrupt mode, the AD714X
+			 * continuously generates hardware interrupts.
+			 */
+			ad714x_slider_use_com_int(ad714x, idx);
+			dev_dbg(ad714x->dev, "slider %d touched\n", idx);
+		}
+		break;
+
+	case JITTER:
+		if (c_state == mask) {
+			ad714x_slider_cal_sensor_val(ad714x, idx);
+			ad714x_slider_cal_highest_stage(ad714x, idx);
+			ad714x_slider_cal_abs_pos(ad714x, idx);
+			sw->flt_pos = sw->abs_pos;
+			sw->state = ACTIVE;
+		}
+		break;
+
+	case ACTIVE:
+		if (c_state == mask) {
+			if (h_state) {
+				ad714x_slider_cal_sensor_val(ad714x, idx);
+				ad714x_slider_cal_highest_stage(ad714x, idx);
+				ad714x_slider_cal_abs_pos(ad714x, idx);
+				ad714x_slider_cal_flt_pos(ad714x, idx);
+				input_report_abs(sw->input, ABS_X, sw->flt_pos);
+				input_report_key(sw->input, BTN_TOUCH, 1);
+			} else {
+				/* When the user lifts off the sensor, configure
+				 * the AD714X back to threshold interrupt mode.
+				 */
+				ad714x_slider_use_thr_int(ad714x, idx);
+				sw->state = IDLE;
+				input_report_key(sw->input, BTN_TOUCH, 0);
+				dev_dbg(ad714x->dev, "slider %d released\n",
+					idx);
+			}
+			input_sync(sw->input);
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+/*
+ * When the scroll wheel is activated, we compute the absolute position based
+ * on the sensor values. To calculate the position, we first determine the
+ * sensor that has the greatest response among the 8 sensors that constitutes
+ * the scrollwheel. Then we determined the 2 sensors on either sides of the
+ * sensor with the highest response and we apply weights to these sensors.
+ */
+static void ad714x_wheel_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
+	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
+
+	sw->pre_highest_stage = sw->highest_stage;
+	sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage,
+			hw->end_stage);
+
+	dev_dbg(ad714x->dev, "wheel %d highest_stage:%d\n", idx,
+		sw->highest_stage);
+}
+
+static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
+	int i;
+
+	ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
+			&ad714x->adc_reg[hw->start_stage],
+			hw->end_stage - hw->start_stage + 1);
+
+	for (i = hw->start_stage; i <= hw->end_stage; i++) {
+		ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+				&ad714x->amb_reg[i], 1);
+		if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
+			ad714x->sensor_val[i] =
+				ad714x->adc_reg[i] - ad714x->amb_reg[i];
+		else
+			ad714x->sensor_val[i] = 0;
+	}
+}
+
+/*
+ * When the scroll wheel is activated, we compute the absolute position based
+ * on the sensor values. To calculate the position, we first determine the
+ * sensor that has the greatest response among the sensors that constitutes
+ * the scrollwheel. Then we determined the sensors on either sides of the
+ * sensor with the highest response and we apply weights to these sensors. The
+ * result of this computation gives us the mean value.
+ */
+
+static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
+	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
+	int stage_num = hw->end_stage - hw->start_stage + 1;
+	int first_before, highest, first_after;
+	int a_param, b_param;
+
+	first_before = (sw->highest_stage + stage_num - 1) % stage_num;
+	highest = sw->highest_stage;
+	first_after = (sw->highest_stage + stage_num + 1) % stage_num;
+
+	a_param = ad714x->sensor_val[highest] *
+		(highest - hw->start_stage) +
+		ad714x->sensor_val[first_before] *
+		(highest - hw->start_stage - 1) +
+		ad714x->sensor_val[first_after] *
+		(highest - hw->start_stage + 1);
+	b_param = ad714x->sensor_val[highest] +
+		ad714x->sensor_val[first_before] +
+		ad714x->sensor_val[first_after];
+
+	sw->abs_pos = ((hw->max_coord / (hw->end_stage - hw->start_stage)) *
+			a_param) / b_param;
+
+	if (sw->abs_pos > hw->max_coord)
+		sw->abs_pos = hw->max_coord;
+	else if (sw->abs_pos < 0)
+		sw->abs_pos = 0;
+}
+
+static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
+	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
+	if (((sw->pre_highest_stage == hw->end_stage) &&
+			(sw->highest_stage == hw->start_stage)) ||
+	    ((sw->pre_highest_stage == hw->start_stage) &&
+			(sw->highest_stage == hw->end_stage)))
+		sw->flt_pos = sw->abs_pos;
+	else
+		sw->flt_pos = ((sw->flt_pos * 30) + (sw->abs_pos * 71)) / 100;
+
+	if (sw->flt_pos > hw->max_coord)
+		sw->flt_pos = hw->max_coord;
+}
+
+static void ad714x_wheel_use_com_int(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
+
+	ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage);
+}
+
+static void ad714x_wheel_use_thr_int(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
+
+	ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage);
+}
+
+static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
+	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
+	unsigned short h_state, c_state;
+	unsigned short mask;
+
+	mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1);
+
+	h_state = ad714x->h_state & mask;
+	c_state = ad714x->c_state & mask;
+
+	switch (sw->state) {
+	case IDLE:
+		if (h_state) {
+			sw->state = JITTER;
+			/* In End of Conversion interrupt mode, the AD714X
+			 * continuously generates hardware interrupts.
+			 */
+			ad714x_wheel_use_com_int(ad714x, idx);
+			dev_dbg(ad714x->dev, "wheel %d touched\n", idx);
+		}
+		break;
+
+	case JITTER:
+		if (c_state == mask)	{
+			ad714x_wheel_cal_sensor_val(ad714x, idx);
+			ad714x_wheel_cal_highest_stage(ad714x, idx);
+			ad714x_wheel_cal_abs_pos(ad714x, idx);
+			sw->flt_pos = sw->abs_pos;
+			sw->state = ACTIVE;
+		}
+		break;
+
+	case ACTIVE:
+		if (c_state == mask) {
+			if (h_state) {
+				ad714x_wheel_cal_sensor_val(ad714x, idx);
+				ad714x_wheel_cal_highest_stage(ad714x, idx);
+				ad714x_wheel_cal_abs_pos(ad714x, idx);
+				ad714x_wheel_cal_flt_pos(ad714x, idx);
+				input_report_abs(sw->input, ABS_WHEEL,
+					sw->flt_pos);
+				input_report_key(sw->input, BTN_TOUCH, 1);
+			} else {
+				/* When the user lifts off the sensor, configure
+				 * the AD714X back to threshold interrupt mode.
+				 */
+				ad714x_wheel_use_thr_int(ad714x, idx);
+				sw->state = IDLE;
+				input_report_key(sw->input, BTN_TOUCH, 0);
+
+				dev_dbg(ad714x->dev, "wheel %d released\n",
+					idx);
+			}
+			input_sync(sw->input);
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void touchpad_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
+	int i;
+
+	ad714x->read(ad714x, CDC_RESULT_S0 + hw->x_start_stage,
+			&ad714x->adc_reg[hw->x_start_stage],
+			hw->x_end_stage - hw->x_start_stage + 1);
+
+	for (i = hw->x_start_stage; i <= hw->x_end_stage; i++) {
+		ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+				&ad714x->amb_reg[i], 1);
+		if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
+			ad714x->sensor_val[i] =
+				ad714x->adc_reg[i] - ad714x->amb_reg[i];
+		else
+			ad714x->sensor_val[i] = 0;
+	}
+}
+
+static void touchpad_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
+	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
+
+	sw->x_highest_stage = ad714x_cal_highest_stage(ad714x,
+		hw->x_start_stage, hw->x_end_stage);
+	sw->y_highest_stage = ad714x_cal_highest_stage(ad714x,
+		hw->y_start_stage, hw->y_end_stage);
+
+	dev_dbg(ad714x->dev,
+		"touchpad %d x_highest_stage:%d, y_highest_stage:%d\n",
+		idx, sw->x_highest_stage, sw->y_highest_stage);
+}
+
+/*
+ * If 2 fingers are touching the sensor then 2 peaks can be observed in the
+ * distribution.
+ * The arithmetic doesn't support to get absolute coordinates for multi-touch
+ * yet.
+ */
+static int touchpad_check_second_peak(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
+	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
+	int i;
+
+	for (i = hw->x_start_stage; i < sw->x_highest_stage; i++) {
+		if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
+			> (ad714x->sensor_val[i + 1] / 10))
+			return 1;
+	}
+
+	for (i = sw->x_highest_stage; i < hw->x_end_stage; i++) {
+		if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
+			> (ad714x->sensor_val[i] / 10))
+			return 1;
+	}
+
+	for (i = hw->y_start_stage; i < sw->y_highest_stage; i++) {
+		if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
+			> (ad714x->sensor_val[i + 1] / 10))
+			return 1;
+	}
+
+	for (i = sw->y_highest_stage; i < hw->y_end_stage; i++) {
+		if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
+			> (ad714x->sensor_val[i] / 10))
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * If only one finger is used to activate the touch pad then only 1 peak will be
+ * registered in the distribution. This peak and the 2 adjacent sensors will be
+ * used in the calculation of the absolute position. This will prevent hand
+ * shadows to affect the absolute position calculation.
+ */
+static void touchpad_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
+	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
+
+	sw->x_abs_pos = ad714x_cal_abs_pos(ad714x, hw->x_start_stage,
+			hw->x_end_stage, sw->x_highest_stage, hw->x_max_coord);
+	sw->y_abs_pos = ad714x_cal_abs_pos(ad714x, hw->y_start_stage,
+			hw->y_end_stage, sw->y_highest_stage, hw->y_max_coord);
+
+	dev_dbg(ad714x->dev, "touchpad %d absolute position:(%d, %d)\n", idx,
+			sw->x_abs_pos, sw->y_abs_pos);
+}
+
+static void touchpad_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
+
+	sw->x_flt_pos = (sw->x_flt_pos * (10 - 4) +
+			sw->x_abs_pos * 4)/10;
+	sw->y_flt_pos = (sw->y_flt_pos * (10 - 4) +
+			sw->y_abs_pos * 4)/10;
+
+	dev_dbg(ad714x->dev, "touchpad %d filter position:(%d, %d)\n",
+			idx, sw->x_flt_pos, sw->y_flt_pos);
+}
+
+/*
+ * To prevent distortion from showing in the absolute position, it is
+ * necessary to detect the end points. When endpoints are detected, the
+ * driver stops updating the status variables with absolute positions.
+ * End points are detected on the 4 edges of the touchpad sensor. The
+ * method to detect them is the same for all 4.
+ * To detect the end points, the firmware computes the difference in
+ * percent between the sensor on the edge and the adjacent one. The
+ * difference is calculated in percent in order to make the end point
+ * detection independent of the pressure.
+ */
+
+#define LEFT_END_POINT_DETECTION_LEVEL                  550
+#define RIGHT_END_POINT_DETECTION_LEVEL                 750
+#define LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL         850
+#define TOP_END_POINT_DETECTION_LEVEL                   550
+#define BOTTOM_END_POINT_DETECTION_LEVEL                950
+#define TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL         700
+static int touchpad_check_endpoint(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
+	struct ad714x_touchpad_drv *sw  = &ad714x->sw->touchpad[idx];
+	int percent_sensor_diff;
+
+	/* left endpoint detect */
+	percent_sensor_diff = (ad714x->sensor_val[hw->x_start_stage] -
+			ad714x->sensor_val[hw->x_start_stage + 1]) * 100 /
+			ad714x->sensor_val[hw->x_start_stage + 1];
+	if (!sw->left_ep) {
+		if (percent_sensor_diff >= LEFT_END_POINT_DETECTION_LEVEL)  {
+			sw->left_ep = 1;
+			sw->left_ep_val =
+				ad714x->sensor_val[hw->x_start_stage + 1];
+		}
+	} else {
+		if ((percent_sensor_diff < LEFT_END_POINT_DETECTION_LEVEL) &&
+		    (ad714x->sensor_val[hw->x_start_stage + 1] >
+		     LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->left_ep_val))
+			sw->left_ep = 0;
+	}
+
+	/* right endpoint detect */
+	percent_sensor_diff = (ad714x->sensor_val[hw->x_end_stage] -
+			ad714x->sensor_val[hw->x_end_stage - 1]) * 100 /
+			ad714x->sensor_val[hw->x_end_stage - 1];
+	if (!sw->right_ep) {
+		if (percent_sensor_diff >= RIGHT_END_POINT_DETECTION_LEVEL)  {
+			sw->right_ep = 1;
+			sw->right_ep_val =
+				ad714x->sensor_val[hw->x_end_stage - 1];
+		}
+	} else {
+		if ((percent_sensor_diff < RIGHT_END_POINT_DETECTION_LEVEL) &&
+		(ad714x->sensor_val[hw->x_end_stage - 1] >
+		LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->right_ep_val))
+			sw->right_ep = 0;
+	}
+
+	/* top endpoint detect */
+	percent_sensor_diff = (ad714x->sensor_val[hw->y_start_stage] -
+			ad714x->sensor_val[hw->y_start_stage + 1]) * 100 /
+			ad714x->sensor_val[hw->y_start_stage + 1];
+	if (!sw->top_ep) {
+		if (percent_sensor_diff >= TOP_END_POINT_DETECTION_LEVEL)  {
+			sw->top_ep = 1;
+			sw->top_ep_val =
+				ad714x->sensor_val[hw->y_start_stage + 1];
+		}
+	} else {
+		if ((percent_sensor_diff < TOP_END_POINT_DETECTION_LEVEL) &&
+		(ad714x->sensor_val[hw->y_start_stage + 1] >
+		TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->top_ep_val))
+			sw->top_ep = 0;
+	}
+
+	/* bottom endpoint detect */
+	percent_sensor_diff = (ad714x->sensor_val[hw->y_end_stage] -
+		ad714x->sensor_val[hw->y_end_stage - 1]) * 100 /
+		ad714x->sensor_val[hw->y_end_stage - 1];
+	if (!sw->bottom_ep) {
+		if (percent_sensor_diff >= BOTTOM_END_POINT_DETECTION_LEVEL)  {
+			sw->bottom_ep = 1;
+			sw->bottom_ep_val =
+				ad714x->sensor_val[hw->y_end_stage - 1];
+		}
+	} else {
+		if ((percent_sensor_diff < BOTTOM_END_POINT_DETECTION_LEVEL) &&
+		(ad714x->sensor_val[hw->y_end_stage - 1] >
+		 TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->bottom_ep_val))
+			sw->bottom_ep = 0;
+	}
+
+	return sw->left_ep || sw->right_ep || sw->top_ep || sw->bottom_ep;
+}
+
+static void touchpad_use_com_int(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
+
+	ad714x_use_com_int(ad714x, hw->x_start_stage, hw->x_end_stage);
+}
+
+static void touchpad_use_thr_int(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
+
+	ad714x_use_thr_int(ad714x, hw->x_start_stage, hw->x_end_stage);
+	ad714x_use_thr_int(ad714x, hw->y_start_stage, hw->y_end_stage);
+}
+
+static void ad714x_touchpad_state_machine(struct ad714x_chip *ad714x, int idx)
+{
+	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
+	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
+	unsigned short h_state, c_state;
+	unsigned short mask;
+
+	mask = (((1 << (hw->x_end_stage + 1)) - 1) -
+		((1 << hw->x_start_stage) - 1)) +
+		(((1 << (hw->y_end_stage + 1)) - 1) -
+		((1 << hw->y_start_stage) - 1));
+
+	h_state = ad714x->h_state & mask;
+	c_state = ad714x->c_state & mask;
+
+	switch (sw->state) {
+	case IDLE:
+		if (h_state) {
+			sw->state = JITTER;
+			/* In End of Conversion interrupt mode, the AD714X
+			 * continuously generates hardware interrupts.
+			 */
+			touchpad_use_com_int(ad714x, idx);
+			dev_dbg(ad714x->dev, "touchpad %d touched\n", idx);
+		}
+		break;
+
+	case JITTER:
+		if (c_state == mask) {
+			touchpad_cal_sensor_val(ad714x, idx);
+			touchpad_cal_highest_stage(ad714x, idx);
+			if ((!touchpad_check_second_peak(ad714x, idx)) &&
+				(!touchpad_check_endpoint(ad714x, idx))) {
+				dev_dbg(ad714x->dev,
+					"touchpad%d, 2 fingers or endpoint\n",
+					idx);
+				touchpad_cal_abs_pos(ad714x, idx);
+				sw->x_flt_pos = sw->x_abs_pos;
+				sw->y_flt_pos = sw->y_abs_pos;
+				sw->state = ACTIVE;
+			}
+		}
+		break;
+
+	case ACTIVE:
+		if (c_state == mask) {
+			if (h_state) {
+				touchpad_cal_sensor_val(ad714x, idx);
+				touchpad_cal_highest_stage(ad714x, idx);
+				if ((!touchpad_check_second_peak(ad714x, idx))
+				  && (!touchpad_check_endpoint(ad714x, idx))) {
+					touchpad_cal_abs_pos(ad714x, idx);
+					touchpad_cal_flt_pos(ad714x, idx);
+					input_report_abs(sw->input, ABS_X,
+						sw->x_flt_pos);
+					input_report_abs(sw->input, ABS_Y,
+						sw->y_flt_pos);
+					input_report_key(sw->input, BTN_TOUCH,
+						1);
+				}
+			} else {
+				/* When the user lifts off the sensor, configure
+				 * the AD714X back to threshold interrupt mode.
+				 */
+				touchpad_use_thr_int(ad714x, idx);
+				sw->state = IDLE;
+				input_report_key(sw->input, BTN_TOUCH, 0);
+				dev_dbg(ad714x->dev, "touchpad %d released\n",
+					idx);
+			}
+			input_sync(sw->input);
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int ad714x_hw_detect(struct ad714x_chip *ad714x)
+{
+	unsigned short data;
+
+	ad714x->read(ad714x, AD714X_PARTID_REG, &data, 1);
+	switch (data & 0xFFF0) {
+	case AD7142_PARTID:
+		ad714x->product = 0x7142;
+		ad714x->version = data & 0xF;
+		dev_info(ad714x->dev, "found AD7142 captouch, rev:%d\n",
+				ad714x->version);
+		return 0;
+
+	case AD7143_PARTID:
+		ad714x->product = 0x7143;
+		ad714x->version = data & 0xF;
+		dev_info(ad714x->dev, "found AD7143 captouch, rev:%d\n",
+				ad714x->version);
+		return 0;
+
+	case AD7147_PARTID:
+		ad714x->product = 0x7147;
+		ad714x->version = data & 0xF;
+		dev_info(ad714x->dev, "found AD7147(A) captouch, rev:%d\n",
+				ad714x->version);
+		return 0;
+
+	case AD7148_PARTID:
+		ad714x->product = 0x7148;
+		ad714x->version = data & 0xF;
+		dev_info(ad714x->dev, "found AD7148 captouch, rev:%d\n",
+				ad714x->version);
+		return 0;
+
+	default:
+		dev_err(ad714x->dev,
+			"fail to detect AD714X captouch, read ID is %04x\n",
+			data);
+		return -ENODEV;
+	}
+}
+
+static void ad714x_hw_init(struct ad714x_chip *ad714x)
+{
+	int i, j;
+	unsigned short reg_base;
+	unsigned short data;
+
+	/* configuration CDC and interrupts */
+
+	for (i = 0; i < STAGE_NUM; i++) {
+		reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM;
+		for (j = 0; j < STAGE_CFGREG_NUM; j++)
+			ad714x->write(ad714x, reg_base + j,
+					ad714x->hw->stage_cfg_reg[i][j]);
+	}
+
+	for (i = 0; i < SYS_CFGREG_NUM; i++)
+		ad714x->write(ad714x, AD714X_SYSCFG_REG + i,
+			ad714x->hw->sys_cfg_reg[i]);
+	for (i = 0; i < SYS_CFGREG_NUM; i++)
+		ad714x->read(ad714x, AD714X_SYSCFG_REG + i, &data, 1);
+
+	ad714x->write(ad714x, AD714X_STG_CAL_EN_REG, 0xFFF);
+
+	/* clear all interrupts */
+	ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
+}
+
+static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
+{
+	struct ad714x_chip *ad714x = data;
+	int i;
+
+	mutex_lock(&ad714x->mutex);
+
+	ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
+
+	for (i = 0; i < ad714x->hw->button_num; i++)
+		ad714x_button_state_machine(ad714x, i);
+	for (i = 0; i < ad714x->hw->slider_num; i++)
+		ad714x_slider_state_machine(ad714x, i);
+	for (i = 0; i < ad714x->hw->wheel_num; i++)
+		ad714x_wheel_state_machine(ad714x, i);
+	for (i = 0; i < ad714x->hw->touchpad_num; i++)
+		ad714x_touchpad_state_machine(ad714x, i);
+
+	mutex_unlock(&ad714x->mutex);
+
+	return IRQ_HANDLED;
+}
+
+#define MAX_DEVICE_NUM 8
+struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
+				 ad714x_read_t read, ad714x_write_t write)
+{
+	int i, alloc_idx;
+	int error;
+	struct input_dev *input[MAX_DEVICE_NUM];
+
+	struct ad714x_platform_data *plat_data = dev->platform_data;
+	struct ad714x_chip *ad714x;
+	void *drv_mem;
+
+	struct ad714x_button_drv *bt_drv;
+	struct ad714x_slider_drv *sd_drv;
+	struct ad714x_wheel_drv *wl_drv;
+	struct ad714x_touchpad_drv *tp_drv;
+
+
+	if (irq <= 0) {
+		dev_err(dev, "IRQ not configured!\n");
+		error = -EINVAL;
+		goto err_out;
+	}
+
+	if (dev->platform_data == NULL) {
+		dev_err(dev, "platform data for ad714x doesn't exist\n");
+		error = -EINVAL;
+		goto err_out;
+	}
+
+	ad714x = kzalloc(sizeof(*ad714x) + sizeof(*ad714x->sw) +
+			 sizeof(*sd_drv) * plat_data->slider_num +
+			 sizeof(*wl_drv) * plat_data->wheel_num +
+			 sizeof(*tp_drv) * plat_data->touchpad_num +
+			 sizeof(*bt_drv) * plat_data->button_num, GFP_KERNEL);
+	if (!ad714x) {
+		error = -ENOMEM;
+		goto err_out;
+	}
+
+	ad714x->hw = plat_data;
+
+	drv_mem = ad714x + 1;
+	ad714x->sw = drv_mem;
+	drv_mem += sizeof(*ad714x->sw);
+	ad714x->sw->slider = sd_drv = drv_mem;
+	drv_mem += sizeof(*sd_drv) * ad714x->hw->slider_num;
+	ad714x->sw->wheel = wl_drv = drv_mem;
+	drv_mem += sizeof(*wl_drv) * ad714x->hw->wheel_num;
+	ad714x->sw->touchpad = tp_drv = drv_mem;
+	drv_mem += sizeof(*tp_drv) * ad714x->hw->touchpad_num;
+	ad714x->sw->button = bt_drv = drv_mem;
+	drv_mem += sizeof(*bt_drv) * ad714x->hw->button_num;
+
+	ad714x->read = read;
+	ad714x->write = write;
+	ad714x->irq = irq;
+	ad714x->dev = dev;
+
+	error = ad714x_hw_detect(ad714x);
+	if (error)
+		goto err_free_mem;
+
+	/* initialize and request sw/hw resources */
+
+	ad714x_hw_init(ad714x);
+	mutex_init(&ad714x->mutex);
+
+	/*
+	 * Allocate and register AD714X input device
+	 */
+	alloc_idx = 0;
+
+	/* a slider uses one input_dev instance */
+	if (ad714x->hw->slider_num > 0) {
+		struct ad714x_slider_plat *sd_plat = ad714x->hw->slider;
+
+		for (i = 0; i < ad714x->hw->slider_num; i++) {
+			sd_drv[i].input = input[alloc_idx] = input_allocate_device();
+			if (!input[alloc_idx]) {
+				error = -ENOMEM;
+				goto err_free_dev;
+			}
+
+			__set_bit(EV_ABS, input[alloc_idx]->evbit);
+			__set_bit(EV_KEY, input[alloc_idx]->evbit);
+			__set_bit(ABS_X, input[alloc_idx]->absbit);
+			__set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
+			input_set_abs_params(input[alloc_idx],
+				ABS_X, 0, sd_plat->max_coord, 0, 0);
+
+			input[alloc_idx]->id.bustype = bus_type;
+			input[alloc_idx]->id.product = ad714x->product;
+			input[alloc_idx]->id.version = ad714x->version;
+			input[alloc_idx]->name = "ad714x_captouch_slider";
+			input[alloc_idx]->dev.parent = dev;
+
+			error = input_register_device(input[alloc_idx]);
+			if (error)
+				goto err_free_dev;
+
+			alloc_idx++;
+		}
+	}
+
+	/* a wheel uses one input_dev instance */
+	if (ad714x->hw->wheel_num > 0) {
+		struct ad714x_wheel_plat *wl_plat = ad714x->hw->wheel;
+
+		for (i = 0; i < ad714x->hw->wheel_num; i++) {
+			wl_drv[i].input = input[alloc_idx] = input_allocate_device();
+			if (!input[alloc_idx]) {
+				error = -ENOMEM;
+				goto err_free_dev;
+			}
+
+			__set_bit(EV_KEY, input[alloc_idx]->evbit);
+			__set_bit(EV_ABS, input[alloc_idx]->evbit);
+			__set_bit(ABS_WHEEL, input[alloc_idx]->absbit);
+			__set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
+			input_set_abs_params(input[alloc_idx],
+				ABS_WHEEL, 0, wl_plat->max_coord, 0, 0);
+
+			input[alloc_idx]->id.bustype = bus_type;
+			input[alloc_idx]->id.product = ad714x->product;
+			input[alloc_idx]->id.version = ad714x->version;
+			input[alloc_idx]->name = "ad714x_captouch_wheel";
+			input[alloc_idx]->dev.parent = dev;
+
+			error = input_register_device(input[alloc_idx]);
+			if (error)
+				goto err_free_dev;
+
+			alloc_idx++;
+		}
+	}
+
+	/* a touchpad uses one input_dev instance */
+	if (ad714x->hw->touchpad_num > 0) {
+		struct ad714x_touchpad_plat *tp_plat = ad714x->hw->touchpad;
+
+		for (i = 0; i < ad714x->hw->touchpad_num; i++) {
+			tp_drv[i].input = input[alloc_idx] = input_allocate_device();
+			if (!input[alloc_idx]) {
+				error = -ENOMEM;
+				goto err_free_dev;
+			}
+
+			__set_bit(EV_ABS, input[alloc_idx]->evbit);
+			__set_bit(EV_KEY, input[alloc_idx]->evbit);
+			__set_bit(ABS_X, input[alloc_idx]->absbit);
+			__set_bit(ABS_Y, input[alloc_idx]->absbit);
+			__set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
+			input_set_abs_params(input[alloc_idx],
+				ABS_X, 0, tp_plat->x_max_coord, 0, 0);
+			input_set_abs_params(input[alloc_idx],
+				ABS_Y, 0, tp_plat->y_max_coord, 0, 0);
+
+			input[alloc_idx]->id.bustype = bus_type;
+			input[alloc_idx]->id.product = ad714x->product;
+			input[alloc_idx]->id.version = ad714x->version;
+			input[alloc_idx]->name = "ad714x_captouch_pad";
+			input[alloc_idx]->dev.parent = dev;
+
+			error = input_register_device(input[alloc_idx]);
+			if (error)
+				goto err_free_dev;
+
+			alloc_idx++;
+		}
+	}
+
+	/* all buttons use one input node */
+	if (ad714x->hw->button_num > 0) {
+		struct ad714x_button_plat *bt_plat = ad714x->hw->button;
+
+		input[alloc_idx] = input_allocate_device();
+		if (!input[alloc_idx]) {
+			error = -ENOMEM;
+			goto err_free_dev;
+		}
+
+		__set_bit(EV_KEY, input[alloc_idx]->evbit);
+		for (i = 0; i < ad714x->hw->button_num; i++) {
+			bt_drv[i].input = input[alloc_idx];
+			__set_bit(bt_plat[i].keycode, input[alloc_idx]->keybit);
+		}
+
+		input[alloc_idx]->id.bustype = bus_type;
+		input[alloc_idx]->id.product = ad714x->product;
+		input[alloc_idx]->id.version = ad714x->version;
+		input[alloc_idx]->name = "ad714x_captouch_button";
+		input[alloc_idx]->dev.parent = dev;
+
+		error = input_register_device(input[alloc_idx]);
+		if (error)
+			goto err_free_dev;
+
+		alloc_idx++;
+	}
+
+	error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread,
+				plat_data->irqflags ?
+					plat_data->irqflags : IRQF_TRIGGER_FALLING,
+				"ad714x_captouch", ad714x);
+	if (error) {
+		dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
+		goto err_unreg_dev;
+	}
+
+	return ad714x;
+
+ err_free_dev:
+	dev_err(dev, "failed to setup AD714x input device %i\n", alloc_idx);
+	input_free_device(input[alloc_idx]);
+ err_unreg_dev:
+	while (--alloc_idx >= 0)
+		input_unregister_device(input[alloc_idx]);
+ err_free_mem:
+	kfree(ad714x);
+ err_out:
+	return ERR_PTR(error);
+}
+EXPORT_SYMBOL(ad714x_probe);
+
+void ad714x_remove(struct ad714x_chip *ad714x)
+{
+	struct ad714x_platform_data *hw = ad714x->hw;
+	struct ad714x_driver_data *sw = ad714x->sw;
+	int i;
+
+	free_irq(ad714x->irq, ad714x);
+
+	/* unregister and free all input devices */
+
+	for (i = 0; i < hw->slider_num; i++)
+		input_unregister_device(sw->slider[i].input);
+
+	for (i = 0; i < hw->wheel_num; i++)
+		input_unregister_device(sw->wheel[i].input);
+
+	for (i = 0; i < hw->touchpad_num; i++)
+		input_unregister_device(sw->touchpad[i].input);
+
+	if (hw->button_num)
+		input_unregister_device(sw->button[0].input);
+
+	kfree(ad714x);
+}
+EXPORT_SYMBOL(ad714x_remove);
+
+#ifdef CONFIG_PM
+int ad714x_disable(struct ad714x_chip *ad714x)
+{
+	unsigned short data;
+
+	dev_dbg(ad714x->dev, "%s enter\n", __func__);
+
+	mutex_lock(&ad714x->mutex);
+
+	data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3;
+	ad714x->write(ad714x, AD714X_PWR_CTRL, data);
+
+	mutex_unlock(&ad714x->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ad714x_disable);
+
+int ad714x_enable(struct ad714x_chip *ad714x)
+{
+	dev_dbg(ad714x->dev, "%s enter\n", __func__);
+
+	mutex_lock(&ad714x->mutex);
+
+	/* resume to non-shutdown mode */
+
+	ad714x->write(ad714x, AD714X_PWR_CTRL,
+			ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL]);
+
+	/* make sure the interrupt output line is not low level after resume,
+	 * otherwise we will get no chance to enter falling-edge irq again
+	 */
+
+	ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
+
+	mutex_unlock(&ad714x->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ad714x_enable);
+#endif
+
+MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor Driver");
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x.h b/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x.h
new file mode 100644
index 0000000..3c85455
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/ad714x.h
@@ -0,0 +1,55 @@
+/*
+ * AD714X CapTouch Programmable Controller driver (bus interfaces)
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _AD714X_H_
+#define _AD714X_H_
+
+#include <linux/types.h>
+
+#define STAGE_NUM              12
+
+struct device;
+struct ad714x_platform_data;
+struct ad714x_driver_data;
+struct ad714x_chip;
+
+typedef int (*ad714x_read_t)(struct ad714x_chip *, unsigned short, unsigned short *, size_t);
+typedef int (*ad714x_write_t)(struct ad714x_chip *, unsigned short, unsigned short);
+
+struct ad714x_chip {
+	unsigned short l_state;
+	unsigned short h_state;
+	unsigned short c_state;
+	unsigned short adc_reg[STAGE_NUM];
+	unsigned short amb_reg[STAGE_NUM];
+	unsigned short sensor_val[STAGE_NUM];
+
+	struct ad714x_platform_data *hw;
+	struct ad714x_driver_data *sw;
+
+	int irq;
+	struct device *dev;
+	ad714x_read_t read;
+	ad714x_write_t write;
+
+	struct mutex mutex;
+
+	unsigned product;
+	unsigned version;
+
+	__be16 xfer_buf[16] ____cacheline_aligned;
+
+};
+
+int ad714x_disable(struct ad714x_chip *ad714x);
+int ad714x_enable(struct ad714x_chip *ad714x);
+struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
+				 ad714x_read_t read, ad714x_write_t write);
+void ad714x_remove(struct ad714x_chip *ad714x);
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x-i2c.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x-i2c.c
new file mode 100644
index 0000000..dd1d1c1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x-i2c.c
@@ -0,0 +1,155 @@
+/*
+ * ADLX345/346 Three-Axis Digital Accelerometers (I2C Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_I2C */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pm.h>
+#include "adxl34x.h"
+
+static int adxl34x_smbus_read(struct device *dev, unsigned char reg)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int adxl34x_smbus_write(struct device *dev,
+			       unsigned char reg, unsigned char val)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int adxl34x_smbus_read_block(struct device *dev,
+				    unsigned char reg, int count,
+				    void *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_read_i2c_block_data(client, reg, count, buf);
+}
+
+static int adxl34x_i2c_read_block(struct device *dev,
+				  unsigned char reg, int count,
+				  void *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int ret;
+
+	ret = i2c_master_send(client, &reg, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_master_recv(client, buf, count);
+	if (ret < 0)
+		return ret;
+
+	if (ret != count)
+		return -EIO;
+
+	return 0;
+}
+
+static const struct adxl34x_bus_ops adxl34x_smbus_bops = {
+	.bustype	= BUS_I2C,
+	.write		= adxl34x_smbus_write,
+	.read		= adxl34x_smbus_read,
+	.read_block	= adxl34x_smbus_read_block,
+};
+
+static const struct adxl34x_bus_ops adxl34x_i2c_bops = {
+	.bustype	= BUS_I2C,
+	.write		= adxl34x_smbus_write,
+	.read		= adxl34x_smbus_read,
+	.read_block	= adxl34x_i2c_read_block,
+};
+
+static int __devinit adxl34x_i2c_probe(struct i2c_client *client,
+				       const struct i2c_device_id *id)
+{
+	struct adxl34x *ac;
+	int error;
+
+	error = i2c_check_functionality(client->adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA);
+	if (!error) {
+		dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+		return -EIO;
+	}
+
+	ac = adxl34x_probe(&client->dev, client->irq, false,
+			   i2c_check_functionality(client->adapter,
+						   I2C_FUNC_SMBUS_READ_I2C_BLOCK) ?
+				&adxl34x_smbus_bops : &adxl34x_i2c_bops);
+	if (IS_ERR(ac))
+		return PTR_ERR(ac);
+
+	i2c_set_clientdata(client, ac);
+
+	return 0;
+}
+
+static int __devexit adxl34x_i2c_remove(struct i2c_client *client)
+{
+	struct adxl34x *ac = i2c_get_clientdata(client);
+
+	return adxl34x_remove(ac);
+}
+
+#ifdef CONFIG_PM
+static int adxl34x_i2c_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adxl34x *ac = i2c_get_clientdata(client);
+
+	adxl34x_suspend(ac);
+
+	return 0;
+}
+
+static int adxl34x_i2c_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adxl34x *ac = i2c_get_clientdata(client);
+
+	adxl34x_resume(ac);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(adxl34x_i2c_pm, adxl34x_i2c_suspend,
+			 adxl34x_i2c_resume);
+
+static const struct i2c_device_id adxl34x_id[] = {
+	{ "adxl34x", 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, adxl34x_id);
+
+static struct i2c_driver adxl34x_driver = {
+	.driver = {
+		.name = "adxl34x",
+		.owner = THIS_MODULE,
+		.pm = &adxl34x_i2c_pm,
+	},
+	.probe    = adxl34x_i2c_probe,
+	.remove   = __devexit_p(adxl34x_i2c_remove),
+	.id_table = adxl34x_id,
+};
+
+module_i2c_driver(adxl34x_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x-spi.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x-spi.c
new file mode 100644
index 0000000..820a802
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x-spi.c
@@ -0,0 +1,136 @@
+/*
+ * ADLX345/346 Three-Axis Digital Accelerometers (SPI Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_SPI */
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/pm.h>
+#include <linux/types.h>
+#include "adxl34x.h"
+
+#define MAX_SPI_FREQ_HZ		5000000
+#define MAX_FREQ_NO_FIFODELAY	1500000
+#define ADXL34X_CMD_MULTB	(1 << 6)
+#define ADXL34X_CMD_READ	(1 << 7)
+#define ADXL34X_WRITECMD(reg)	(reg & 0x3F)
+#define ADXL34X_READCMD(reg)	(ADXL34X_CMD_READ | (reg & 0x3F))
+#define ADXL34X_READMB_CMD(reg) (ADXL34X_CMD_READ | ADXL34X_CMD_MULTB \
+					| (reg & 0x3F))
+
+static int adxl34x_spi_read(struct device *dev, unsigned char reg)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	unsigned char cmd;
+
+	cmd = ADXL34X_READCMD(reg);
+
+	return spi_w8r8(spi, cmd);
+}
+
+static int adxl34x_spi_write(struct device *dev,
+			     unsigned char reg, unsigned char val)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	unsigned char buf[2];
+
+	buf[0] = ADXL34X_WRITECMD(reg);
+	buf[1] = val;
+
+	return spi_write(spi, buf, sizeof(buf));
+}
+
+static int adxl34x_spi_read_block(struct device *dev,
+				  unsigned char reg, int count,
+				  void *buf)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	ssize_t status;
+
+	reg = ADXL34X_READMB_CMD(reg);
+	status = spi_write_then_read(spi, &reg, 1, buf, count);
+
+	return (status < 0) ? status : 0;
+}
+
+static const struct adxl34x_bus_ops adxl34x_spi_bops = {
+	.bustype	= BUS_SPI,
+	.write		= adxl34x_spi_write,
+	.read		= adxl34x_spi_read,
+	.read_block	= adxl34x_spi_read_block,
+};
+
+static int __devinit adxl34x_spi_probe(struct spi_device *spi)
+{
+	struct adxl34x *ac;
+
+	/* don't exceed max specified SPI CLK frequency */
+	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+		dev_err(&spi->dev, "SPI CLK %d Hz too fast\n", spi->max_speed_hz);
+		return -EINVAL;
+	}
+
+	ac = adxl34x_probe(&spi->dev, spi->irq,
+			   spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY,
+			   &adxl34x_spi_bops);
+
+	if (IS_ERR(ac))
+		return PTR_ERR(ac);
+
+	spi_set_drvdata(spi, ac);
+
+	return 0;
+}
+
+static int __devexit adxl34x_spi_remove(struct spi_device *spi)
+{
+	struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+	return adxl34x_remove(ac);
+}
+
+#ifdef CONFIG_PM
+static int adxl34x_spi_suspend(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+	adxl34x_suspend(ac);
+
+	return 0;
+}
+
+static int adxl34x_spi_resume(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+	adxl34x_resume(ac);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(adxl34x_spi_pm, adxl34x_spi_suspend,
+			 adxl34x_spi_resume);
+
+static struct spi_driver adxl34x_driver = {
+	.driver = {
+		.name = "adxl34x",
+		.owner = THIS_MODULE,
+		.pm = &adxl34x_spi_pm,
+	},
+	.probe   = adxl34x_spi_probe,
+	.remove  = __devexit_p(adxl34x_spi_remove),
+};
+
+module_spi_driver(adxl34x_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x.c
new file mode 100644
index 0000000..1cf72fe
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x.c
@@ -0,0 +1,915 @@
+/*
+ * ADXL345/346 Three-Axis Digital Accelerometers
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/input/adxl34x.h>
+#include <linux/module.h>
+
+#include "adxl34x.h"
+
+/* ADXL345/6 Register Map */
+#define DEVID		0x00	/* R   Device ID */
+#define THRESH_TAP	0x1D	/* R/W Tap threshold */
+#define OFSX		0x1E	/* R/W X-axis offset */
+#define OFSY		0x1F	/* R/W Y-axis offset */
+#define OFSZ		0x20	/* R/W Z-axis offset */
+#define DUR		0x21	/* R/W Tap duration */
+#define LATENT		0x22	/* R/W Tap latency */
+#define WINDOW		0x23	/* R/W Tap window */
+#define THRESH_ACT	0x24	/* R/W Activity threshold */
+#define THRESH_INACT	0x25	/* R/W Inactivity threshold */
+#define TIME_INACT	0x26	/* R/W Inactivity time */
+#define ACT_INACT_CTL	0x27	/* R/W Axis enable control for activity and */
+				/* inactivity detection */
+#define THRESH_FF	0x28	/* R/W Free-fall threshold */
+#define TIME_FF		0x29	/* R/W Free-fall time */
+#define TAP_AXES	0x2A	/* R/W Axis control for tap/double tap */
+#define ACT_TAP_STATUS	0x2B	/* R   Source of tap/double tap */
+#define BW_RATE		0x2C	/* R/W Data rate and power mode control */
+#define POWER_CTL	0x2D	/* R/W Power saving features control */
+#define INT_ENABLE	0x2E	/* R/W Interrupt enable control */
+#define INT_MAP		0x2F	/* R/W Interrupt mapping control */
+#define INT_SOURCE	0x30	/* R   Source of interrupts */
+#define DATA_FORMAT	0x31	/* R/W Data format control */
+#define DATAX0		0x32	/* R   X-Axis Data 0 */
+#define DATAX1		0x33	/* R   X-Axis Data 1 */
+#define DATAY0		0x34	/* R   Y-Axis Data 0 */
+#define DATAY1		0x35	/* R   Y-Axis Data 1 */
+#define DATAZ0		0x36	/* R   Z-Axis Data 0 */
+#define DATAZ1		0x37	/* R   Z-Axis Data 1 */
+#define FIFO_CTL	0x38	/* R/W FIFO control */
+#define FIFO_STATUS	0x39	/* R   FIFO status */
+#define TAP_SIGN	0x3A	/* R   Sign and source for tap/double tap */
+/* Orientation ADXL346 only */
+#define ORIENT_CONF	0x3B	/* R/W Orientation configuration */
+#define ORIENT		0x3C	/* R   Orientation status */
+
+/* DEVIDs */
+#define ID_ADXL345	0xE5
+#define ID_ADXL346	0xE6
+
+/* INT_ENABLE/INT_MAP/INT_SOURCE Bits */
+#define DATA_READY	(1 << 7)
+#define SINGLE_TAP	(1 << 6)
+#define DOUBLE_TAP	(1 << 5)
+#define ACTIVITY	(1 << 4)
+#define INACTIVITY	(1 << 3)
+#define FREE_FALL	(1 << 2)
+#define WATERMARK	(1 << 1)
+#define OVERRUN		(1 << 0)
+
+/* ACT_INACT_CONTROL Bits */
+#define ACT_ACDC	(1 << 7)
+#define ACT_X_EN	(1 << 6)
+#define ACT_Y_EN	(1 << 5)
+#define ACT_Z_EN	(1 << 4)
+#define INACT_ACDC	(1 << 3)
+#define INACT_X_EN	(1 << 2)
+#define INACT_Y_EN	(1 << 1)
+#define INACT_Z_EN	(1 << 0)
+
+/* TAP_AXES Bits */
+#define SUPPRESS	(1 << 3)
+#define TAP_X_EN	(1 << 2)
+#define TAP_Y_EN	(1 << 1)
+#define TAP_Z_EN	(1 << 0)
+
+/* ACT_TAP_STATUS Bits */
+#define ACT_X_SRC	(1 << 6)
+#define ACT_Y_SRC	(1 << 5)
+#define ACT_Z_SRC	(1 << 4)
+#define ASLEEP		(1 << 3)
+#define TAP_X_SRC	(1 << 2)
+#define TAP_Y_SRC	(1 << 1)
+#define TAP_Z_SRC	(1 << 0)
+
+/* BW_RATE Bits */
+#define LOW_POWER	(1 << 4)
+#define RATE(x)		((x) & 0xF)
+
+/* POWER_CTL Bits */
+#define PCTL_LINK	(1 << 5)
+#define PCTL_AUTO_SLEEP (1 << 4)
+#define PCTL_MEASURE	(1 << 3)
+#define PCTL_SLEEP	(1 << 2)
+#define PCTL_WAKEUP(x)	((x) & 0x3)
+
+/* DATA_FORMAT Bits */
+#define SELF_TEST	(1 << 7)
+#define SPI		(1 << 6)
+#define INT_INVERT	(1 << 5)
+#define FULL_RES	(1 << 3)
+#define JUSTIFY		(1 << 2)
+#define RANGE(x)	((x) & 0x3)
+#define RANGE_PM_2g	0
+#define RANGE_PM_4g	1
+#define RANGE_PM_8g	2
+#define RANGE_PM_16g	3
+
+/*
+ * Maximum value our axis may get in full res mode for the input device
+ * (signed 13 bits)
+ */
+#define ADXL_FULLRES_MAX_VAL 4096
+
+/*
+ * Maximum value our axis may get in fixed res mode for the input device
+ * (signed 10 bits)
+ */
+#define ADXL_FIXEDRES_MAX_VAL 512
+
+/* FIFO_CTL Bits */
+#define FIFO_MODE(x)	(((x) & 0x3) << 6)
+#define FIFO_BYPASS	0
+#define FIFO_FIFO	1
+#define FIFO_STREAM	2
+#define FIFO_TRIGGER	3
+#define TRIGGER		(1 << 5)
+#define SAMPLES(x)	((x) & 0x1F)
+
+/* FIFO_STATUS Bits */
+#define FIFO_TRIG	(1 << 7)
+#define ENTRIES(x)	((x) & 0x3F)
+
+/* TAP_SIGN Bits ADXL346 only */
+#define XSIGN		(1 << 6)
+#define YSIGN		(1 << 5)
+#define ZSIGN		(1 << 4)
+#define XTAP		(1 << 3)
+#define YTAP		(1 << 2)
+#define ZTAP		(1 << 1)
+
+/* ORIENT_CONF ADXL346 only */
+#define ORIENT_DEADZONE(x)	(((x) & 0x7) << 4)
+#define ORIENT_DIVISOR(x)	((x) & 0x7)
+
+/* ORIENT ADXL346 only */
+#define ADXL346_2D_VALID		(1 << 6)
+#define ADXL346_2D_ORIENT(x)		(((x) & 0x3) >> 4)
+#define ADXL346_3D_VALID		(1 << 3)
+#define ADXL346_3D_ORIENT(x)		((x) & 0x7)
+#define ADXL346_2D_PORTRAIT_POS		0	/* +X */
+#define ADXL346_2D_PORTRAIT_NEG		1	/* -X */
+#define ADXL346_2D_LANDSCAPE_POS	2	/* +Y */
+#define ADXL346_2D_LANDSCAPE_NEG	3	/* -Y */
+
+#define ADXL346_3D_FRONT		3	/* +X */
+#define ADXL346_3D_BACK			4	/* -X */
+#define ADXL346_3D_RIGHT		2	/* +Y */
+#define ADXL346_3D_LEFT			5	/* -Y */
+#define ADXL346_3D_TOP			1	/* +Z */
+#define ADXL346_3D_BOTTOM		6	/* -Z */
+
+#undef ADXL_DEBUG
+
+#define ADXL_X_AXIS			0
+#define ADXL_Y_AXIS			1
+#define ADXL_Z_AXIS			2
+
+#define AC_READ(ac, reg)	((ac)->bops->read((ac)->dev, reg))
+#define AC_WRITE(ac, reg, val)	((ac)->bops->write((ac)->dev, reg, val))
+
+struct axis_triple {
+	int x;
+	int y;
+	int z;
+};
+
+struct adxl34x {
+	struct device *dev;
+	struct input_dev *input;
+	struct mutex mutex;	/* reentrant protection for struct */
+	struct adxl34x_platform_data pdata;
+	struct axis_triple swcal;
+	struct axis_triple hwcal;
+	struct axis_triple saved;
+	char phys[32];
+	unsigned orient2d_saved;
+	unsigned orient3d_saved;
+	bool disabled;	/* P: mutex */
+	bool opened;	/* P: mutex */
+	bool suspended;	/* P: mutex */
+	bool fifo_delay;
+	int irq;
+	unsigned model;
+	unsigned int_mask;
+
+	const struct adxl34x_bus_ops *bops;
+};
+
+static const struct adxl34x_platform_data adxl34x_default_init = {
+	.tap_threshold = 35,
+	.tap_duration = 3,
+	.tap_latency = 20,
+	.tap_window = 20,
+	.tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN,
+	.act_axis_control = 0xFF,
+	.activity_threshold = 6,
+	.inactivity_threshold = 4,
+	.inactivity_time = 3,
+	.free_fall_threshold = 8,
+	.free_fall_time = 0x20,
+	.data_rate = 8,
+	.data_range = ADXL_FULL_RES,
+
+	.ev_type = EV_ABS,
+	.ev_code_x = ABS_X,	/* EV_REL */
+	.ev_code_y = ABS_Y,	/* EV_REL */
+	.ev_code_z = ABS_Z,	/* EV_REL */
+
+	.ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY {x,y,z} */
+	.power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
+	.fifo_mode = FIFO_STREAM,
+	.watermark = 0,
+};
+
+static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
+{
+	short buf[3];
+
+	ac->bops->read_block(ac->dev, DATAX0, DATAZ1 - DATAX0 + 1, buf);
+
+	mutex_lock(&ac->mutex);
+	ac->saved.x = (s16) le16_to_cpu(buf[0]);
+	axis->x = ac->saved.x;
+
+	ac->saved.y = (s16) le16_to_cpu(buf[1]);
+	axis->y = ac->saved.y;
+
+	ac->saved.z = (s16) le16_to_cpu(buf[2]);
+	axis->z = ac->saved.z;
+	mutex_unlock(&ac->mutex);
+}
+
+static void adxl34x_service_ev_fifo(struct adxl34x *ac)
+{
+	struct adxl34x_platform_data *pdata = &ac->pdata;
+	struct axis_triple axis;
+
+	adxl34x_get_triple(ac, &axis);
+
+	input_event(ac->input, pdata->ev_type, pdata->ev_code_x,
+		    axis.x - ac->swcal.x);
+	input_event(ac->input, pdata->ev_type, pdata->ev_code_y,
+		    axis.y - ac->swcal.y);
+	input_event(ac->input, pdata->ev_type, pdata->ev_code_z,
+		    axis.z - ac->swcal.z);
+}
+
+static void adxl34x_report_key_single(struct input_dev *input, int key)
+{
+	input_report_key(input, key, true);
+	input_sync(input);
+	input_report_key(input, key, false);
+}
+
+static void adxl34x_send_key_events(struct adxl34x *ac,
+		struct adxl34x_platform_data *pdata, int status, int press)
+{
+	int i;
+
+	for (i = ADXL_X_AXIS; i <= ADXL_Z_AXIS; i++) {
+		if (status & (1 << (ADXL_Z_AXIS - i)))
+			input_report_key(ac->input,
+					 pdata->ev_code_tap[i], press);
+	}
+}
+
+static void adxl34x_do_tap(struct adxl34x *ac,
+		struct adxl34x_platform_data *pdata, int status)
+{
+	adxl34x_send_key_events(ac, pdata, status, true);
+	input_sync(ac->input);
+	adxl34x_send_key_events(ac, pdata, status, false);
+}
+
+static irqreturn_t adxl34x_irq(int irq, void *handle)
+{
+	struct adxl34x *ac = handle;
+	struct adxl34x_platform_data *pdata = &ac->pdata;
+	int int_stat, tap_stat, samples, orient, orient_code;
+
+	/*
+	 * ACT_TAP_STATUS should be read before clearing the interrupt
+	 * Avoid reading ACT_TAP_STATUS in case TAP detection is disabled
+	 */
+
+	if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
+		tap_stat = AC_READ(ac, ACT_TAP_STATUS);
+	else
+		tap_stat = 0;
+
+	int_stat = AC_READ(ac, INT_SOURCE);
+
+	if (int_stat & FREE_FALL)
+		adxl34x_report_key_single(ac->input, pdata->ev_code_ff);
+
+	if (int_stat & OVERRUN)
+		dev_dbg(ac->dev, "OVERRUN\n");
+
+	if (int_stat & (SINGLE_TAP | DOUBLE_TAP)) {
+		adxl34x_do_tap(ac, pdata, tap_stat);
+
+		if (int_stat & DOUBLE_TAP)
+			adxl34x_do_tap(ac, pdata, tap_stat);
+	}
+
+	if (pdata->ev_code_act_inactivity) {
+		if (int_stat & ACTIVITY)
+			input_report_key(ac->input,
+					 pdata->ev_code_act_inactivity, 1);
+		if (int_stat & INACTIVITY)
+			input_report_key(ac->input,
+					 pdata->ev_code_act_inactivity, 0);
+	}
+
+	/*
+	 * ORIENTATION SENSING ADXL346 only
+	 */
+	if (pdata->orientation_enable) {
+		orient = AC_READ(ac, ORIENT);
+		if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_2D) &&
+		    (orient & ADXL346_2D_VALID)) {
+
+			orient_code = ADXL346_2D_ORIENT(orient);
+			/* Report orientation only when it changes */
+			if (ac->orient2d_saved != orient_code) {
+				ac->orient2d_saved = orient_code;
+				adxl34x_report_key_single(ac->input,
+					pdata->ev_codes_orient_2d[orient_code]);
+			}
+		}
+
+		if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_3D) &&
+		    (orient & ADXL346_3D_VALID)) {
+
+			orient_code = ADXL346_3D_ORIENT(orient) - 1;
+			/* Report orientation only when it changes */
+			if (ac->orient3d_saved != orient_code) {
+				ac->orient3d_saved = orient_code;
+				adxl34x_report_key_single(ac->input,
+					pdata->ev_codes_orient_3d[orient_code]);
+			}
+		}
+	}
+
+	if (int_stat & (DATA_READY | WATERMARK)) {
+
+		if (pdata->fifo_mode)
+			samples = ENTRIES(AC_READ(ac, FIFO_STATUS)) + 1;
+		else
+			samples = 1;
+
+		for (; samples > 0; samples--) {
+			adxl34x_service_ev_fifo(ac);
+			/*
+			 * To ensure that the FIFO has
+			 * completely popped, there must be at least 5 us between
+			 * the end of reading the data registers, signified by the
+			 * transition to register 0x38 from 0x37 or the CS pin
+			 * going high, and the start of new reads of the FIFO or
+			 * reading the FIFO_STATUS register. For SPI operation at
+			 * 1.5 MHz or lower, the register addressing portion of the
+			 * transmission is sufficient delay to ensure the FIFO has
+			 * completely popped. It is necessary for SPI operation
+			 * greater than 1.5 MHz to de-assert the CS pin to ensure a
+			 * total of 5 us, which is at most 3.4 us at 5 MHz
+			 * operation.
+			 */
+			if (ac->fifo_delay && (samples > 1))
+				udelay(3);
+		}
+	}
+
+	input_sync(ac->input);
+
+	return IRQ_HANDLED;
+}
+
+static void __adxl34x_disable(struct adxl34x *ac)
+{
+	/*
+	 * A '0' places the ADXL34x into standby mode
+	 * with minimum power consumption.
+	 */
+	AC_WRITE(ac, POWER_CTL, 0);
+}
+
+static void __adxl34x_enable(struct adxl34x *ac)
+{
+	AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
+}
+
+void adxl34x_suspend(struct adxl34x *ac)
+{
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && !ac->disabled && ac->opened)
+		__adxl34x_disable(ac);
+
+	ac->suspended = true;
+
+	mutex_unlock(&ac->mutex);
+}
+EXPORT_SYMBOL_GPL(adxl34x_suspend);
+
+void adxl34x_resume(struct adxl34x *ac)
+{
+	mutex_lock(&ac->mutex);
+
+	if (ac->suspended && !ac->disabled && ac->opened)
+		__adxl34x_enable(ac);
+
+	ac->suspended = false;
+
+	mutex_unlock(&ac->mutex);
+}
+EXPORT_SYMBOL_GPL(adxl34x_resume);
+
+static ssize_t adxl34x_disable_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ac->disabled);
+}
+
+static ssize_t adxl34x_disable_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned int val;
+	int error;
+
+	error = kstrtouint(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && ac->opened) {
+		if (val) {
+			if (!ac->disabled)
+				__adxl34x_disable(ac);
+		} else {
+			if (ac->disabled)
+				__adxl34x_enable(ac);
+		}
+	}
+
+	ac->disabled = !!val;
+
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(disable, 0664, adxl34x_disable_show, adxl34x_disable_store);
+
+static ssize_t adxl34x_calibrate_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	ssize_t count;
+
+	mutex_lock(&ac->mutex);
+	count = sprintf(buf, "%d,%d,%d\n",
+			ac->hwcal.x * 4 + ac->swcal.x,
+			ac->hwcal.y * 4 + ac->swcal.y,
+			ac->hwcal.z * 4 + ac->swcal.z);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static ssize_t adxl34x_calibrate_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	/*
+	 * Hardware offset calibration has a resolution of 15.6 mg/LSB.
+	 * We use HW calibration and handle the remaining bits in SW. (4mg/LSB)
+	 */
+
+	mutex_lock(&ac->mutex);
+	ac->hwcal.x -= (ac->saved.x / 4);
+	ac->swcal.x = ac->saved.x % 4;
+
+	ac->hwcal.y -= (ac->saved.y / 4);
+	ac->swcal.y = ac->saved.y % 4;
+
+	ac->hwcal.z -= (ac->saved.z / 4);
+	ac->swcal.z = ac->saved.z % 4;
+
+	AC_WRITE(ac, OFSX, (s8) ac->hwcal.x);
+	AC_WRITE(ac, OFSY, (s8) ac->hwcal.y);
+	AC_WRITE(ac, OFSZ, (s8) ac->hwcal.z);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(calibrate, 0664,
+		   adxl34x_calibrate_show, adxl34x_calibrate_store);
+
+static ssize_t adxl34x_rate_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", RATE(ac->pdata.data_rate));
+}
+
+static ssize_t adxl34x_rate_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned char val;
+	int error;
+
+	error = kstrtou8(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+
+	ac->pdata.data_rate = RATE(val);
+	AC_WRITE(ac, BW_RATE,
+		 ac->pdata.data_rate |
+			(ac->pdata.low_power_mode ? LOW_POWER : 0));
+
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(rate, 0664, adxl34x_rate_show, adxl34x_rate_store);
+
+static ssize_t adxl34x_autosleep_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n",
+		ac->pdata.power_mode & (PCTL_AUTO_SLEEP | PCTL_LINK) ? 1 : 0);
+}
+
+static ssize_t adxl34x_autosleep_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned int val;
+	int error;
+
+	error = kstrtouint(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+
+	if (val)
+		ac->pdata.power_mode |= (PCTL_AUTO_SLEEP | PCTL_LINK);
+	else
+		ac->pdata.power_mode &= ~(PCTL_AUTO_SLEEP | PCTL_LINK);
+
+	if (!ac->disabled && !ac->suspended && ac->opened)
+		AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
+
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(autosleep, 0664,
+		   adxl34x_autosleep_show, adxl34x_autosleep_store);
+
+static ssize_t adxl34x_position_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	ssize_t count;
+
+	mutex_lock(&ac->mutex);
+	count = sprintf(buf, "(%d, %d, %d)\n",
+			ac->saved.x, ac->saved.y, ac->saved.z);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(position, S_IRUGO, adxl34x_position_show, NULL);
+
+#ifdef ADXL_DEBUG
+static ssize_t adxl34x_write_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned int val;
+	int error;
+
+	/*
+	 * This allows basic ADXL register write access for debug purposes.
+	 */
+	error = kstrtouint(buf, 16, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+	AC_WRITE(ac, val >> 8, val & 0xFF);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(write, 0664, NULL, adxl34x_write_store);
+#endif
+
+static struct attribute *adxl34x_attributes[] = {
+	&dev_attr_disable.attr,
+	&dev_attr_calibrate.attr,
+	&dev_attr_rate.attr,
+	&dev_attr_autosleep.attr,
+	&dev_attr_position.attr,
+#ifdef ADXL_DEBUG
+	&dev_attr_write.attr,
+#endif
+	NULL
+};
+
+static const struct attribute_group adxl34x_attr_group = {
+	.attrs = adxl34x_attributes,
+};
+
+static int adxl34x_input_open(struct input_dev *input)
+{
+	struct adxl34x *ac = input_get_drvdata(input);
+
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && !ac->disabled)
+		__adxl34x_enable(ac);
+
+	ac->opened = true;
+
+	mutex_unlock(&ac->mutex);
+
+	return 0;
+}
+
+static void adxl34x_input_close(struct input_dev *input)
+{
+	struct adxl34x *ac = input_get_drvdata(input);
+
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && !ac->disabled)
+		__adxl34x_disable(ac);
+
+	ac->opened = false;
+
+	mutex_unlock(&ac->mutex);
+}
+
+struct adxl34x *adxl34x_probe(struct device *dev, int irq,
+			      bool fifo_delay_default,
+			      const struct adxl34x_bus_ops *bops)
+{
+	struct adxl34x *ac;
+	struct input_dev *input_dev;
+	const struct adxl34x_platform_data *pdata;
+	int err, range, i;
+	unsigned char revid;
+
+	if (!irq) {
+		dev_err(dev, "no IRQ?\n");
+		err = -ENODEV;
+		goto err_out;
+	}
+
+	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ac || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ac->fifo_delay = fifo_delay_default;
+
+	pdata = dev->platform_data;
+	if (!pdata) {
+		dev_dbg(dev,
+			"No platform data: Using default initialization\n");
+		pdata = &adxl34x_default_init;
+	}
+
+	ac->pdata = *pdata;
+	pdata = &ac->pdata;
+
+	ac->input = input_dev;
+	ac->dev = dev;
+	ac->irq = irq;
+	ac->bops = bops;
+
+	mutex_init(&ac->mutex);
+
+	input_dev->name = "ADXL34x accelerometer";
+	revid = ac->bops->read(dev, DEVID);
+
+	switch (revid) {
+	case ID_ADXL345:
+		ac->model = 345;
+		break;
+	case ID_ADXL346:
+		ac->model = 346;
+		break;
+	default:
+		dev_err(dev, "Failed to probe %s\n", input_dev->name);
+		err = -ENODEV;
+		goto err_free_mem;
+	}
+
+	snprintf(ac->phys, sizeof(ac->phys), "%s/input0", dev_name(dev));
+
+	input_dev->phys = ac->phys;
+	input_dev->dev.parent = dev;
+	input_dev->id.product = ac->model;
+	input_dev->id.bustype = bops->bustype;
+	input_dev->open = adxl34x_input_open;
+	input_dev->close = adxl34x_input_close;
+
+	input_set_drvdata(input_dev, ac);
+
+	__set_bit(ac->pdata.ev_type, input_dev->evbit);
+
+	if (ac->pdata.ev_type == EV_REL) {
+		__set_bit(REL_X, input_dev->relbit);
+		__set_bit(REL_Y, input_dev->relbit);
+		__set_bit(REL_Z, input_dev->relbit);
+	} else {
+		/* EV_ABS */
+		__set_bit(ABS_X, input_dev->absbit);
+		__set_bit(ABS_Y, input_dev->absbit);
+		__set_bit(ABS_Z, input_dev->absbit);
+
+		if (pdata->data_range & FULL_RES)
+			range = ADXL_FULLRES_MAX_VAL;	/* Signed 13-bit */
+		else
+			range = ADXL_FIXEDRES_MAX_VAL;	/* Signed 10-bit */
+
+		input_set_abs_params(input_dev, ABS_X, -range, range, 3, 3);
+		input_set_abs_params(input_dev, ABS_Y, -range, range, 3, 3);
+		input_set_abs_params(input_dev, ABS_Z, -range, range, 3, 3);
+	}
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(pdata->ev_code_tap[ADXL_X_AXIS], input_dev->keybit);
+	__set_bit(pdata->ev_code_tap[ADXL_Y_AXIS], input_dev->keybit);
+	__set_bit(pdata->ev_code_tap[ADXL_Z_AXIS], input_dev->keybit);
+
+	if (pdata->ev_code_ff) {
+		ac->int_mask = FREE_FALL;
+		__set_bit(pdata->ev_code_ff, input_dev->keybit);
+	}
+
+	if (pdata->ev_code_act_inactivity)
+		__set_bit(pdata->ev_code_act_inactivity, input_dev->keybit);
+
+	ac->int_mask |= ACTIVITY | INACTIVITY;
+
+	if (pdata->watermark) {
+		ac->int_mask |= WATERMARK;
+		if (!FIFO_MODE(pdata->fifo_mode))
+			ac->pdata.fifo_mode |= FIFO_STREAM;
+	} else {
+		ac->int_mask |= DATA_READY;
+	}
+
+	if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
+		ac->int_mask |= SINGLE_TAP | DOUBLE_TAP;
+
+	if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
+		ac->fifo_delay = false;
+
+	ac->bops->write(dev, POWER_CTL, 0);
+
+	err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
+				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				   dev_name(dev), ac);
+	if (err) {
+		dev_err(dev, "irq %d busy?\n", ac->irq);
+		goto err_free_mem;
+	}
+
+	err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group);
+	if (err)
+		goto err_free_irq;
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_remove_attr;
+
+	AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
+	AC_WRITE(ac, OFSX, pdata->x_axis_offset);
+	ac->hwcal.x = pdata->x_axis_offset;
+	AC_WRITE(ac, OFSY, pdata->y_axis_offset);
+	ac->hwcal.y = pdata->y_axis_offset;
+	AC_WRITE(ac, OFSZ, pdata->z_axis_offset);
+	ac->hwcal.z = pdata->z_axis_offset;
+	AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
+	AC_WRITE(ac, DUR, pdata->tap_duration);
+	AC_WRITE(ac, LATENT, pdata->tap_latency);
+	AC_WRITE(ac, WINDOW, pdata->tap_window);
+	AC_WRITE(ac, THRESH_ACT, pdata->activity_threshold);
+	AC_WRITE(ac, THRESH_INACT, pdata->inactivity_threshold);
+	AC_WRITE(ac, TIME_INACT, pdata->inactivity_time);
+	AC_WRITE(ac, THRESH_FF, pdata->free_fall_threshold);
+	AC_WRITE(ac, TIME_FF, pdata->free_fall_time);
+	AC_WRITE(ac, TAP_AXES, pdata->tap_axis_control);
+	AC_WRITE(ac, ACT_INACT_CTL, pdata->act_axis_control);
+	AC_WRITE(ac, BW_RATE, RATE(ac->pdata.data_rate) |
+		 (pdata->low_power_mode ? LOW_POWER : 0));
+	AC_WRITE(ac, DATA_FORMAT, pdata->data_range);
+	AC_WRITE(ac, FIFO_CTL, FIFO_MODE(pdata->fifo_mode) |
+			SAMPLES(pdata->watermark));
+
+	if (pdata->use_int2) {
+		/* Map all INTs to INT2 */
+		AC_WRITE(ac, INT_MAP, ac->int_mask | OVERRUN);
+	} else {
+		/* Map all INTs to INT1 */
+		AC_WRITE(ac, INT_MAP, 0);
+	}
+
+	if (ac->model == 346 && ac->pdata.orientation_enable) {
+		AC_WRITE(ac, ORIENT_CONF,
+			ORIENT_DEADZONE(ac->pdata.deadzone_angle) |
+			ORIENT_DIVISOR(ac->pdata.divisor_length));
+
+		ac->orient2d_saved = 1234;
+		ac->orient3d_saved = 1234;
+
+		if (pdata->orientation_enable & ADXL_EN_ORIENTATION_3D)
+			for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_3d); i++)
+				__set_bit(pdata->ev_codes_orient_3d[i],
+					  input_dev->keybit);
+
+		if (pdata->orientation_enable & ADXL_EN_ORIENTATION_2D)
+			for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_2d); i++)
+				__set_bit(pdata->ev_codes_orient_2d[i],
+					  input_dev->keybit);
+	} else {
+		ac->pdata.orientation_enable = 0;
+	}
+
+	AC_WRITE(ac, INT_ENABLE, ac->int_mask | OVERRUN);
+
+	ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK);
+
+	return ac;
+
+ err_remove_attr:
+	sysfs_remove_group(&dev->kobj, &adxl34x_attr_group);
+ err_free_irq:
+	free_irq(ac->irq, ac);
+ err_free_mem:
+	input_free_device(input_dev);
+	kfree(ac);
+ err_out:
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(adxl34x_probe);
+
+int adxl34x_remove(struct adxl34x *ac)
+{
+	sysfs_remove_group(&ac->dev->kobj, &adxl34x_attr_group);
+	free_irq(ac->irq, ac);
+	input_unregister_device(ac->input);
+	dev_dbg(ac->dev, "unregistered accelerometer\n");
+	kfree(ac);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(adxl34x_remove);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x.h b/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x.h
new file mode 100644
index 0000000..bbbc80f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/adxl34x.h
@@ -0,0 +1,30 @@
+/*
+ * ADXL345/346 Three-Axis Digital Accelerometers (I2C/SPI Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADXL34X_H_
+#define _ADXL34X_H_
+
+struct device;
+struct adxl34x;
+
+struct adxl34x_bus_ops {
+	u16 bustype;
+	int (*read)(struct device *, unsigned char);
+	int (*read_block)(struct device *, unsigned char, int, void *);
+	int (*write)(struct device *, unsigned char, unsigned char);
+};
+
+void adxl34x_suspend(struct adxl34x *ac);
+void adxl34x_resume(struct adxl34x *ac);
+struct adxl34x *adxl34x_probe(struct device *dev, int irq,
+			      bool fifo_delay_default,
+			      const struct adxl34x_bus_ops *bops);
+int adxl34x_remove(struct adxl34x *ac);
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/apanel.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/apanel.c
new file mode 100644
index 0000000..a8d2b8d
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/apanel.c
@@ -0,0 +1,350 @@
+/*
+ *  Fujitsu Lifebook Application Panel button drive
+ *
+ *  Copyright (C) 2007 Stephen Hemminger <shemminger@linux-foundation.org>
+ *  Copyright (C) 2001-2003 Jochen Eisinger <jochen@penguin-breeder.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * Many Fujitsu Lifebook laptops have a small panel of buttons that are
+ * accessible via the i2c/smbus interface. This driver polls those
+ * buttons and generates input events.
+ *
+ * For more details see:
+ *	http://apanel.sourceforge.net/tech.php
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/input-polldev.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/leds.h>
+
+#define APANEL_NAME	"Fujitsu Application Panel"
+#define APANEL_VERSION	"1.3.1"
+#define APANEL		"apanel"
+
+/* How often we poll keys - msecs */
+#define POLL_INTERVAL_DEFAULT	1000
+
+/* Magic constants in BIOS that tell about buttons */
+enum apanel_devid {
+	APANEL_DEV_NONE	  = 0,
+	APANEL_DEV_APPBTN = 1,
+	APANEL_DEV_CDBTN  = 2,
+	APANEL_DEV_LCD	  = 3,
+	APANEL_DEV_LED	  = 4,
+
+	APANEL_DEV_MAX,
+};
+
+enum apanel_chip {
+	CHIP_NONE    = 0,
+	CHIP_OZ992C  = 1,
+	CHIP_OZ163T  = 2,
+	CHIP_OZ711M3 = 4,
+};
+
+/* Result of BIOS snooping/probing -- what features are supported */
+static enum apanel_chip device_chip[APANEL_DEV_MAX];
+
+#define MAX_PANEL_KEYS	12
+
+struct apanel {
+	struct input_polled_dev *ipdev;
+	struct i2c_client *client;
+	unsigned short keymap[MAX_PANEL_KEYS];
+	u16    nkeys;
+	u16    led_bits;
+	struct work_struct led_work;
+	struct led_classdev mail_led;
+};
+
+
+static int apanel_probe(struct i2c_client *, const struct i2c_device_id *);
+
+static void report_key(struct input_dev *input, unsigned keycode)
+{
+	pr_debug(APANEL ": report key %#x\n", keycode);
+	input_report_key(input, keycode, 1);
+	input_sync(input);
+
+	input_report_key(input, keycode, 0);
+	input_sync(input);
+}
+
+/* Poll for key changes
+ *
+ * Read Application keys via SMI
+ *  A (0x4), B (0x8), Internet (0x2), Email (0x1).
+ *
+ * CD keys:
+ * Forward (0x100), Rewind (0x200), Stop (0x400), Pause (0x800)
+ */
+static void apanel_poll(struct input_polled_dev *ipdev)
+{
+	struct apanel *ap = ipdev->private;
+	struct input_dev *idev = ipdev->input;
+	u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8;
+	s32 data;
+	int i;
+
+	data = i2c_smbus_read_word_data(ap->client, cmd);
+	if (data < 0)
+		return;	/* ignore errors (due to ACPI??) */
+
+	/* write back to clear latch */
+	i2c_smbus_write_word_data(ap->client, cmd, 0);
+
+	if (!data)
+		return;
+
+	dev_dbg(&idev->dev, APANEL ": data %#x\n", data);
+	for (i = 0; i < idev->keycodemax; i++)
+		if ((1u << i) & data)
+			report_key(idev, ap->keymap[i]);
+}
+
+/* Track state changes of LED */
+static void led_update(struct work_struct *work)
+{
+	struct apanel *ap = container_of(work, struct apanel, led_work);
+
+	i2c_smbus_write_word_data(ap->client, 0x10, ap->led_bits);
+}
+
+static void mail_led_set(struct led_classdev *led,
+			 enum led_brightness value)
+{
+	struct apanel *ap = container_of(led, struct apanel, mail_led);
+
+	if (value != LED_OFF)
+		ap->led_bits |= 0x8000;
+	else
+		ap->led_bits &= ~0x8000;
+
+	schedule_work(&ap->led_work);
+}
+
+static int apanel_remove(struct i2c_client *client)
+{
+	struct apanel *ap = i2c_get_clientdata(client);
+
+	if (device_chip[APANEL_DEV_LED] != CHIP_NONE)
+		led_classdev_unregister(&ap->mail_led);
+
+	input_unregister_polled_device(ap->ipdev);
+	input_free_polled_device(ap->ipdev);
+
+	return 0;
+}
+
+static void apanel_shutdown(struct i2c_client *client)
+{
+	apanel_remove(client);
+}
+
+static const struct i2c_device_id apanel_id[] = {
+	{ "fujitsu_apanel", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, apanel_id);
+
+static struct i2c_driver apanel_driver = {
+	.driver = {
+		.name = APANEL,
+	},
+	.probe		= &apanel_probe,
+	.remove		= &apanel_remove,
+	.shutdown	= &apanel_shutdown,
+	.id_table	= apanel_id,
+};
+
+static struct apanel apanel = {
+	.keymap = {
+		[0] = KEY_MAIL,
+		[1] = KEY_WWW,
+		[2] = KEY_PROG2,
+		[3] = KEY_PROG1,
+
+		[8] = KEY_FORWARD,
+		[9] = KEY_REWIND,
+		[10] = KEY_STOPCD,
+		[11] = KEY_PLAYPAUSE,
+
+	},
+	.mail_led = {
+		.name = "mail:blue",
+		.brightness_set = mail_led_set,
+	},
+};
+
+/* NB: Only one panel on the i2c. */
+static int apanel_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct apanel *ap;
+	struct input_polled_dev *ipdev;
+	struct input_dev *idev;
+	u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8;
+	int i, err = -ENOMEM;
+
+	ap = &apanel;
+
+	ipdev = input_allocate_polled_device();
+	if (!ipdev)
+		goto out1;
+
+	ap->ipdev = ipdev;
+	ap->client = client;
+
+	i2c_set_clientdata(client, ap);
+
+	err = i2c_smbus_write_word_data(client, cmd, 0);
+	if (err) {
+		dev_warn(&client->dev, APANEL ": smbus write error %d\n",
+			 err);
+		goto out3;
+	}
+
+	ipdev->poll = apanel_poll;
+	ipdev->poll_interval = POLL_INTERVAL_DEFAULT;
+	ipdev->private = ap;
+
+	idev = ipdev->input;
+	idev->name = APANEL_NAME " buttons";
+	idev->phys = "apanel/input0";
+	idev->id.bustype = BUS_HOST;
+	idev->dev.parent = &client->dev;
+
+	set_bit(EV_KEY, idev->evbit);
+
+	idev->keycode = ap->keymap;
+	idev->keycodesize = sizeof(ap->keymap[0]);
+	idev->keycodemax = (device_chip[APANEL_DEV_CDBTN] != CHIP_NONE) ? 12 : 4;
+
+	for (i = 0; i < idev->keycodemax; i++)
+		if (ap->keymap[i])
+			set_bit(ap->keymap[i], idev->keybit);
+
+	err = input_register_polled_device(ipdev);
+	if (err)
+		goto out3;
+
+	INIT_WORK(&ap->led_work, led_update);
+	if (device_chip[APANEL_DEV_LED] != CHIP_NONE) {
+		err = led_classdev_register(&client->dev, &ap->mail_led);
+		if (err)
+			goto out4;
+	}
+
+	return 0;
+out4:
+	input_unregister_polled_device(ipdev);
+out3:
+	input_free_polled_device(ipdev);
+out1:
+	return err;
+}
+
+/* Scan the system ROM for the signature "FJKEYINF" */
+static __init const void __iomem *bios_signature(const void __iomem *bios)
+{
+	ssize_t offset;
+	const unsigned char signature[] = "FJKEYINF";
+
+	for (offset = 0; offset < 0x10000; offset += 0x10) {
+		if (check_signature(bios + offset, signature,
+				    sizeof(signature)-1))
+			return bios + offset;
+	}
+	pr_notice(APANEL ": Fujitsu BIOS signature '%s' not found...\n",
+		  signature);
+	return NULL;
+}
+
+static int __init apanel_init(void)
+{
+	void __iomem *bios;
+	const void __iomem *p;
+	u8 devno;
+	unsigned char i2c_addr;
+	int found = 0;
+
+	bios = ioremap(0xF0000, 0x10000); /* Can't fail */
+
+	p = bios_signature(bios);
+	if (!p) {
+		iounmap(bios);
+		return -ENODEV;
+	}
+
+	/* just use the first address */
+	p += 8;
+	i2c_addr = readb(p + 3) >> 1;
+
+	for ( ; (devno = readb(p)) & 0x7f; p += 4) {
+		unsigned char method, slave, chip;
+
+		method = readb(p + 1);
+		chip = readb(p + 2);
+		slave = readb(p + 3) >> 1;
+
+		if (slave != i2c_addr) {
+			pr_notice(APANEL ": only one SMBus slave "
+				  "address supported, skiping device...\n");
+			continue;
+		}
+
+		/* translate alternative device numbers */
+		switch (devno) {
+		case 6:
+			devno = APANEL_DEV_APPBTN;
+			break;
+		case 7:
+			devno = APANEL_DEV_LED;
+			break;
+		}
+
+		if (devno >= APANEL_DEV_MAX)
+			pr_notice(APANEL ": unknown device %u found\n", devno);
+		else if (device_chip[devno] != CHIP_NONE)
+			pr_warning(APANEL ": duplicate entry for devno %u\n", devno);
+
+		else if (method != 1 && method != 2 && method != 4) {
+			pr_notice(APANEL ": unknown method %u for devno %u\n",
+				  method, devno);
+		} else {
+			device_chip[devno] = (enum apanel_chip) chip;
+			++found;
+		}
+	}
+	iounmap(bios);
+
+	if (found == 0) {
+		pr_info(APANEL ": no input devices reported by BIOS\n");
+		return -EIO;
+	}
+
+	return i2c_add_driver(&apanel_driver);
+}
+module_init(apanel_init);
+
+static void __exit apanel_cleanup(void)
+{
+	i2c_del_driver(&apanel_driver);
+}
+module_exit(apanel_cleanup);
+
+MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
+MODULE_DESCRIPTION(APANEL_NAME " driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(APANEL_VERSION);
+
+MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifeBook*:pvr*:rvnFUJITSU:*");
+MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifebook*:pvr*:rvnFUJITSU:*");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/ati_remote2.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/ati_remote2.c
new file mode 100644
index 0000000..f63341f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/ati_remote2.c
@@ -0,0 +1,1016 @@
+/*
+ * ati_remote2 - ATI/Philips USB RF remote driver
+ *
+ * Copyright (C) 2005-2008 Ville Syrjala <syrjala@sci.fi>
+ * Copyright (C) 2007-2008 Peter Stokes <linux@dadeos.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/usb/input.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#define DRIVER_DESC    "ATI/Philips USB RF remote driver"
+#define DRIVER_VERSION "0.3"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
+MODULE_LICENSE("GPL");
+
+/*
+ * ATI Remote Wonder II Channel Configuration
+ *
+ * The remote control can by assigned one of sixteen "channels" in order to facilitate
+ * the use of multiple remote controls within range of each other.
+ * A remote's "channel" may be altered by pressing and holding the "PC" button for
+ * approximately 3 seconds, after which the button will slowly flash the count of the
+ * currently configured "channel", using the numeric keypad enter a number between 1 and
+ * 16 and then press the "PC" button again, the button will slowly flash the count of the
+ * newly configured "channel".
+ */
+
+enum {
+	ATI_REMOTE2_MAX_CHANNEL_MASK = 0xFFFF,
+	ATI_REMOTE2_MAX_MODE_MASK = 0x1F,
+};
+
+static int ati_remote2_set_mask(const char *val,
+				const struct kernel_param *kp,
+				unsigned int max)
+{
+	unsigned int mask;
+	int ret;
+
+	if (!val)
+		return -EINVAL;
+
+	ret = kstrtouint(val, 0, &mask);
+	if (ret)
+		return ret;
+
+	if (mask & ~max)
+		return -EINVAL;
+
+	*(unsigned int *)kp->arg = mask;
+
+	return 0;
+}
+
+static int ati_remote2_set_channel_mask(const char *val,
+					const struct kernel_param *kp)
+{
+	pr_debug("%s()\n", __func__);
+
+	return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_CHANNEL_MASK);
+}
+
+static int ati_remote2_get_channel_mask(char *buffer,
+					const struct kernel_param *kp)
+{
+	pr_debug("%s()\n", __func__);
+
+	return sprintf(buffer, "0x%04x", *(unsigned int *)kp->arg);
+}
+
+static int ati_remote2_set_mode_mask(const char *val,
+				     const struct kernel_param *kp)
+{
+	pr_debug("%s()\n", __func__);
+
+	return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_MODE_MASK);
+}
+
+static int ati_remote2_get_mode_mask(char *buffer,
+				     const struct kernel_param *kp)
+{
+	pr_debug("%s()\n", __func__);
+
+	return sprintf(buffer, "0x%02x", *(unsigned int *)kp->arg);
+}
+
+static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
+#define param_check_channel_mask(name, p) __param_check(name, p, unsigned int)
+static struct kernel_param_ops param_ops_channel_mask = {
+	.set = ati_remote2_set_channel_mask,
+	.get = ati_remote2_get_channel_mask,
+};
+module_param(channel_mask, channel_mask, 0644);
+MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>");
+
+static unsigned int mode_mask = ATI_REMOTE2_MAX_MODE_MASK;
+#define param_check_mode_mask(name, p) __param_check(name, p, unsigned int)
+static struct kernel_param_ops param_ops_mode_mask = {
+	.set = ati_remote2_set_mode_mask,
+	.get = ati_remote2_get_mode_mask,
+};
+module_param(mode_mask, mode_mask, 0644);
+MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
+
+static struct usb_device_id ati_remote2_id_table[] = {
+	{ USB_DEVICE(0x0471, 0x0602) },	/* ATI Remote Wonder II */
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
+
+static DEFINE_MUTEX(ati_remote2_mutex);
+
+enum {
+	ATI_REMOTE2_OPENED = 0x1,
+	ATI_REMOTE2_SUSPENDED = 0x2,
+};
+
+enum {
+	ATI_REMOTE2_AUX1,
+	ATI_REMOTE2_AUX2,
+	ATI_REMOTE2_AUX3,
+	ATI_REMOTE2_AUX4,
+	ATI_REMOTE2_PC,
+	ATI_REMOTE2_MODES,
+};
+
+static const struct {
+	u8  hw_code;
+	u16 keycode;
+} ati_remote2_key_table[] = {
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+	{ 0x0c, KEY_POWER },
+	{ 0x0d, KEY_MUTE },
+	{ 0x10, KEY_VOLUMEUP },
+	{ 0x11, KEY_VOLUMEDOWN },
+	{ 0x20, KEY_CHANNELUP },
+	{ 0x21, KEY_CHANNELDOWN },
+	{ 0x28, KEY_FORWARD },
+	{ 0x29, KEY_REWIND },
+	{ 0x2c, KEY_PLAY },
+	{ 0x30, KEY_PAUSE },
+	{ 0x31, KEY_STOP },
+	{ 0x37, KEY_RECORD },
+	{ 0x38, KEY_DVD },
+	{ 0x39, KEY_TV },
+	{ 0x3f, KEY_PROG1 }, /* AUX1-AUX4 and PC */
+	{ 0x54, KEY_MENU },
+	{ 0x58, KEY_UP },
+	{ 0x59, KEY_DOWN },
+	{ 0x5a, KEY_LEFT },
+	{ 0x5b, KEY_RIGHT },
+	{ 0x5c, KEY_OK },
+	{ 0x78, KEY_A },
+	{ 0x79, KEY_B },
+	{ 0x7a, KEY_C },
+	{ 0x7b, KEY_D },
+	{ 0x7c, KEY_E },
+	{ 0x7d, KEY_F },
+	{ 0x82, KEY_ENTER },
+	{ 0x8e, KEY_VENDOR },
+	{ 0x96, KEY_COFFEE },
+	{ 0xa9, BTN_LEFT },
+	{ 0xaa, BTN_RIGHT },
+	{ 0xbe, KEY_QUESTION },
+	{ 0xd0, KEY_EDIT },
+	{ 0xd5, KEY_FRONT },
+	{ 0xf9, KEY_INFO },
+};
+
+struct ati_remote2 {
+	struct input_dev *idev;
+	struct usb_device *udev;
+
+	struct usb_interface *intf[2];
+	struct usb_endpoint_descriptor *ep[2];
+	struct urb *urb[2];
+	void *buf[2];
+	dma_addr_t buf_dma[2];
+
+	unsigned long jiffies;
+	int mode;
+
+	char name[64];
+	char phys[64];
+
+	/* Each mode (AUX1-AUX4 and PC) can have an independent keymap. */
+	u16 keycode[ATI_REMOTE2_MODES][ARRAY_SIZE(ati_remote2_key_table)];
+
+	unsigned int flags;
+
+	unsigned int channel_mask;
+	unsigned int mode_mask;
+};
+
+static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
+static void ati_remote2_disconnect(struct usb_interface *interface);
+static int ati_remote2_suspend(struct usb_interface *interface, pm_message_t message);
+static int ati_remote2_resume(struct usb_interface *interface);
+static int ati_remote2_reset_resume(struct usb_interface *interface);
+static int ati_remote2_pre_reset(struct usb_interface *interface);
+static int ati_remote2_post_reset(struct usb_interface *interface);
+
+static struct usb_driver ati_remote2_driver = {
+	.name       = "ati_remote2",
+	.probe      = ati_remote2_probe,
+	.disconnect = ati_remote2_disconnect,
+	.id_table   = ati_remote2_id_table,
+	.suspend    = ati_remote2_suspend,
+	.resume     = ati_remote2_resume,
+	.reset_resume = ati_remote2_reset_resume,
+	.pre_reset  = ati_remote2_pre_reset,
+	.post_reset = ati_remote2_post_reset,
+	.supports_autosuspend = 1,
+};
+
+static int ati_remote2_submit_urbs(struct ati_remote2 *ar2)
+{
+	int r;
+
+	r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
+	if (r) {
+		dev_err(&ar2->intf[0]->dev,
+			"%s(): usb_submit_urb() = %d\n", __func__, r);
+		return r;
+	}
+	r = usb_submit_urb(ar2->urb[1], GFP_KERNEL);
+	if (r) {
+		usb_kill_urb(ar2->urb[0]);
+		dev_err(&ar2->intf[1]->dev,
+			"%s(): usb_submit_urb() = %d\n", __func__, r);
+		return r;
+	}
+
+	return 0;
+}
+
+static void ati_remote2_kill_urbs(struct ati_remote2 *ar2)
+{
+	usb_kill_urb(ar2->urb[1]);
+	usb_kill_urb(ar2->urb[0]);
+}
+
+static int ati_remote2_open(struct input_dev *idev)
+{
+	struct ati_remote2 *ar2 = input_get_drvdata(idev);
+	int r;
+
+	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
+
+	r = usb_autopm_get_interface(ar2->intf[0]);
+	if (r) {
+		dev_err(&ar2->intf[0]->dev,
+			"%s(): usb_autopm_get_interface() = %d\n", __func__, r);
+		goto fail1;
+	}
+
+	mutex_lock(&ati_remote2_mutex);
+
+	if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) {
+		r = ati_remote2_submit_urbs(ar2);
+		if (r)
+			goto fail2;
+	}
+
+	ar2->flags |= ATI_REMOTE2_OPENED;
+
+	mutex_unlock(&ati_remote2_mutex);
+
+	usb_autopm_put_interface(ar2->intf[0]);
+
+	return 0;
+
+ fail2:
+	mutex_unlock(&ati_remote2_mutex);
+	usb_autopm_put_interface(ar2->intf[0]);
+ fail1:
+	return r;
+}
+
+static void ati_remote2_close(struct input_dev *idev)
+{
+	struct ati_remote2 *ar2 = input_get_drvdata(idev);
+
+	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
+
+	mutex_lock(&ati_remote2_mutex);
+
+	if (!(ar2->flags & ATI_REMOTE2_SUSPENDED))
+		ati_remote2_kill_urbs(ar2);
+
+	ar2->flags &= ~ATI_REMOTE2_OPENED;
+
+	mutex_unlock(&ati_remote2_mutex);
+}
+
+static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
+{
+	struct input_dev *idev = ar2->idev;
+	u8 *data = ar2->buf[0];
+	int channel, mode;
+
+	channel = data[0] >> 4;
+
+	if (!((1 << channel) & ar2->channel_mask))
+		return;
+
+	mode = data[0] & 0x0F;
+
+	if (mode > ATI_REMOTE2_PC) {
+		dev_err(&ar2->intf[0]->dev,
+			"Unknown mode byte (%02x %02x %02x %02x)\n",
+			data[3], data[2], data[1], data[0]);
+		return;
+	}
+
+	if (!((1 << mode) & ar2->mode_mask))
+		return;
+
+	input_event(idev, EV_REL, REL_X, (s8) data[1]);
+	input_event(idev, EV_REL, REL_Y, (s8) data[2]);
+	input_sync(idev);
+}
+
+static int ati_remote2_lookup(unsigned int hw_code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ati_remote2_key_table); i++)
+		if (ati_remote2_key_table[i].hw_code == hw_code)
+			return i;
+
+	return -1;
+}
+
+static void ati_remote2_input_key(struct ati_remote2 *ar2)
+{
+	struct input_dev *idev = ar2->idev;
+	u8 *data = ar2->buf[1];
+	int channel, mode, hw_code, index;
+
+	channel = data[0] >> 4;
+
+	if (!((1 << channel) & ar2->channel_mask))
+		return;
+
+	mode = data[0] & 0x0F;
+
+	if (mode > ATI_REMOTE2_PC) {
+		dev_err(&ar2->intf[1]->dev,
+			"Unknown mode byte (%02x %02x %02x %02x)\n",
+			data[3], data[2], data[1], data[0]);
+		return;
+	}
+
+	hw_code = data[2];
+	if (hw_code == 0x3f) {
+		/*
+		 * For some incomprehensible reason the mouse pad generates
+		 * events which look identical to the events from the last
+		 * pressed mode key. Naturally we don't want to generate key
+		 * events for the mouse pad so we filter out any subsequent
+		 * events from the same mode key.
+		 */
+		if (ar2->mode == mode)
+			return;
+
+		if (data[1] == 0)
+			ar2->mode = mode;
+	}
+
+	if (!((1 << mode) & ar2->mode_mask))
+		return;
+
+	index = ati_remote2_lookup(hw_code);
+	if (index < 0) {
+		dev_err(&ar2->intf[1]->dev,
+			"Unknown code byte (%02x %02x %02x %02x)\n",
+			data[3], data[2], data[1], data[0]);
+		return;
+	}
+
+	switch (data[1]) {
+	case 0:	/* release */
+		break;
+	case 1:	/* press */
+		ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_DELAY]);
+		break;
+	case 2:	/* repeat */
+
+		/* No repeat for mouse buttons. */
+		if (ar2->keycode[mode][index] == BTN_LEFT ||
+		    ar2->keycode[mode][index] == BTN_RIGHT)
+			return;
+
+		if (!time_after_eq(jiffies, ar2->jiffies))
+			return;
+
+		ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_PERIOD]);
+		break;
+	default:
+		dev_err(&ar2->intf[1]->dev,
+			"Unknown state byte (%02x %02x %02x %02x)\n",
+			data[3], data[2], data[1], data[0]);
+		return;
+	}
+
+	input_event(idev, EV_KEY, ar2->keycode[mode][index], data[1]);
+	input_sync(idev);
+}
+
+static void ati_remote2_complete_mouse(struct urb *urb)
+{
+	struct ati_remote2 *ar2 = urb->context;
+	int r;
+
+	switch (urb->status) {
+	case 0:
+		usb_mark_last_busy(ar2->udev);
+		ati_remote2_input_mouse(ar2);
+		break;
+	case -ENOENT:
+	case -EILSEQ:
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		dev_dbg(&ar2->intf[0]->dev,
+			"%s(): urb status = %d\n", __func__, urb->status);
+		return;
+	default:
+		usb_mark_last_busy(ar2->udev);
+		dev_err(&ar2->intf[0]->dev,
+			"%s(): urb status = %d\n", __func__, urb->status);
+	}
+
+	r = usb_submit_urb(urb, GFP_ATOMIC);
+	if (r)
+		dev_err(&ar2->intf[0]->dev,
+			"%s(): usb_submit_urb() = %d\n", __func__, r);
+}
+
+static void ati_remote2_complete_key(struct urb *urb)
+{
+	struct ati_remote2 *ar2 = urb->context;
+	int r;
+
+	switch (urb->status) {
+	case 0:
+		usb_mark_last_busy(ar2->udev);
+		ati_remote2_input_key(ar2);
+		break;
+	case -ENOENT:
+	case -EILSEQ:
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		dev_dbg(&ar2->intf[1]->dev,
+			"%s(): urb status = %d\n", __func__, urb->status);
+		return;
+	default:
+		usb_mark_last_busy(ar2->udev);
+		dev_err(&ar2->intf[1]->dev,
+			"%s(): urb status = %d\n", __func__, urb->status);
+	}
+
+	r = usb_submit_urb(urb, GFP_ATOMIC);
+	if (r)
+		dev_err(&ar2->intf[1]->dev,
+			"%s(): usb_submit_urb() = %d\n", __func__, r);
+}
+
+static int ati_remote2_getkeycode(struct input_dev *idev,
+				  struct input_keymap_entry *ke)
+{
+	struct ati_remote2 *ar2 = input_get_drvdata(idev);
+	unsigned int mode;
+	int offset;
+	unsigned int index;
+	unsigned int scancode;
+
+	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+		index = ke->index;
+		if (index >= ATI_REMOTE2_MODES *
+				ARRAY_SIZE(ati_remote2_key_table))
+			return -EINVAL;
+
+		mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
+		offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
+		scancode = (mode << 8) + ati_remote2_key_table[offset].hw_code;
+	} else {
+		if (input_scancode_to_scalar(ke, &scancode))
+			return -EINVAL;
+
+		mode = scancode >> 8;
+		if (mode > ATI_REMOTE2_PC)
+			return -EINVAL;
+
+		offset = ati_remote2_lookup(scancode & 0xff);
+		if (offset < 0)
+			return -EINVAL;
+
+		index = mode * ARRAY_SIZE(ati_remote2_key_table) + offset;
+	}
+
+	ke->keycode = ar2->keycode[mode][offset];
+	ke->len = sizeof(scancode);
+	memcpy(&ke->scancode, &scancode, sizeof(scancode));
+	ke->index = index;
+
+	return 0;
+}
+
+static int ati_remote2_setkeycode(struct input_dev *idev,
+				  const struct input_keymap_entry *ke,
+				  unsigned int *old_keycode)
+{
+	struct ati_remote2 *ar2 = input_get_drvdata(idev);
+	unsigned int mode;
+	int offset;
+	unsigned int index;
+	unsigned int scancode;
+
+	if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+		if (ke->index >= ATI_REMOTE2_MODES *
+				ARRAY_SIZE(ati_remote2_key_table))
+			return -EINVAL;
+
+		mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
+		offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
+	} else {
+		if (input_scancode_to_scalar(ke, &scancode))
+			return -EINVAL;
+
+		mode = scancode >> 8;
+		if (mode > ATI_REMOTE2_PC)
+			return -EINVAL;
+
+		offset = ati_remote2_lookup(scancode & 0xff);
+		if (offset < 0)
+			return -EINVAL;
+	}
+
+	*old_keycode = ar2->keycode[mode][offset];
+	ar2->keycode[mode][offset] = ke->keycode;
+	__set_bit(ke->keycode, idev->keybit);
+
+	for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
+		for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
+			if (ar2->keycode[mode][index] == *old_keycode)
+				return 0;
+		}
+	}
+
+	__clear_bit(*old_keycode, idev->keybit);
+
+	return 0;
+}
+
+static int ati_remote2_input_init(struct ati_remote2 *ar2)
+{
+	struct input_dev *idev;
+	int index, mode, retval;
+
+	idev = input_allocate_device();
+	if (!idev)
+		return -ENOMEM;
+
+	ar2->idev = idev;
+	input_set_drvdata(idev, ar2);
+
+	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
+	idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+		BIT_MASK(BTN_RIGHT);
+	idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+
+	for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
+		for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
+			ar2->keycode[mode][index] = ati_remote2_key_table[index].keycode;
+			__set_bit(ar2->keycode[mode][index], idev->keybit);
+		}
+	}
+
+	/* AUX1-AUX4 and PC generate the same scancode. */
+	index = ati_remote2_lookup(0x3f);
+	ar2->keycode[ATI_REMOTE2_AUX1][index] = KEY_PROG1;
+	ar2->keycode[ATI_REMOTE2_AUX2][index] = KEY_PROG2;
+	ar2->keycode[ATI_REMOTE2_AUX3][index] = KEY_PROG3;
+	ar2->keycode[ATI_REMOTE2_AUX4][index] = KEY_PROG4;
+	ar2->keycode[ATI_REMOTE2_PC][index] = KEY_PC;
+	__set_bit(KEY_PROG1, idev->keybit);
+	__set_bit(KEY_PROG2, idev->keybit);
+	__set_bit(KEY_PROG3, idev->keybit);
+	__set_bit(KEY_PROG4, idev->keybit);
+	__set_bit(KEY_PC, idev->keybit);
+
+	idev->rep[REP_DELAY]  = 250;
+	idev->rep[REP_PERIOD] = 33;
+
+	idev->open = ati_remote2_open;
+	idev->close = ati_remote2_close;
+
+	idev->getkeycode = ati_remote2_getkeycode;
+	idev->setkeycode = ati_remote2_setkeycode;
+
+	idev->name = ar2->name;
+	idev->phys = ar2->phys;
+
+	usb_to_input_id(ar2->udev, &idev->id);
+	idev->dev.parent = &ar2->udev->dev;
+
+	retval = input_register_device(idev);
+	if (retval)
+		input_free_device(idev);
+
+	return retval;
+}
+
+static int ati_remote2_urb_init(struct ati_remote2 *ar2)
+{
+	struct usb_device *udev = ar2->udev;
+	int i, pipe, maxp;
+
+	for (i = 0; i < 2; i++) {
+		ar2->buf[i] = usb_alloc_coherent(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
+		if (!ar2->buf[i])
+			return -ENOMEM;
+
+		ar2->urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+		if (!ar2->urb[i])
+			return -ENOMEM;
+
+		pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress);
+		maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+		maxp = maxp > 4 ? 4 : maxp;
+
+		usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp,
+				 i ? ati_remote2_complete_key : ati_remote2_complete_mouse,
+				 ar2, ar2->ep[i]->bInterval);
+		ar2->urb[i]->transfer_dma = ar2->buf_dma[i];
+		ar2->urb[i]->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	}
+
+	return 0;
+}
+
+static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		usb_free_urb(ar2->urb[i]);
+		usb_free_coherent(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
+	}
+}
+
+static int ati_remote2_setup(struct ati_remote2 *ar2, unsigned int ch_mask)
+{
+	int r, i, channel;
+
+	/*
+	 * Configure receiver to only accept input from remote "channel"
+	 *  channel == 0  -> Accept input from any remote channel
+	 *  channel == 1  -> Only accept input from remote channel 1
+	 *  channel == 2  -> Only accept input from remote channel 2
+	 *  ...
+	 *  channel == 16 -> Only accept input from remote channel 16
+	 */
+
+	channel = 0;
+	for (i = 0; i < 16; i++) {
+		if ((1 << i) & ch_mask) {
+			if (!(~(1 << i) & ch_mask))
+				channel = i + 1;
+			break;
+		}
+	}
+
+	r = usb_control_msg(ar2->udev, usb_sndctrlpipe(ar2->udev, 0),
+			    0x20,
+			    USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			    channel, 0x0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+	if (r) {
+		dev_err(&ar2->udev->dev, "%s - failed to set channel due to error: %d\n",
+			__func__, r);
+		return r;
+	}
+
+	return 0;
+}
+
+static ssize_t ati_remote2_show_channel_mask(struct device *dev,
+					     struct device_attribute *attr,
+					     char *buf)
+{
+	struct usb_device *udev = to_usb_device(dev);
+	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
+
+	return sprintf(buf, "0x%04x\n", ar2->channel_mask);
+}
+
+static ssize_t ati_remote2_store_channel_mask(struct device *dev,
+					      struct device_attribute *attr,
+					      const char *buf, size_t count)
+{
+	struct usb_device *udev = to_usb_device(dev);
+	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
+	unsigned int mask;
+	int r;
+
+	r = kstrtouint(buf, 0, &mask);
+	if (r)
+		return r;
+
+	if (mask & ~ATI_REMOTE2_MAX_CHANNEL_MASK)
+		return -EINVAL;
+
+	r = usb_autopm_get_interface(ar2->intf[0]);
+	if (r) {
+		dev_err(&ar2->intf[0]->dev,
+			"%s(): usb_autopm_get_interface() = %d\n", __func__, r);
+		return r;
+	}
+
+	mutex_lock(&ati_remote2_mutex);
+
+	if (mask != ar2->channel_mask) {
+		r = ati_remote2_setup(ar2, mask);
+		if (!r)
+			ar2->channel_mask = mask;
+	}
+
+	mutex_unlock(&ati_remote2_mutex);
+
+	usb_autopm_put_interface(ar2->intf[0]);
+
+	return r ? r : count;
+}
+
+static ssize_t ati_remote2_show_mode_mask(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	struct usb_device *udev = to_usb_device(dev);
+	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
+
+	return sprintf(buf, "0x%02x\n", ar2->mode_mask);
+}
+
+static ssize_t ati_remote2_store_mode_mask(struct device *dev,
+					   struct device_attribute *attr,
+					   const char *buf, size_t count)
+{
+	struct usb_device *udev = to_usb_device(dev);
+	struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+	struct ati_remote2 *ar2 = usb_get_intfdata(intf);
+	unsigned int mask;
+	int err;
+
+	err = kstrtouint(buf, 0, &mask);
+	if (err)
+		return err;
+
+	if (mask & ~ATI_REMOTE2_MAX_MODE_MASK)
+		return -EINVAL;
+
+	ar2->mode_mask = mask;
+
+	return count;
+}
+
+static DEVICE_ATTR(channel_mask, 0644, ati_remote2_show_channel_mask,
+		   ati_remote2_store_channel_mask);
+
+static DEVICE_ATTR(mode_mask, 0644, ati_remote2_show_mode_mask,
+		   ati_remote2_store_mode_mask);
+
+static struct attribute *ati_remote2_attrs[] = {
+	&dev_attr_channel_mask.attr,
+	&dev_attr_mode_mask.attr,
+	NULL,
+};
+
+static struct attribute_group ati_remote2_attr_group = {
+	.attrs = ati_remote2_attrs,
+};
+
+static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_host_interface *alt = interface->cur_altsetting;
+	struct ati_remote2 *ar2;
+	int r;
+
+	if (alt->desc.bInterfaceNumber)
+		return -ENODEV;
+
+	ar2 = kzalloc(sizeof (struct ati_remote2), GFP_KERNEL);
+	if (!ar2)
+		return -ENOMEM;
+
+	ar2->udev = udev;
+
+	ar2->intf[0] = interface;
+	ar2->ep[0] = &alt->endpoint[0].desc;
+
+	ar2->intf[1] = usb_ifnum_to_if(udev, 1);
+	r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
+	if (r)
+		goto fail1;
+	alt = ar2->intf[1]->cur_altsetting;
+	ar2->ep[1] = &alt->endpoint[0].desc;
+
+	r = ati_remote2_urb_init(ar2);
+	if (r)
+		goto fail2;
+
+	ar2->channel_mask = channel_mask;
+	ar2->mode_mask = mode_mask;
+
+	r = ati_remote2_setup(ar2, ar2->channel_mask);
+	if (r)
+		goto fail2;
+
+	usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
+	strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
+
+	strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name));
+
+	r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group);
+	if (r)
+		goto fail2;
+
+	r = ati_remote2_input_init(ar2);
+	if (r)
+		goto fail3;
+
+	usb_set_intfdata(interface, ar2);
+
+	interface->needs_remote_wakeup = 1;
+
+	return 0;
+
+ fail3:
+	sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group);
+ fail2:
+	ati_remote2_urb_cleanup(ar2);
+	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
+ fail1:
+	kfree(ar2);
+
+	return r;
+}
+
+static void ati_remote2_disconnect(struct usb_interface *interface)
+{
+	struct ati_remote2 *ar2;
+	struct usb_host_interface *alt = interface->cur_altsetting;
+
+	if (alt->desc.bInterfaceNumber)
+		return;
+
+	ar2 = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	input_unregister_device(ar2->idev);
+
+	sysfs_remove_group(&ar2->udev->dev.kobj, &ati_remote2_attr_group);
+
+	ati_remote2_urb_cleanup(ar2);
+
+	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
+
+	kfree(ar2);
+}
+
+static int ati_remote2_suspend(struct usb_interface *interface,
+			       pm_message_t message)
+{
+	struct ati_remote2 *ar2;
+	struct usb_host_interface *alt = interface->cur_altsetting;
+
+	if (alt->desc.bInterfaceNumber)
+		return 0;
+
+	ar2 = usb_get_intfdata(interface);
+
+	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
+
+	mutex_lock(&ati_remote2_mutex);
+
+	if (ar2->flags & ATI_REMOTE2_OPENED)
+		ati_remote2_kill_urbs(ar2);
+
+	ar2->flags |= ATI_REMOTE2_SUSPENDED;
+
+	mutex_unlock(&ati_remote2_mutex);
+
+	return 0;
+}
+
+static int ati_remote2_resume(struct usb_interface *interface)
+{
+	struct ati_remote2 *ar2;
+	struct usb_host_interface *alt = interface->cur_altsetting;
+	int r = 0;
+
+	if (alt->desc.bInterfaceNumber)
+		return 0;
+
+	ar2 = usb_get_intfdata(interface);
+
+	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
+
+	mutex_lock(&ati_remote2_mutex);
+
+	if (ar2->flags & ATI_REMOTE2_OPENED)
+		r = ati_remote2_submit_urbs(ar2);
+
+	if (!r)
+		ar2->flags &= ~ATI_REMOTE2_SUSPENDED;
+
+	mutex_unlock(&ati_remote2_mutex);
+
+	return r;
+}
+
+static int ati_remote2_reset_resume(struct usb_interface *interface)
+{
+	struct ati_remote2 *ar2;
+	struct usb_host_interface *alt = interface->cur_altsetting;
+	int r = 0;
+
+	if (alt->desc.bInterfaceNumber)
+		return 0;
+
+	ar2 = usb_get_intfdata(interface);
+
+	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
+
+	mutex_lock(&ati_remote2_mutex);
+
+	r = ati_remote2_setup(ar2, ar2->channel_mask);
+	if (r)
+		goto out;
+
+	if (ar2->flags & ATI_REMOTE2_OPENED)
+		r = ati_remote2_submit_urbs(ar2);
+
+	if (!r)
+		ar2->flags &= ~ATI_REMOTE2_SUSPENDED;
+
+ out:
+	mutex_unlock(&ati_remote2_mutex);
+
+	return r;
+}
+
+static int ati_remote2_pre_reset(struct usb_interface *interface)
+{
+	struct ati_remote2 *ar2;
+	struct usb_host_interface *alt = interface->cur_altsetting;
+
+	if (alt->desc.bInterfaceNumber)
+		return 0;
+
+	ar2 = usb_get_intfdata(interface);
+
+	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
+
+	mutex_lock(&ati_remote2_mutex);
+
+	if (ar2->flags == ATI_REMOTE2_OPENED)
+		ati_remote2_kill_urbs(ar2);
+
+	return 0;
+}
+
+static int ati_remote2_post_reset(struct usb_interface *interface)
+{
+	struct ati_remote2 *ar2;
+	struct usb_host_interface *alt = interface->cur_altsetting;
+	int r = 0;
+
+	if (alt->desc.bInterfaceNumber)
+		return 0;
+
+	ar2 = usb_get_intfdata(interface);
+
+	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
+
+	if (ar2->flags == ATI_REMOTE2_OPENED)
+		r = ati_remote2_submit_urbs(ar2);
+
+	mutex_unlock(&ati_remote2_mutex);
+
+	return r;
+}
+
+module_usb_driver(ati_remote2_driver);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/atlas_btns.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/atlas_btns.c
new file mode 100644
index 0000000..601f737
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/atlas_btns.c
@@ -0,0 +1,174 @@
+/*
+ *  atlas_btns.c - Atlas Wallmount Touchscreen ACPI Extras
+ *
+ *  Copyright (C) 2006 Jaya Kumar
+ *  Based on Toshiba ACPI by John Belmonte and ASUS ACPI
+ *  This work was sponsored by CIS(M) Sdn Bhd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_ATLAS_NAME		"Atlas ACPI"
+#define ACPI_ATLAS_CLASS	"Atlas"
+
+static unsigned short atlas_keymap[16];
+static struct input_dev *input_dev;
+
+/* button handling code */
+static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
+		    u32 function, void *handler_context, void **return_context)
+{
+	*return_context =
+		(function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL;
+
+	return AE_OK;
+}
+
+static acpi_status acpi_atlas_button_handler(u32 function,
+		      acpi_physical_address address,
+		      u32 bit_width, u64 *value,
+		      void *handler_context, void *region_context)
+{
+	acpi_status status;
+
+	if (function == ACPI_WRITE) {
+		int code = address & 0x0f;
+		int key_down = !(address & 0x10);
+
+		input_event(input_dev, EV_MSC, MSC_SCAN, code);
+		input_report_key(input_dev, atlas_keymap[code], key_down);
+		input_sync(input_dev);
+
+		status = AE_OK;
+	} else {
+		pr_warn("shrugged on unexpected function: function=%x,address=%lx,value=%x\n",
+			function, (unsigned long)address, (u32)*value);
+		status = AE_BAD_PARAMETER;
+	}
+
+	return status;
+}
+
+static int atlas_acpi_button_add(struct acpi_device *device)
+{
+	acpi_status status;
+	int i;
+	int err;
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		pr_err("unable to allocate input device\n");
+		return -ENOMEM;
+	}
+
+	input_dev->name = "Atlas ACPI button driver";
+	input_dev->phys = "ASIM0000/atlas/input0";
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->keycode = atlas_keymap;
+	input_dev->keycodesize = sizeof(unsigned short);
+	input_dev->keycodemax = ARRAY_SIZE(atlas_keymap);
+
+	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+	__set_bit(EV_KEY, input_dev->evbit);
+	for (i = 0; i < ARRAY_SIZE(atlas_keymap); i++) {
+		if (i < 9) {
+			atlas_keymap[i] = KEY_F1 + i;
+			__set_bit(KEY_F1 + i, input_dev->keybit);
+		} else
+			atlas_keymap[i] = KEY_RESERVED;
+	}
+
+	err = input_register_device(input_dev);
+	if (err) {
+		pr_err("couldn't register input device\n");
+		input_free_device(input_dev);
+		return err;
+	}
+
+	/* hookup button handler */
+	status = acpi_install_address_space_handler(device->handle,
+				0x81, &acpi_atlas_button_handler,
+				&acpi_atlas_button_setup, device);
+	if (ACPI_FAILURE(status)) {
+		pr_err("error installing addr spc handler\n");
+		input_unregister_device(input_dev);
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+static int atlas_acpi_button_remove(struct acpi_device *device, int type)
+{
+	acpi_status status;
+
+	status = acpi_remove_address_space_handler(device->handle,
+				0x81, &acpi_atlas_button_handler);
+	if (ACPI_FAILURE(status))
+		pr_err("error removing addr spc handler\n");
+
+	input_unregister_device(input_dev);
+
+	return 0;
+}
+
+static const struct acpi_device_id atlas_device_ids[] = {
+	{"ASIM0000", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
+
+static struct acpi_driver atlas_acpi_driver = {
+	.name	= ACPI_ATLAS_NAME,
+	.class	= ACPI_ATLAS_CLASS,
+	.owner	= THIS_MODULE,
+	.ids	= atlas_device_ids,
+	.ops	= {
+		.add	= atlas_acpi_button_add,
+		.remove	= atlas_acpi_button_remove,
+	},
+};
+
+static int __init atlas_acpi_init(void)
+{
+	if (acpi_disabled)
+		return -ENODEV;
+
+	return acpi_bus_register_driver(&atlas_acpi_driver);
+}
+
+static void __exit atlas_acpi_exit(void)
+{
+	acpi_bus_unregister_driver(&atlas_acpi_driver);
+}
+
+module_init(atlas_acpi_init);
+module_exit(atlas_acpi_exit);
+
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Atlas button driver");
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/bfin_rotary.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/bfin_rotary.c
new file mode 100644
index 0000000..1c4146f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/bfin_rotary.c
@@ -0,0 +1,272 @@
+/*
+ * Rotary counter driver for Analog Devices Blackfin Processors
+ *
+ * Copyright 2008-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include <asm/portmux.h>
+#include <asm/bfin_rotary.h>
+
+static const u16 per_cnt[] = {
+	P_CNT_CUD,
+	P_CNT_CDG,
+	P_CNT_CZM,
+	0
+};
+
+struct bfin_rot {
+	struct input_dev *input;
+	int irq;
+	unsigned int up_key;
+	unsigned int down_key;
+	unsigned int button_key;
+	unsigned int rel_code;
+	unsigned short cnt_config;
+	unsigned short cnt_imask;
+	unsigned short cnt_debounce;
+};
+
+static void report_key_event(struct input_dev *input, int keycode)
+{
+	/* simulate a press-n-release */
+	input_report_key(input, keycode, 1);
+	input_sync(input);
+	input_report_key(input, keycode, 0);
+	input_sync(input);
+}
+
+static void report_rotary_event(struct bfin_rot *rotary, int delta)
+{
+	struct input_dev *input = rotary->input;
+
+	if (rotary->up_key) {
+		report_key_event(input,
+				 delta > 0 ? rotary->up_key : rotary->down_key);
+	} else {
+		input_report_rel(input, rotary->rel_code, delta);
+		input_sync(input);
+	}
+}
+
+static irqreturn_t bfin_rotary_isr(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct bfin_rot *rotary = platform_get_drvdata(pdev);
+	int delta;
+
+	switch (bfin_read_CNT_STATUS()) {
+
+	case ICII:
+		break;
+
+	case UCII:
+	case DCII:
+		delta = bfin_read_CNT_COUNTER();
+		if (delta)
+			report_rotary_event(rotary, delta);
+		break;
+
+	case CZMII:
+		report_key_event(rotary->input, rotary->button_key);
+		break;
+
+	default:
+		break;
+	}
+
+	bfin_write_CNT_COMMAND(W1LCNT_ZERO);	/* Clear COUNTER */
+	bfin_write_CNT_STATUS(-1);	/* Clear STATUS */
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit bfin_rotary_probe(struct platform_device *pdev)
+{
+	struct bfin_rotary_platform_data *pdata = pdev->dev.platform_data;
+	struct bfin_rot *rotary;
+	struct input_dev *input;
+	int error;
+
+	/* Basic validation */
+	if ((pdata->rotary_up_key && !pdata->rotary_down_key) ||
+	    (!pdata->rotary_up_key && pdata->rotary_down_key)) {
+		return -EINVAL;
+	}
+
+	error = peripheral_request_list(per_cnt, dev_name(&pdev->dev));
+	if (error) {
+		dev_err(&pdev->dev, "requesting peripherals failed\n");
+		return error;
+	}
+
+	rotary = kzalloc(sizeof(struct bfin_rot), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!rotary || !input) {
+		error = -ENOMEM;
+		goto out1;
+	}
+
+	rotary->input = input;
+
+	rotary->up_key = pdata->rotary_up_key;
+	rotary->down_key = pdata->rotary_down_key;
+	rotary->button_key = pdata->rotary_button_key;
+	rotary->rel_code = pdata->rotary_rel_code;
+
+	error = rotary->irq = platform_get_irq(pdev, 0);
+	if (error < 0)
+		goto out1;
+
+	input->name = pdev->name;
+	input->phys = "bfin-rotary/input0";
+	input->dev.parent = &pdev->dev;
+
+	input_set_drvdata(input, rotary);
+
+	input->id.bustype = BUS_HOST;
+	input->id.vendor = 0x0001;
+	input->id.product = 0x0001;
+	input->id.version = 0x0100;
+
+	if (rotary->up_key) {
+		__set_bit(EV_KEY, input->evbit);
+		__set_bit(rotary->up_key, input->keybit);
+		__set_bit(rotary->down_key, input->keybit);
+	} else {
+		__set_bit(EV_REL, input->evbit);
+		__set_bit(rotary->rel_code, input->relbit);
+	}
+
+	if (rotary->button_key) {
+		__set_bit(EV_KEY, input->evbit);
+		__set_bit(rotary->button_key, input->keybit);
+	}
+
+	error = request_irq(rotary->irq, bfin_rotary_isr,
+			    0, dev_name(&pdev->dev), pdev);
+	if (error) {
+		dev_err(&pdev->dev,
+			"unable to claim irq %d; error %d\n",
+			rotary->irq, error);
+		goto out1;
+	}
+
+	error = input_register_device(input);
+	if (error) {
+		dev_err(&pdev->dev,
+			"unable to register input device (%d)\n", error);
+		goto out2;
+	}
+
+	if (pdata->rotary_button_key)
+		bfin_write_CNT_IMASK(CZMIE);
+
+	if (pdata->mode & ROT_DEBE)
+		bfin_write_CNT_DEBOUNCE(pdata->debounce & DPRESCALE);
+
+	if (pdata->mode)
+		bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() |
+					(pdata->mode & ~CNTE));
+
+	bfin_write_CNT_IMASK(bfin_read_CNT_IMASK() | UCIE | DCIE);
+	bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | CNTE);
+
+	platform_set_drvdata(pdev, rotary);
+	device_init_wakeup(&pdev->dev, 1);
+
+	return 0;
+
+out2:
+	free_irq(rotary->irq, pdev);
+out1:
+	input_free_device(input);
+	kfree(rotary);
+	peripheral_free_list(per_cnt);
+
+	return error;
+}
+
+static int __devexit bfin_rotary_remove(struct platform_device *pdev)
+{
+	struct bfin_rot *rotary = platform_get_drvdata(pdev);
+
+	bfin_write_CNT_CONFIG(0);
+	bfin_write_CNT_IMASK(0);
+
+	free_irq(rotary->irq, pdev);
+	input_unregister_device(rotary->input);
+	peripheral_free_list(per_cnt);
+
+	kfree(rotary);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_rotary_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct bfin_rot *rotary = platform_get_drvdata(pdev);
+
+	rotary->cnt_config = bfin_read_CNT_CONFIG();
+	rotary->cnt_imask = bfin_read_CNT_IMASK();
+	rotary->cnt_debounce = bfin_read_CNT_DEBOUNCE();
+
+	if (device_may_wakeup(&pdev->dev))
+		enable_irq_wake(rotary->irq);
+
+	return 0;
+}
+
+static int bfin_rotary_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct bfin_rot *rotary = platform_get_drvdata(pdev);
+
+	bfin_write_CNT_DEBOUNCE(rotary->cnt_debounce);
+	bfin_write_CNT_IMASK(rotary->cnt_imask);
+	bfin_write_CNT_CONFIG(rotary->cnt_config & ~CNTE);
+
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(rotary->irq);
+
+	if (rotary->cnt_config & CNTE)
+		bfin_write_CNT_CONFIG(rotary->cnt_config);
+
+	return 0;
+}
+
+static const struct dev_pm_ops bfin_rotary_pm_ops = {
+	.suspend	= bfin_rotary_suspend,
+	.resume		= bfin_rotary_resume,
+};
+#endif
+
+static struct platform_driver bfin_rotary_device_driver = {
+	.probe		= bfin_rotary_probe,
+	.remove		= __devexit_p(bfin_rotary_remove),
+	.driver		= {
+		.name	= "bfin-rotary",
+		.owner	= THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &bfin_rotary_pm_ops,
+#endif
+	},
+};
+module_platform_driver(bfin_rotary_device_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Rotary Counter driver for Blackfin Processors");
+MODULE_ALIAS("platform:bfin-rotary");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/bma150.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/bma150.c
new file mode 100644
index 0000000..e2f1e9f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/bma150.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2011 Bosch Sensortec GmbH
+ * Copyright (c) 2011 Unixphere
+ *
+ * This driver adds support for Bosch Sensortec's digital acceleration
+ * sensors BMA150 and SMB380.
+ * The SMB380 is fully compatible with BMA150 and only differs in packaging.
+ *
+ * The datasheet for the BMA150 chip can be found here:
+ * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMA150-DS000-07.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/bma150.h>
+
+#define ABSMAX_ACC_VAL		0x01FF
+#define ABSMIN_ACC_VAL		-(ABSMAX_ACC_VAL)
+
+/* Each axis is represented by a 2-byte data word */
+#define BMA150_XYZ_DATA_SIZE	6
+
+/* Input poll interval in milliseconds */
+#define BMA150_POLL_INTERVAL	10
+#define BMA150_POLL_MAX		200
+#define BMA150_POLL_MIN		0
+
+#define BMA150_BW_25HZ		0
+#define BMA150_BW_50HZ		1
+#define BMA150_BW_100HZ		2
+#define BMA150_BW_190HZ		3
+#define BMA150_BW_375HZ		4
+#define BMA150_BW_750HZ		5
+#define BMA150_BW_1500HZ	6
+
+#define BMA150_RANGE_2G		0
+#define BMA150_RANGE_4G		1
+#define BMA150_RANGE_8G		2
+
+#define BMA150_MODE_NORMAL	0
+#define BMA150_MODE_SLEEP	2
+#define BMA150_MODE_WAKE_UP	3
+
+/* Data register addresses */
+#define BMA150_DATA_0_REG	0x00
+#define BMA150_DATA_1_REG	0x01
+#define BMA150_DATA_2_REG	0x02
+
+/* Control register addresses */
+#define BMA150_CTRL_0_REG	0x0A
+#define BMA150_CTRL_1_REG	0x0B
+#define BMA150_CTRL_2_REG	0x14
+#define BMA150_CTRL_3_REG	0x15
+
+/* Configuration/Setting register addresses */
+#define BMA150_CFG_0_REG	0x0C
+#define BMA150_CFG_1_REG	0x0D
+#define BMA150_CFG_2_REG	0x0E
+#define BMA150_CFG_3_REG	0x0F
+#define BMA150_CFG_4_REG	0x10
+#define BMA150_CFG_5_REG	0x11
+
+#define BMA150_CHIP_ID		2
+#define BMA150_CHIP_ID_REG	BMA150_DATA_0_REG
+
+#define BMA150_ACC_X_LSB_REG	BMA150_DATA_2_REG
+
+#define BMA150_SLEEP_POS	0
+#define BMA150_SLEEP_MSK	0x01
+#define BMA150_SLEEP_REG	BMA150_CTRL_0_REG
+
+#define BMA150_BANDWIDTH_POS	0
+#define BMA150_BANDWIDTH_MSK	0x07
+#define BMA150_BANDWIDTH_REG	BMA150_CTRL_2_REG
+
+#define BMA150_RANGE_POS	3
+#define BMA150_RANGE_MSK	0x18
+#define BMA150_RANGE_REG	BMA150_CTRL_2_REG
+
+#define BMA150_WAKE_UP_POS	0
+#define BMA150_WAKE_UP_MSK	0x01
+#define BMA150_WAKE_UP_REG	BMA150_CTRL_3_REG
+
+#define BMA150_SW_RES_POS	1
+#define BMA150_SW_RES_MSK	0x02
+#define BMA150_SW_RES_REG	BMA150_CTRL_0_REG
+
+/* Any-motion interrupt register fields */
+#define BMA150_ANY_MOTION_EN_POS	6
+#define BMA150_ANY_MOTION_EN_MSK	0x40
+#define BMA150_ANY_MOTION_EN_REG	BMA150_CTRL_1_REG
+
+#define BMA150_ANY_MOTION_DUR_POS	6
+#define BMA150_ANY_MOTION_DUR_MSK	0xC0
+#define BMA150_ANY_MOTION_DUR_REG	BMA150_CFG_5_REG
+
+#define BMA150_ANY_MOTION_THRES_REG	BMA150_CFG_4_REG
+
+/* Advanced interrupt register fields */
+#define BMA150_ADV_INT_EN_POS		6
+#define BMA150_ADV_INT_EN_MSK		0x40
+#define BMA150_ADV_INT_EN_REG		BMA150_CTRL_3_REG
+
+/* High-G interrupt register fields */
+#define BMA150_HIGH_G_EN_POS		1
+#define BMA150_HIGH_G_EN_MSK		0x02
+#define BMA150_HIGH_G_EN_REG		BMA150_CTRL_1_REG
+
+#define BMA150_HIGH_G_HYST_POS		3
+#define BMA150_HIGH_G_HYST_MSK		0x38
+#define BMA150_HIGH_G_HYST_REG		BMA150_CFG_5_REG
+
+#define BMA150_HIGH_G_DUR_REG		BMA150_CFG_3_REG
+#define BMA150_HIGH_G_THRES_REG		BMA150_CFG_2_REG
+
+/* Low-G interrupt register fields */
+#define BMA150_LOW_G_EN_POS		0
+#define BMA150_LOW_G_EN_MSK		0x01
+#define BMA150_LOW_G_EN_REG		BMA150_CTRL_1_REG
+
+#define BMA150_LOW_G_HYST_POS		0
+#define BMA150_LOW_G_HYST_MSK		0x07
+#define BMA150_LOW_G_HYST_REG		BMA150_CFG_5_REG
+
+#define BMA150_LOW_G_DUR_REG		BMA150_CFG_1_REG
+#define BMA150_LOW_G_THRES_REG		BMA150_CFG_0_REG
+
+struct bma150_data {
+	struct i2c_client *client;
+	struct input_polled_dev *input_polled;
+	struct input_dev *input;
+	u8 mode;
+};
+
+/*
+ * The settings for the given range, bandwidth and interrupt features
+ * are stated and verified by Bosch Sensortec where they are configured
+ * to provide a generic sensitivity performance.
+ */
+static struct bma150_cfg default_cfg __devinitdata = {
+	.any_motion_int = 1,
+	.hg_int = 1,
+	.lg_int = 1,
+	.any_motion_dur = 0,
+	.any_motion_thres = 0,
+	.hg_hyst = 0,
+	.hg_dur = 150,
+	.hg_thres = 160,
+	.lg_hyst = 0,
+	.lg_dur = 150,
+	.lg_thres = 20,
+	.range = BMA150_RANGE_2G,
+	.bandwidth = BMA150_BW_50HZ
+};
+
+static int bma150_write_byte(struct i2c_client *client, u8 reg, u8 val)
+{
+	s32 ret;
+
+	/* As per specification, disable irq in between register writes */
+	if (client->irq)
+		disable_irq_nosync(client->irq);
+
+	ret = i2c_smbus_write_byte_data(client, reg, val);
+
+	if (client->irq)
+		enable_irq(client->irq);
+
+	return ret;
+}
+
+static int bma150_set_reg_bits(struct i2c_client *client,
+					int val, int shift, u8 mask, u8 reg)
+{
+	int data;
+
+	data = i2c_smbus_read_byte_data(client, reg);
+	if (data < 0)
+		return data;
+
+	data = (data & ~mask) | ((val << shift) & mask);
+	return bma150_write_byte(client, reg, data);
+}
+
+static int bma150_set_mode(struct bma150_data *bma150, u8 mode)
+{
+	int error;
+
+	error = bma150_set_reg_bits(bma150->client, mode, BMA150_WAKE_UP_POS,
+				BMA150_WAKE_UP_MSK, BMA150_WAKE_UP_REG);
+	if (error)
+		return error;
+
+	error = bma150_set_reg_bits(bma150->client, mode, BMA150_SLEEP_POS,
+				BMA150_SLEEP_MSK, BMA150_SLEEP_REG);
+	if (error)
+		return error;
+
+	if (mode == BMA150_MODE_NORMAL)
+		msleep(2);
+
+	bma150->mode = mode;
+	return 0;
+}
+
+static int __devinit bma150_soft_reset(struct bma150_data *bma150)
+{
+	int error;
+
+	error = bma150_set_reg_bits(bma150->client, 1, BMA150_SW_RES_POS,
+				BMA150_SW_RES_MSK, BMA150_SW_RES_REG);
+	if (error)
+		return error;
+
+	msleep(2);
+	return 0;
+}
+
+static int __devinit bma150_set_range(struct bma150_data *bma150, u8 range)
+{
+	return bma150_set_reg_bits(bma150->client, range, BMA150_RANGE_POS,
+				BMA150_RANGE_MSK, BMA150_RANGE_REG);
+}
+
+static int __devinit bma150_set_bandwidth(struct bma150_data *bma150, u8 bw)
+{
+	return bma150_set_reg_bits(bma150->client, bw, BMA150_BANDWIDTH_POS,
+				BMA150_BANDWIDTH_MSK, BMA150_BANDWIDTH_REG);
+}
+
+static int __devinit bma150_set_low_g_interrupt(struct bma150_data *bma150,
+					u8 enable, u8 hyst, u8 dur, u8 thres)
+{
+	int error;
+
+	error = bma150_set_reg_bits(bma150->client, hyst,
+				BMA150_LOW_G_HYST_POS, BMA150_LOW_G_HYST_MSK,
+				BMA150_LOW_G_HYST_REG);
+	if (error)
+		return error;
+
+	error = bma150_write_byte(bma150->client, BMA150_LOW_G_DUR_REG, dur);
+	if (error)
+		return error;
+
+	error = bma150_write_byte(bma150->client, BMA150_LOW_G_THRES_REG, thres);
+	if (error)
+		return error;
+
+	return bma150_set_reg_bits(bma150->client, !!enable,
+				BMA150_LOW_G_EN_POS, BMA150_LOW_G_EN_MSK,
+				BMA150_LOW_G_EN_REG);
+}
+
+static int __devinit bma150_set_high_g_interrupt(struct bma150_data *bma150,
+					u8 enable, u8 hyst, u8 dur, u8 thres)
+{
+	int error;
+
+	error = bma150_set_reg_bits(bma150->client, hyst,
+				BMA150_HIGH_G_HYST_POS, BMA150_HIGH_G_HYST_MSK,
+				BMA150_HIGH_G_HYST_REG);
+	if (error)
+		return error;
+
+	error = bma150_write_byte(bma150->client,
+				BMA150_HIGH_G_DUR_REG, dur);
+	if (error)
+		return error;
+
+	error = bma150_write_byte(bma150->client,
+				BMA150_HIGH_G_THRES_REG, thres);
+	if (error)
+		return error;
+
+	return bma150_set_reg_bits(bma150->client, !!enable,
+				BMA150_HIGH_G_EN_POS, BMA150_HIGH_G_EN_MSK,
+				BMA150_HIGH_G_EN_REG);
+}
+
+
+static int __devinit bma150_set_any_motion_interrupt(struct bma150_data *bma150,
+						u8 enable, u8 dur, u8 thres)
+{
+	int error;
+
+	error = bma150_set_reg_bits(bma150->client, dur,
+				BMA150_ANY_MOTION_DUR_POS,
+				BMA150_ANY_MOTION_DUR_MSK,
+				BMA150_ANY_MOTION_DUR_REG);
+	if (error)
+		return error;
+
+	error = bma150_write_byte(bma150->client,
+				BMA150_ANY_MOTION_THRES_REG, thres);
+	if (error)
+		return error;
+
+	error = bma150_set_reg_bits(bma150->client, !!enable,
+				BMA150_ADV_INT_EN_POS, BMA150_ADV_INT_EN_MSK,
+				BMA150_ADV_INT_EN_REG);
+	if (error)
+		return error;
+
+	return bma150_set_reg_bits(bma150->client, !!enable,
+				BMA150_ANY_MOTION_EN_POS,
+				BMA150_ANY_MOTION_EN_MSK,
+				BMA150_ANY_MOTION_EN_REG);
+}
+
+static void bma150_report_xyz(struct bma150_data *bma150)
+{
+	u8 data[BMA150_XYZ_DATA_SIZE];
+	s16 x, y, z;
+	s32 ret;
+
+	ret = i2c_smbus_read_i2c_block_data(bma150->client,
+			BMA150_ACC_X_LSB_REG, BMA150_XYZ_DATA_SIZE, data);
+	if (ret != BMA150_XYZ_DATA_SIZE)
+		return;
+
+	x = ((0xc0 & data[0]) >> 6) | (data[1] << 2);
+	y = ((0xc0 & data[2]) >> 6) | (data[3] << 2);
+	z = ((0xc0 & data[4]) >> 6) | (data[5] << 2);
+
+	/* sign extension */
+	x = (s16) (x << 6) >> 6;
+	y = (s16) (y << 6) >> 6;
+	z = (s16) (z << 6) >> 6;
+
+	input_report_abs(bma150->input, ABS_X, x);
+	input_report_abs(bma150->input, ABS_Y, y);
+	input_report_abs(bma150->input, ABS_Z, z);
+	input_sync(bma150->input);
+}
+
+static irqreturn_t bma150_irq_thread(int irq, void *dev)
+{
+	bma150_report_xyz(dev);
+
+	return IRQ_HANDLED;
+}
+
+static void bma150_poll(struct input_polled_dev *dev)
+{
+	bma150_report_xyz(dev->private);
+}
+
+static int bma150_open(struct bma150_data *bma150)
+{
+	int error;
+
+	error = pm_runtime_get_sync(&bma150->client->dev);
+	if (error && error != -ENOSYS)
+		return error;
+
+	/*
+	 * See if runtime PM woke up the device. If runtime PM
+	 * is disabled we need to do it ourselves.
+	 */
+	if (bma150->mode != BMA150_MODE_NORMAL) {
+		error = bma150_set_mode(bma150, BMA150_MODE_NORMAL);
+		if (error)
+			return error;
+	}
+
+	return 0;
+}
+
+static void bma150_close(struct bma150_data *bma150)
+{
+	pm_runtime_put_sync(&bma150->client->dev);
+
+	if (bma150->mode != BMA150_MODE_SLEEP)
+		bma150_set_mode(bma150, BMA150_MODE_SLEEP);
+}
+
+static int bma150_irq_open(struct input_dev *input)
+{
+	struct bma150_data *bma150 = input_get_drvdata(input);
+
+	return bma150_open(bma150);
+}
+
+static void bma150_irq_close(struct input_dev *input)
+{
+	struct bma150_data *bma150 = input_get_drvdata(input);
+
+	bma150_close(bma150);
+}
+
+static void bma150_poll_open(struct input_polled_dev *ipoll_dev)
+{
+	struct bma150_data *bma150 = ipoll_dev->private;
+
+	bma150_open(bma150);
+}
+
+static void bma150_poll_close(struct input_polled_dev *ipoll_dev)
+{
+	struct bma150_data *bma150 = ipoll_dev->private;
+
+	bma150_close(bma150);
+}
+
+static int __devinit bma150_initialize(struct bma150_data *bma150,
+				       const struct bma150_cfg *cfg)
+{
+	int error;
+
+	error = bma150_soft_reset(bma150);
+	if (error)
+		return error;
+
+	error = bma150_set_bandwidth(bma150, cfg->bandwidth);
+	if (error)
+		return error;
+
+	error = bma150_set_range(bma150, cfg->range);
+	if (error)
+		return error;
+
+	if (bma150->client->irq) {
+		error = bma150_set_any_motion_interrupt(bma150,
+					cfg->any_motion_int,
+					cfg->any_motion_dur,
+					cfg->any_motion_thres);
+		if (error)
+			return error;
+
+		error = bma150_set_high_g_interrupt(bma150,
+					cfg->hg_int, cfg->hg_hyst,
+					cfg->hg_dur, cfg->hg_thres);
+		if (error)
+			return error;
+
+		error = bma150_set_low_g_interrupt(bma150,
+					cfg->lg_int, cfg->lg_hyst,
+					cfg->lg_dur, cfg->lg_thres);
+		if (error)
+			return error;
+	}
+
+	return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
+}
+
+static void __devinit bma150_init_input_device(struct bma150_data *bma150,
+						struct input_dev *idev)
+{
+	idev->name = BMA150_DRIVER;
+	idev->phys = BMA150_DRIVER "/input0";
+	idev->id.bustype = BUS_I2C;
+	idev->dev.parent = &bma150->client->dev;
+
+	idev->evbit[0] = BIT_MASK(EV_ABS);
+	input_set_abs_params(idev, ABS_X, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
+	input_set_abs_params(idev, ABS_Y, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
+	input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
+}
+
+static int __devinit bma150_register_input_device(struct bma150_data *bma150)
+{
+	struct input_dev *idev;
+	int error;
+
+	idev = input_allocate_device();
+	if (!idev)
+		return -ENOMEM;
+
+	bma150_init_input_device(bma150, idev);
+
+	idev->open = bma150_irq_open;
+	idev->close = bma150_irq_close;
+	input_set_drvdata(idev, bma150);
+
+	error = input_register_device(idev);
+	if (error) {
+		input_free_device(idev);
+		return error;
+	}
+
+	bma150->input = idev;
+	return 0;
+}
+
+static int __devinit bma150_register_polled_device(struct bma150_data *bma150)
+{
+	struct input_polled_dev *ipoll_dev;
+	int error;
+
+	ipoll_dev = input_allocate_polled_device();
+	if (!ipoll_dev)
+		return -ENOMEM;
+
+	ipoll_dev->private = bma150;
+	ipoll_dev->open = bma150_poll_open;
+	ipoll_dev->close = bma150_poll_close;
+	ipoll_dev->poll = bma150_poll;
+	ipoll_dev->poll_interval = BMA150_POLL_INTERVAL;
+	ipoll_dev->poll_interval_min = BMA150_POLL_MIN;
+	ipoll_dev->poll_interval_max = BMA150_POLL_MAX;
+
+	bma150_init_input_device(bma150, ipoll_dev->input);
+
+	error = input_register_polled_device(ipoll_dev);
+	if (error) {
+		input_free_polled_device(ipoll_dev);
+		return error;
+	}
+
+	bma150->input_polled = ipoll_dev;
+	bma150->input = ipoll_dev->input;
+
+	return 0;
+}
+
+static int __devinit bma150_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
+{
+	const struct bma150_platform_data *pdata = client->dev.platform_data;
+	const struct bma150_cfg *cfg;
+	struct bma150_data *bma150;
+	int chip_id;
+	int error;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "i2c_check_functionality error\n");
+		return -EIO;
+	}
+
+	chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);
+	if (chip_id != BMA150_CHIP_ID) {
+		dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
+		return -EINVAL;
+	}
+
+	bma150 = kzalloc(sizeof(struct bma150_data), GFP_KERNEL);
+	if (!bma150)
+		return -ENOMEM;
+
+	bma150->client = client;
+
+	if (pdata) {
+		if (pdata->irq_gpio_cfg) {
+			error = pdata->irq_gpio_cfg();
+			if (error) {
+				dev_err(&client->dev,
+					"IRQ GPIO conf. error %d, error %d\n",
+					client->irq, error);
+				goto err_free_mem;
+			}
+		}
+		cfg = &pdata->cfg;
+	} else {
+		cfg = &default_cfg;
+	}
+
+	error = bma150_initialize(bma150, cfg);
+	if (error)
+		goto err_free_mem;
+
+	if (client->irq > 0) {
+		error = bma150_register_input_device(bma150);
+		if (error)
+			goto err_free_mem;
+
+		error = request_threaded_irq(client->irq,
+					NULL, bma150_irq_thread,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					BMA150_DRIVER, bma150);
+		if (error) {
+			dev_err(&client->dev,
+				"irq request failed %d, error %d\n",
+				client->irq, error);
+			input_unregister_device(bma150->input);
+			goto err_free_mem;
+		}
+	} else {
+		error = bma150_register_polled_device(bma150);
+		if (error)
+			goto err_free_mem;
+	}
+
+	i2c_set_clientdata(client, bma150);
+
+	pm_runtime_enable(&client->dev);
+
+	return 0;
+
+err_free_mem:
+	kfree(bma150);
+	return error;
+}
+
+static int __devexit bma150_remove(struct i2c_client *client)
+{
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	pm_runtime_disable(&client->dev);
+
+	if (client->irq > 0) {
+		free_irq(client->irq, bma150);
+		input_unregister_device(bma150->input);
+	} else {
+		input_unregister_polled_device(bma150->input_polled);
+		input_free_polled_device(bma150->input_polled);
+	}
+
+	kfree(bma150);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bma150_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
+}
+
+static int bma150_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	return bma150_set_mode(bma150, BMA150_MODE_NORMAL);
+}
+#endif
+
+static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
+
+static const struct i2c_device_id bma150_id[] = {
+	{ "bma150", 0 },
+	{ "smb380", 0 },
+	{ "bma023", 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, bma150_id);
+
+static struct i2c_driver bma150_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= BMA150_DRIVER,
+		.pm	= &bma150_pm,
+	},
+	.class		= I2C_CLASS_HWMON,
+	.id_table	= bma150_id,
+	.probe		= bma150_probe,
+	.remove		= __devexit_p(bma150_remove),
+};
+
+module_i2c_driver(bma150_driver);
+
+MODULE_AUTHOR("Albert Zhang <xu.zhang@bosch-sensortec.com>");
+MODULE_DESCRIPTION("BMA150 driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/cm109.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/cm109.c
new file mode 100644
index 0000000..ab86051
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/cm109.c
@@ -0,0 +1,911 @@
+/*
+ * Driver for the VoIP USB phones with CM109 chipsets.
+ *
+ * Copyright (C) 2007 - 2008 Alfred E. Heggestad <aeh@db.org>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ */
+
+/*
+ *   Tested devices:
+ *	- Komunikate KIP1000
+ *	- Genius G-talk
+ *	- Allied-Telesis Corega USBPH01
+ *	- ...
+ *
+ * This driver is based on the yealink.c driver
+ *
+ * Thanks to:
+ *   - Authors of yealink.c
+ *   - Thomas Reitmayr
+ *   - Oliver Neukum for good review comments and code
+ *   - Shaun Jackman <sjackman@gmail.com> for Genius G-talk keymap
+ *   - Dmitry Torokhov for valuable input and review
+ *
+ * Todo:
+ *   - Read/write EEPROM
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/rwsem.h>
+#include <linux/usb/input.h>
+
+#define DRIVER_VERSION "20080805"
+#define DRIVER_AUTHOR  "Alfred E. Heggestad"
+#define DRIVER_DESC    "CM109 phone driver"
+
+static char *phone = "kip1000";
+module_param(phone, charp, S_IRUSR);
+MODULE_PARM_DESC(phone, "Phone name {kip1000, gtalk, usbph01, atcom}");
+
+enum {
+	/* HID Registers */
+	HID_IR0 = 0x00, /* Record/Playback-mute button, Volume up/down  */
+	HID_IR1 = 0x01, /* GPI, generic registers or EEPROM_DATA0       */
+	HID_IR2 = 0x02, /* Generic registers or EEPROM_DATA1            */
+	HID_IR3 = 0x03, /* Generic registers or EEPROM_CTRL             */
+	HID_OR0 = 0x00, /* Mapping control, buzzer, SPDIF (offset 0x04) */
+	HID_OR1 = 0x01, /* GPO - General Purpose Output                 */
+	HID_OR2 = 0x02, /* Set GPIO to input/output mode                */
+	HID_OR3 = 0x03, /* SPDIF status channel or EEPROM_CTRL          */
+
+	/* HID_IR0 */
+	RECORD_MUTE   = 1 << 3,
+	PLAYBACK_MUTE = 1 << 2,
+	VOLUME_DOWN   = 1 << 1,
+	VOLUME_UP     = 1 << 0,
+
+	/* HID_OR0 */
+	/* bits 7-6
+	   0: HID_OR1-2 are used for GPO; HID_OR0, 3 are used for buzzer
+	      and SPDIF
+	   1: HID_OR0-3 are used as generic HID registers
+	   2: Values written to HID_OR0-3 are also mapped to MCU_CTRL,
+	      EEPROM_DATA0-1, EEPROM_CTRL (see Note)
+	   3: Reserved
+	 */
+	HID_OR_GPO_BUZ_SPDIF   = 0 << 6,
+	HID_OR_GENERIC_HID_REG = 1 << 6,
+	HID_OR_MAP_MCU_EEPROM  = 2 << 6,
+
+	BUZZER_ON = 1 << 5,
+
+	/* up to 256 normal keys, up to 16 special keys */
+	KEYMAP_SIZE = 256 + 16,
+};
+
+/* CM109 protocol packet */
+struct cm109_ctl_packet {
+	u8 byte[4];
+} __attribute__ ((packed));
+
+enum { USB_PKT_LEN = sizeof(struct cm109_ctl_packet) };
+
+/* CM109 device structure */
+struct cm109_dev {
+	struct input_dev *idev;	 /* input device */
+	struct usb_device *udev; /* usb device */
+	struct usb_interface *intf;
+
+	/* irq input channel */
+	struct cm109_ctl_packet *irq_data;
+	dma_addr_t irq_dma;
+	struct urb *urb_irq;
+
+	/* control output channel */
+	struct cm109_ctl_packet *ctl_data;
+	dma_addr_t ctl_dma;
+	struct usb_ctrlrequest *ctl_req;
+	struct urb *urb_ctl;
+	/*
+	 * The 3 bitfields below are protected by ctl_submit_lock.
+	 * They have to be separate since they are accessed from IRQ
+	 * context.
+	 */
+	unsigned irq_urb_pending:1;	/* irq_urb is in flight */
+	unsigned ctl_urb_pending:1;	/* ctl_urb is in flight */
+	unsigned buzzer_pending:1;	/* need to issue buzz command */
+	spinlock_t ctl_submit_lock;
+
+	unsigned char buzzer_state;	/* on/off */
+
+	/* flags */
+	unsigned open:1;
+	unsigned resetting:1;
+	unsigned shutdown:1;
+
+	/* This mutex protects writes to the above flags */
+	struct mutex pm_mutex;
+
+	unsigned short keymap[KEYMAP_SIZE];
+
+	char phys[64];		/* physical device path */
+	int key_code;		/* last reported key */
+	int keybit;		/* 0=new scan  1,2,4,8=scan columns  */
+	u8 gpi;			/* Cached value of GPI (high nibble) */
+};
+
+/******************************************************************************
+ * CM109 key interface
+ *****************************************************************************/
+
+static unsigned short special_keymap(int code)
+{
+	if (code > 0xff) {
+		switch (code - 0xff) {
+		case RECORD_MUTE:	return KEY_MUTE;
+		case PLAYBACK_MUTE:	return KEY_MUTE;
+		case VOLUME_DOWN:	return KEY_VOLUMEDOWN;
+		case VOLUME_UP:		return KEY_VOLUMEUP;
+		}
+	}
+	return KEY_RESERVED;
+}
+
+/* Map device buttons to internal key events.
+ *
+ * The "up" and "down" keys, are symbolised by arrows on the button.
+ * The "pickup" and "hangup" keys are symbolised by a green and red phone
+ * on the button.
+
+ Komunikate KIP1000 Keyboard Matrix
+
+     -> -- 1 -- 2 -- 3  --> GPI pin 4 (0x10)
+      |    |    |    |
+     <- -- 4 -- 5 -- 6  --> GPI pin 5 (0x20)
+      |    |    |    |
+     END - 7 -- 8 -- 9  --> GPI pin 6 (0x40)
+      |    |    |    |
+     OK -- * -- 0 -- #  --> GPI pin 7 (0x80)
+      |    |    |    |
+
+     /|\  /|\  /|\  /|\
+      |    |    |    |
+GPO
+pin:  3    2    1    0
+     0x8  0x4  0x2  0x1
+
+ */
+static unsigned short keymap_kip1000(int scancode)
+{
+	switch (scancode) {				/* phone key:   */
+	case 0x82: return KEY_NUMERIC_0;		/*   0          */
+	case 0x14: return KEY_NUMERIC_1;		/*   1          */
+	case 0x12: return KEY_NUMERIC_2;		/*   2          */
+	case 0x11: return KEY_NUMERIC_3;		/*   3          */
+	case 0x24: return KEY_NUMERIC_4;		/*   4          */
+	case 0x22: return KEY_NUMERIC_5;		/*   5          */
+	case 0x21: return KEY_NUMERIC_6;		/*   6          */
+	case 0x44: return KEY_NUMERIC_7;		/*   7          */
+	case 0x42: return KEY_NUMERIC_8;		/*   8          */
+	case 0x41: return KEY_NUMERIC_9;		/*   9          */
+	case 0x81: return KEY_NUMERIC_POUND;		/*   #          */
+	case 0x84: return KEY_NUMERIC_STAR;		/*   *          */
+	case 0x88: return KEY_ENTER;			/*   pickup     */
+	case 0x48: return KEY_ESC;			/*   hangup     */
+	case 0x28: return KEY_LEFT;			/*   IN         */
+	case 0x18: return KEY_RIGHT;			/*   OUT        */
+	default:   return special_keymap(scancode);
+	}
+}
+
+/*
+  Contributed by Shaun Jackman <sjackman@gmail.com>
+
+  Genius G-Talk keyboard matrix
+     0 1 2 3
+  4: 0 4 8 Talk
+  5: 1 5 9 End
+  6: 2 6 # Up
+  7: 3 7 * Down
+*/
+static unsigned short keymap_gtalk(int scancode)
+{
+	switch (scancode) {
+	case 0x11: return KEY_NUMERIC_0;
+	case 0x21: return KEY_NUMERIC_1;
+	case 0x41: return KEY_NUMERIC_2;
+	case 0x81: return KEY_NUMERIC_3;
+	case 0x12: return KEY_NUMERIC_4;
+	case 0x22: return KEY_NUMERIC_5;
+	case 0x42: return KEY_NUMERIC_6;
+	case 0x82: return KEY_NUMERIC_7;
+	case 0x14: return KEY_NUMERIC_8;
+	case 0x24: return KEY_NUMERIC_9;
+	case 0x44: return KEY_NUMERIC_POUND;	/* # */
+	case 0x84: return KEY_NUMERIC_STAR;	/* * */
+	case 0x18: return KEY_ENTER;		/* Talk (green handset) */
+	case 0x28: return KEY_ESC;		/* End (red handset) */
+	case 0x48: return KEY_UP;		/* Menu up (rocker switch) */
+	case 0x88: return KEY_DOWN;		/* Menu down (rocker switch) */
+	default:   return special_keymap(scancode);
+	}
+}
+
+/*
+ * Keymap for Allied-Telesis Corega USBPH01
+ * http://www.alliedtelesis-corega.com/2/1344/1437/1360/chprd.html
+ *
+ * Contributed by july@nat.bg
+ */
+static unsigned short keymap_usbph01(int scancode)
+{
+	switch (scancode) {
+	case 0x11: return KEY_NUMERIC_0;		/*   0          */
+	case 0x21: return KEY_NUMERIC_1;		/*   1          */
+	case 0x41: return KEY_NUMERIC_2;		/*   2          */
+	case 0x81: return KEY_NUMERIC_3;		/*   3          */
+	case 0x12: return KEY_NUMERIC_4;		/*   4          */
+	case 0x22: return KEY_NUMERIC_5;		/*   5          */
+	case 0x42: return KEY_NUMERIC_6;		/*   6          */
+	case 0x82: return KEY_NUMERIC_7;		/*   7          */
+	case 0x14: return KEY_NUMERIC_8;		/*   8          */
+	case 0x24: return KEY_NUMERIC_9;		/*   9          */
+	case 0x44: return KEY_NUMERIC_POUND;		/*   #          */
+	case 0x84: return KEY_NUMERIC_STAR;		/*   *          */
+	case 0x18: return KEY_ENTER;			/*   pickup     */
+	case 0x28: return KEY_ESC;			/*   hangup     */
+	case 0x48: return KEY_LEFT;			/*   IN         */
+	case 0x88: return KEY_RIGHT;			/*   OUT        */
+	default:   return special_keymap(scancode);
+	}
+}
+
+/*
+ * Keymap for ATCom AU-100
+ * http://www.atcom.cn/products.html 
+ * http://www.packetizer.com/products/au100/
+ * http://www.voip-info.org/wiki/view/AU-100
+ *
+ * Contributed by daniel@gimpelevich.san-francisco.ca.us
+ */
+static unsigned short keymap_atcom(int scancode)
+{
+	switch (scancode) {				/* phone key:   */
+	case 0x82: return KEY_NUMERIC_0;		/*   0          */
+	case 0x11: return KEY_NUMERIC_1;		/*   1          */
+	case 0x12: return KEY_NUMERIC_2;		/*   2          */
+	case 0x14: return KEY_NUMERIC_3;		/*   3          */
+	case 0x21: return KEY_NUMERIC_4;		/*   4          */
+	case 0x22: return KEY_NUMERIC_5;		/*   5          */
+	case 0x24: return KEY_NUMERIC_6;		/*   6          */
+	case 0x41: return KEY_NUMERIC_7;		/*   7          */
+	case 0x42: return KEY_NUMERIC_8;		/*   8          */
+	case 0x44: return KEY_NUMERIC_9;		/*   9          */
+	case 0x84: return KEY_NUMERIC_POUND;		/*   #          */
+	case 0x81: return KEY_NUMERIC_STAR;		/*   *          */
+	case 0x18: return KEY_ENTER;			/*   pickup     */
+	case 0x28: return KEY_ESC;			/*   hangup     */
+	case 0x48: return KEY_LEFT;			/* left arrow   */
+	case 0x88: return KEY_RIGHT;			/* right arrow  */
+	default:   return special_keymap(scancode);
+	}
+}
+
+static unsigned short (*keymap)(int) = keymap_kip1000;
+
+/*
+ * Completes a request by converting the data into events for the
+ * input subsystem.
+ */
+static void report_key(struct cm109_dev *dev, int key)
+{
+	struct input_dev *idev = dev->idev;
+
+	if (dev->key_code >= 0) {
+		/* old key up */
+		input_report_key(idev, dev->key_code, 0);
+	}
+
+	dev->key_code = key;
+	if (key >= 0) {
+		/* new valid key */
+		input_report_key(idev, key, 1);
+	}
+
+	input_sync(idev);
+}
+
+/******************************************************************************
+ * CM109 usb communication interface
+ *****************************************************************************/
+
+static void cm109_submit_buzz_toggle(struct cm109_dev *dev)
+{
+	int error;
+
+	if (dev->buzzer_state)
+		dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
+	else
+		dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
+
+	error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
+	if (error)
+		err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
+}
+
+/*
+ * IRQ handler
+ */
+static void cm109_urb_irq_callback(struct urb *urb)
+{
+	struct cm109_dev *dev = urb->context;
+	const int status = urb->status;
+	int error;
+
+	dev_dbg(&urb->dev->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
+	     dev->irq_data->byte[0],
+	     dev->irq_data->byte[1],
+	     dev->irq_data->byte[2],
+	     dev->irq_data->byte[3],
+	     dev->keybit);
+
+	if (status) {
+		if (status == -ESHUTDOWN)
+			return;
+		err("%s: urb status %d", __func__, status);
+	}
+
+	/* Special keys */
+	if (dev->irq_data->byte[HID_IR0] & 0x0f) {
+		const int code = (dev->irq_data->byte[HID_IR0] & 0x0f);
+		report_key(dev, dev->keymap[0xff + code]);
+	}
+
+	/* Scan key column */
+	if (dev->keybit == 0xf) {
+
+		/* Any changes ? */
+		if ((dev->gpi & 0xf0) == (dev->irq_data->byte[HID_IR1] & 0xf0))
+			goto out;
+
+		dev->gpi = dev->irq_data->byte[HID_IR1] & 0xf0;
+		dev->keybit = 0x1;
+	} else {
+		report_key(dev, dev->keymap[dev->irq_data->byte[HID_IR1]]);
+
+		dev->keybit <<= 1;
+		if (dev->keybit > 0x8)
+			dev->keybit = 0xf;
+	}
+
+ out:
+
+	spin_lock(&dev->ctl_submit_lock);
+
+	dev->irq_urb_pending = 0;
+
+	if (likely(!dev->shutdown)) {
+
+		if (dev->buzzer_state)
+			dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
+		else
+			dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
+
+		dev->ctl_data->byte[HID_OR1] = dev->keybit;
+		dev->ctl_data->byte[HID_OR2] = dev->keybit;
+
+		dev->buzzer_pending = 0;
+		dev->ctl_urb_pending = 1;
+
+		error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
+		if (error)
+			err("%s: usb_submit_urb (urb_ctl) failed %d",
+				__func__, error);
+	}
+
+	spin_unlock(&dev->ctl_submit_lock);
+}
+
+static void cm109_urb_ctl_callback(struct urb *urb)
+{
+	struct cm109_dev *dev = urb->context;
+	const int status = urb->status;
+	int error;
+
+	dev_dbg(&urb->dev->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
+	     dev->ctl_data->byte[0],
+	     dev->ctl_data->byte[1],
+	     dev->ctl_data->byte[2],
+	     dev->ctl_data->byte[3]);
+
+	if (status)
+		err("%s: urb status %d", __func__, status);
+
+	spin_lock(&dev->ctl_submit_lock);
+
+	dev->ctl_urb_pending = 0;
+
+	if (likely(!dev->shutdown)) {
+
+		if (dev->buzzer_pending) {
+			dev->buzzer_pending = 0;
+			dev->ctl_urb_pending = 1;
+			cm109_submit_buzz_toggle(dev);
+		} else if (likely(!dev->irq_urb_pending)) {
+			/* ask for key data */
+			dev->irq_urb_pending = 1;
+			error = usb_submit_urb(dev->urb_irq, GFP_ATOMIC);
+			if (error)
+				err("%s: usb_submit_urb (urb_irq) failed %d",
+					__func__, error);
+		}
+	}
+
+	spin_unlock(&dev->ctl_submit_lock);
+}
+
+static void cm109_toggle_buzzer_async(struct cm109_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->ctl_submit_lock, flags);
+
+	if (dev->ctl_urb_pending) {
+		/* URB completion will resubmit */
+		dev->buzzer_pending = 1;
+	} else {
+		dev->ctl_urb_pending = 1;
+		cm109_submit_buzz_toggle(dev);
+	}
+
+	spin_unlock_irqrestore(&dev->ctl_submit_lock, flags);
+}
+
+static void cm109_toggle_buzzer_sync(struct cm109_dev *dev, int on)
+{
+	int error;
+
+	if (on)
+		dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
+	else
+		dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
+
+	error = usb_control_msg(dev->udev,
+				usb_sndctrlpipe(dev->udev, 0),
+				dev->ctl_req->bRequest,
+				dev->ctl_req->bRequestType,
+				le16_to_cpu(dev->ctl_req->wValue),
+				le16_to_cpu(dev->ctl_req->wIndex),
+				dev->ctl_data,
+				USB_PKT_LEN, USB_CTRL_SET_TIMEOUT);
+	if (error < 0 && error != -EINTR)
+		err("%s: usb_control_msg() failed %d", __func__, error);
+}
+
+static void cm109_stop_traffic(struct cm109_dev *dev)
+{
+	dev->shutdown = 1;
+	/*
+	 * Make sure other CPUs see this
+	 */
+	smp_wmb();
+
+	usb_kill_urb(dev->urb_ctl);
+	usb_kill_urb(dev->urb_irq);
+
+	cm109_toggle_buzzer_sync(dev, 0);
+
+	dev->shutdown = 0;
+	smp_wmb();
+}
+
+static void cm109_restore_state(struct cm109_dev *dev)
+{
+	if (dev->open) {
+		/*
+		 * Restore buzzer state.
+		 * This will also kick regular URB submission
+		 */
+		cm109_toggle_buzzer_async(dev);
+	}
+}
+
+/******************************************************************************
+ * input event interface
+ *****************************************************************************/
+
+static int cm109_input_open(struct input_dev *idev)
+{
+	struct cm109_dev *dev = input_get_drvdata(idev);
+	int error;
+
+	error = usb_autopm_get_interface(dev->intf);
+	if (error < 0) {
+		err("%s - cannot autoresume, result %d",
+		    __func__, error);
+		return error;
+	}
+
+	mutex_lock(&dev->pm_mutex);
+
+	dev->buzzer_state = 0;
+	dev->key_code = -1;	/* no keys pressed */
+	dev->keybit = 0xf;
+
+	/* issue INIT */
+	dev->ctl_data->byte[HID_OR0] = HID_OR_GPO_BUZ_SPDIF;
+	dev->ctl_data->byte[HID_OR1] = dev->keybit;
+	dev->ctl_data->byte[HID_OR2] = dev->keybit;
+	dev->ctl_data->byte[HID_OR3] = 0x00;
+
+	error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL);
+	if (error)
+		err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
+	else
+		dev->open = 1;
+
+	mutex_unlock(&dev->pm_mutex);
+
+	if (error)
+		usb_autopm_put_interface(dev->intf);
+
+	return error;
+}
+
+static void cm109_input_close(struct input_dev *idev)
+{
+	struct cm109_dev *dev = input_get_drvdata(idev);
+
+	mutex_lock(&dev->pm_mutex);
+
+	/*
+	 * Once we are here event delivery is stopped so we
+	 * don't need to worry about someone starting buzzer
+	 * again
+	 */
+	cm109_stop_traffic(dev);
+	dev->open = 0;
+
+	mutex_unlock(&dev->pm_mutex);
+
+	usb_autopm_put_interface(dev->intf);
+}
+
+static int cm109_input_ev(struct input_dev *idev, unsigned int type,
+			  unsigned int code, int value)
+{
+	struct cm109_dev *dev = input_get_drvdata(idev);
+
+	dev_dbg(&dev->udev->dev,
+		"input_ev: type=%u code=%u value=%d\n", type, code, value);
+
+	if (type != EV_SND)
+		return -EINVAL;
+
+	switch (code) {
+	case SND_TONE:
+	case SND_BELL:
+		dev->buzzer_state = !!value;
+		if (!dev->resetting)
+			cm109_toggle_buzzer_async(dev);
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+
+/******************************************************************************
+ * Linux interface and usb initialisation
+ *****************************************************************************/
+
+struct driver_info {
+	char *name;
+};
+
+static const struct driver_info info_cm109 = {
+	.name = "CM109 USB driver",
+};
+
+enum {
+	VENDOR_ID        = 0x0d8c, /* C-Media Electronics */
+	PRODUCT_ID_CM109 = 0x000e, /* CM109 defines range 0x0008 - 0x000f */
+};
+
+/* table of devices that work with this driver */
+static const struct usb_device_id cm109_usb_table[] = {
+	{
+		.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+				USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor = VENDOR_ID,
+		.idProduct = PRODUCT_ID_CM109,
+		.bInterfaceClass = USB_CLASS_HID,
+		.bInterfaceSubClass = 0,
+		.bInterfaceProtocol = 0,
+		.driver_info = (kernel_ulong_t) &info_cm109
+	},
+	/* you can add more devices here with product ID 0x0008 - 0x000f */
+	{ }
+};
+
+static void cm109_usb_cleanup(struct cm109_dev *dev)
+{
+	kfree(dev->ctl_req);
+	if (dev->ctl_data)
+		usb_free_coherent(dev->udev, USB_PKT_LEN,
+				  dev->ctl_data, dev->ctl_dma);
+	if (dev->irq_data)
+		usb_free_coherent(dev->udev, USB_PKT_LEN,
+				  dev->irq_data, dev->irq_dma);
+
+	usb_free_urb(dev->urb_irq);	/* parameter validation in core/urb */
+	usb_free_urb(dev->urb_ctl);	/* parameter validation in core/urb */
+	kfree(dev);
+}
+
+static void cm109_usb_disconnect(struct usb_interface *interface)
+{
+	struct cm109_dev *dev = usb_get_intfdata(interface);
+
+	usb_set_intfdata(interface, NULL);
+	input_unregister_device(dev->idev);
+	cm109_usb_cleanup(dev);
+}
+
+static int cm109_usb_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct driver_info *nfo = (struct driver_info *)id->driver_info;
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct cm109_dev *dev;
+	struct input_dev *input_dev = NULL;
+	int ret, pipe, i;
+	int error = -ENOMEM;
+
+	interface = intf->cur_altsetting;
+	endpoint = &interface->endpoint[0].desc;
+
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	spin_lock_init(&dev->ctl_submit_lock);
+	mutex_init(&dev->pm_mutex);
+
+	dev->udev = udev;
+	dev->intf = intf;
+
+	dev->idev = input_dev = input_allocate_device();
+	if (!input_dev)
+		goto err_out;
+
+	/* allocate usb buffers */
+	dev->irq_data = usb_alloc_coherent(udev, USB_PKT_LEN,
+					   GFP_KERNEL, &dev->irq_dma);
+	if (!dev->irq_data)
+		goto err_out;
+
+	dev->ctl_data = usb_alloc_coherent(udev, USB_PKT_LEN,
+					   GFP_KERNEL, &dev->ctl_dma);
+	if (!dev->ctl_data)
+		goto err_out;
+
+	dev->ctl_req = kmalloc(sizeof(*(dev->ctl_req)), GFP_KERNEL);
+	if (!dev->ctl_req)
+		goto err_out;
+
+	/* allocate urb structures */
+	dev->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->urb_irq)
+		goto err_out;
+
+	dev->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->urb_ctl)
+		goto err_out;
+
+	/* get a handle to the interrupt data pipe */
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	if (ret != USB_PKT_LEN)
+		err("invalid payload size %d, expected %d", ret, USB_PKT_LEN);
+
+	/* initialise irq urb */
+	usb_fill_int_urb(dev->urb_irq, udev, pipe, dev->irq_data,
+			 USB_PKT_LEN,
+			 cm109_urb_irq_callback, dev, endpoint->bInterval);
+	dev->urb_irq->transfer_dma = dev->irq_dma;
+	dev->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	dev->urb_irq->dev = udev;
+
+	/* initialise ctl urb */
+	dev->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+					USB_DIR_OUT;
+	dev->ctl_req->bRequest = USB_REQ_SET_CONFIGURATION;
+	dev->ctl_req->wValue = cpu_to_le16(0x200);
+	dev->ctl_req->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
+	dev->ctl_req->wLength = cpu_to_le16(USB_PKT_LEN);
+
+	usb_fill_control_urb(dev->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
+			     (void *)dev->ctl_req, dev->ctl_data, USB_PKT_LEN,
+			     cm109_urb_ctl_callback, dev);
+	dev->urb_ctl->transfer_dma = dev->ctl_dma;
+	dev->urb_ctl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	dev->urb_ctl->dev = udev;
+
+	/* find out the physical bus location */
+	usb_make_path(udev, dev->phys, sizeof(dev->phys));
+	strlcat(dev->phys, "/input0", sizeof(dev->phys));
+
+	/* register settings for the input device */
+	input_dev->name = nfo->name;
+	input_dev->phys = dev->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, dev);
+	input_dev->open = cm109_input_open;
+	input_dev->close = cm109_input_close;
+	input_dev->event = cm109_input_ev;
+
+	input_dev->keycode = dev->keymap;
+	input_dev->keycodesize = sizeof(unsigned char);
+	input_dev->keycodemax = ARRAY_SIZE(dev->keymap);
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_SND);
+	input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+
+	/* register available key events */
+	for (i = 0; i < KEYMAP_SIZE; i++) {
+		unsigned short k = keymap(i);
+		dev->keymap[i] = k;
+		__set_bit(k, input_dev->keybit);
+	}
+	__clear_bit(KEY_RESERVED, input_dev->keybit);
+
+	error = input_register_device(dev->idev);
+	if (error)
+		goto err_out;
+
+	usb_set_intfdata(intf, dev);
+
+	return 0;
+
+ err_out:
+	input_free_device(input_dev);
+	cm109_usb_cleanup(dev);
+	return error;
+}
+
+static int cm109_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct cm109_dev *dev = usb_get_intfdata(intf);
+
+	dev_info(&intf->dev, "cm109: usb_suspend (event=%d)\n", message.event);
+
+	mutex_lock(&dev->pm_mutex);
+	cm109_stop_traffic(dev);
+	mutex_unlock(&dev->pm_mutex);
+
+	return 0;
+}
+
+static int cm109_usb_resume(struct usb_interface *intf)
+{
+	struct cm109_dev *dev = usb_get_intfdata(intf);
+
+	dev_info(&intf->dev, "cm109: usb_resume\n");
+
+	mutex_lock(&dev->pm_mutex);
+	cm109_restore_state(dev);
+	mutex_unlock(&dev->pm_mutex);
+
+	return 0;
+}
+
+static int cm109_usb_pre_reset(struct usb_interface *intf)
+{
+	struct cm109_dev *dev = usb_get_intfdata(intf);
+
+	mutex_lock(&dev->pm_mutex);
+
+	/*
+	 * Make sure input events don't try to toggle buzzer
+	 * while we are resetting
+	 */
+	dev->resetting = 1;
+	smp_wmb();
+
+	cm109_stop_traffic(dev);
+
+	return 0;
+}
+
+static int cm109_usb_post_reset(struct usb_interface *intf)
+{
+	struct cm109_dev *dev = usb_get_intfdata(intf);
+
+	dev->resetting = 0;
+	smp_wmb();
+
+	cm109_restore_state(dev);
+
+	mutex_unlock(&dev->pm_mutex);
+
+	return 0;
+}
+
+static struct usb_driver cm109_driver = {
+	.name		= "cm109",
+	.probe		= cm109_usb_probe,
+	.disconnect	= cm109_usb_disconnect,
+	.suspend	= cm109_usb_suspend,
+	.resume		= cm109_usb_resume,
+	.reset_resume	= cm109_usb_resume,
+	.pre_reset	= cm109_usb_pre_reset,
+	.post_reset	= cm109_usb_post_reset,
+	.id_table	= cm109_usb_table,
+	.supports_autosuspend = 1,
+};
+
+static int __init cm109_select_keymap(void)
+{
+	/* Load the phone keymap */
+	if (!strcasecmp(phone, "kip1000")) {
+		keymap = keymap_kip1000;
+		printk(KERN_INFO KBUILD_MODNAME ": "
+			"Keymap for Komunikate KIP1000 phone loaded\n");
+	} else if (!strcasecmp(phone, "gtalk")) {
+		keymap = keymap_gtalk;
+		printk(KERN_INFO KBUILD_MODNAME ": "
+			"Keymap for Genius G-talk phone loaded\n");
+	} else if (!strcasecmp(phone, "usbph01")) {
+		keymap = keymap_usbph01;
+		printk(KERN_INFO KBUILD_MODNAME ": "
+			"Keymap for Allied-Telesis Corega USBPH01 phone loaded\n");
+	} else if (!strcasecmp(phone, "atcom")) {
+		keymap = keymap_atcom;
+		printk(KERN_INFO KBUILD_MODNAME ": "
+			"Keymap for ATCom AU-100 phone loaded\n");
+	} else {
+		printk(KERN_ERR KBUILD_MODNAME ": "
+			"Unsupported phone: %s\n", phone);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __init cm109_init(void)
+{
+	int err;
+
+	err = cm109_select_keymap();
+	if (err)
+		return err;
+
+	err = usb_register(&cm109_driver);
+	if (err)
+		return err;
+
+	printk(KERN_INFO KBUILD_MODNAME ": "
+		DRIVER_DESC ": " DRIVER_VERSION " (C) " DRIVER_AUTHOR "\n");
+
+	return 0;
+}
+
+static void __exit cm109_exit(void)
+{
+	usb_deregister(&cm109_driver);
+}
+
+module_init(cm109_init);
+module_exit(cm109_exit);
+
+MODULE_DEVICE_TABLE(usb, cm109_usb_table);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/cma3000_d0x.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/cma3000_d0x.c
new file mode 100644
index 0000000..06517e6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/cma3000_d0x.c
@@ -0,0 +1,399 @@
+/*
+ * VTI CMA3000_D0x Accelerometer driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/cma3000.h>
+#include <linux/module.h>
+
+#include "cma3000_d0x.h"
+
+#define CMA3000_WHOAMI      0x00
+#define CMA3000_REVID       0x01
+#define CMA3000_CTRL        0x02
+#define CMA3000_STATUS      0x03
+#define CMA3000_RSTR        0x04
+#define CMA3000_INTSTATUS   0x05
+#define CMA3000_DOUTX       0x06
+#define CMA3000_DOUTY       0x07
+#define CMA3000_DOUTZ       0x08
+#define CMA3000_MDTHR       0x09
+#define CMA3000_MDFFTMR     0x0A
+#define CMA3000_FFTHR       0x0B
+
+#define CMA3000_RANGE2G    (1 << 7)
+#define CMA3000_RANGE8G    (0 << 7)
+#define CMA3000_BUSI2C     (0 << 4)
+#define CMA3000_MODEMASK   (7 << 1)
+#define CMA3000_GRANGEMASK (1 << 7)
+
+#define CMA3000_STATUS_PERR    1
+#define CMA3000_INTSTATUS_FFDET (1 << 2)
+
+/* Settling time delay in ms */
+#define CMA3000_SETDELAY    30
+
+/* Delay for clearing interrupt in us */
+#define CMA3000_INTDELAY    44
+
+
+/*
+ * Bit weights in mg for bit 0, other bits need
+ * multipy factor 2^n. Eight bit is the sign bit.
+ */
+#define BIT_TO_2G  18
+#define BIT_TO_8G  71
+
+struct cma3000_accl_data {
+	const struct cma3000_bus_ops *bus_ops;
+	const struct cma3000_platform_data *pdata;
+
+	struct device *dev;
+	struct input_dev *input_dev;
+
+	int bit_to_mg;
+	int irq;
+
+	int g_range;
+	u8 mode;
+
+	struct mutex mutex;
+	bool opened;
+	bool suspended;
+};
+
+#define CMA3000_READ(data, reg, msg) \
+	(data->bus_ops->read(data->dev, reg, msg))
+#define CMA3000_SET(data, reg, val, msg) \
+	((data)->bus_ops->write(data->dev, reg, val, msg))
+
+/*
+ * Conversion for each of the eight modes to g, depending
+ * on G range i.e 2G or 8G. Some modes always operate in
+ * 8G.
+ */
+
+static int mode_to_mg[8][2] = {
+	{ 0, 0 },
+	{ BIT_TO_8G, BIT_TO_2G },
+	{ BIT_TO_8G, BIT_TO_2G },
+	{ BIT_TO_8G, BIT_TO_8G },
+	{ BIT_TO_8G, BIT_TO_8G },
+	{ BIT_TO_8G, BIT_TO_2G },
+	{ BIT_TO_8G, BIT_TO_2G },
+	{ 0, 0},
+};
+
+static void decode_mg(struct cma3000_accl_data *data, int *datax,
+				int *datay, int *dataz)
+{
+	/* Data in 2's complement, convert to mg */
+	*datax = ((s8)*datax) * data->bit_to_mg;
+	*datay = ((s8)*datay) * data->bit_to_mg;
+	*dataz = ((s8)*dataz) * data->bit_to_mg;
+}
+
+static irqreturn_t cma3000_thread_irq(int irq, void *dev_id)
+{
+	struct cma3000_accl_data *data = dev_id;
+	int datax, datay, dataz, intr_status;
+	u8 ctrl, mode, range;
+
+	intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status");
+	if (intr_status < 0)
+		return IRQ_NONE;
+
+	/* Check if free fall is detected, report immediately */
+	if (intr_status & CMA3000_INTSTATUS_FFDET) {
+		input_report_abs(data->input_dev, ABS_MISC, 1);
+		input_sync(data->input_dev);
+	} else {
+		input_report_abs(data->input_dev, ABS_MISC, 0);
+	}
+
+	datax = CMA3000_READ(data, CMA3000_DOUTX, "X");
+	datay = CMA3000_READ(data, CMA3000_DOUTY, "Y");
+	dataz = CMA3000_READ(data, CMA3000_DOUTZ, "Z");
+
+	ctrl = CMA3000_READ(data, CMA3000_CTRL, "ctrl");
+	mode = (ctrl & CMA3000_MODEMASK) >> 1;
+	range = (ctrl & CMA3000_GRANGEMASK) >> 7;
+
+	data->bit_to_mg = mode_to_mg[mode][range];
+
+	/* Interrupt not for this device */
+	if (data->bit_to_mg == 0)
+		return IRQ_NONE;
+
+	/* Decode register values to milli g */
+	decode_mg(data, &datax, &datay, &dataz);
+
+	input_report_abs(data->input_dev, ABS_X, datax);
+	input_report_abs(data->input_dev, ABS_Y, datay);
+	input_report_abs(data->input_dev, ABS_Z, dataz);
+	input_sync(data->input_dev);
+
+	return IRQ_HANDLED;
+}
+
+static int cma3000_reset(struct cma3000_accl_data *data)
+{
+	int val;
+
+	/* Reset sequence */
+	CMA3000_SET(data, CMA3000_RSTR, 0x02, "Reset");
+	CMA3000_SET(data, CMA3000_RSTR, 0x0A, "Reset");
+	CMA3000_SET(data, CMA3000_RSTR, 0x04, "Reset");
+
+	/* Settling time delay */
+	mdelay(10);
+
+	val = CMA3000_READ(data, CMA3000_STATUS, "Status");
+	if (val < 0) {
+		dev_err(data->dev, "Reset failed\n");
+		return val;
+	}
+
+	if (val & CMA3000_STATUS_PERR) {
+		dev_err(data->dev, "Parity Error\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int cma3000_poweron(struct cma3000_accl_data *data)
+{
+	const struct cma3000_platform_data *pdata = data->pdata;
+	u8 ctrl = 0;
+	int ret;
+
+	if (data->g_range == CMARANGE_2G) {
+		ctrl = (data->mode << 1) | CMA3000_RANGE2G;
+	} else if (data->g_range == CMARANGE_8G) {
+		ctrl = (data->mode << 1) | CMA3000_RANGE8G;
+	} else {
+		dev_info(data->dev,
+			 "Invalid G range specified, assuming 8G\n");
+		ctrl = (data->mode << 1) | CMA3000_RANGE8G;
+	}
+
+	ctrl |= data->bus_ops->ctrl_mod;
+
+	CMA3000_SET(data, CMA3000_MDTHR, pdata->mdthr,
+		    "Motion Detect Threshold");
+	CMA3000_SET(data, CMA3000_MDFFTMR, pdata->mdfftmr,
+		    "Time register");
+	CMA3000_SET(data, CMA3000_FFTHR, pdata->ffthr,
+		    "Free fall threshold");
+	ret = CMA3000_SET(data, CMA3000_CTRL, ctrl, "Mode setting");
+	if (ret < 0)
+		return -EIO;
+
+	msleep(CMA3000_SETDELAY);
+
+	return 0;
+}
+
+static int cma3000_poweroff(struct cma3000_accl_data *data)
+{
+	int ret;
+
+	ret = CMA3000_SET(data, CMA3000_CTRL, CMAMODE_POFF, "Mode setting");
+	msleep(CMA3000_SETDELAY);
+
+	return ret;
+}
+
+static int cma3000_open(struct input_dev *input_dev)
+{
+	struct cma3000_accl_data *data = input_get_drvdata(input_dev);
+
+	mutex_lock(&data->mutex);
+
+	if (!data->suspended)
+		cma3000_poweron(data);
+
+	data->opened = true;
+
+	mutex_unlock(&data->mutex);
+
+	return 0;
+}
+
+static void cma3000_close(struct input_dev *input_dev)
+{
+	struct cma3000_accl_data *data = input_get_drvdata(input_dev);
+
+	mutex_lock(&data->mutex);
+
+	if (!data->suspended)
+		cma3000_poweroff(data);
+
+	data->opened = false;
+
+	mutex_unlock(&data->mutex);
+}
+
+void cma3000_suspend(struct cma3000_accl_data *data)
+{
+	mutex_lock(&data->mutex);
+
+	if (!data->suspended && data->opened)
+		cma3000_poweroff(data);
+
+	data->suspended = true;
+
+	mutex_unlock(&data->mutex);
+}
+EXPORT_SYMBOL(cma3000_suspend);
+
+
+void cma3000_resume(struct cma3000_accl_data *data)
+{
+	mutex_lock(&data->mutex);
+
+	if (data->suspended && data->opened)
+		cma3000_poweron(data);
+
+	data->suspended = false;
+
+	mutex_unlock(&data->mutex);
+}
+EXPORT_SYMBOL(cma3000_resume);
+
+struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
+				       const struct cma3000_bus_ops *bops)
+{
+	const struct cma3000_platform_data *pdata = dev->platform_data;
+	struct cma3000_accl_data *data;
+	struct input_dev *input_dev;
+	int rev;
+	int error;
+
+	if (!pdata) {
+		dev_err(dev, "platform data not found\n");
+		error = -EINVAL;
+		goto err_out;
+	}
+
+
+	/* if no IRQ return error */
+	if (irq == 0) {
+		error = -EINVAL;
+		goto err_out;
+	}
+
+	data = kzalloc(sizeof(struct cma3000_accl_data), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	data->dev = dev;
+	data->input_dev = input_dev;
+	data->bus_ops = bops;
+	data->pdata = pdata;
+	data->irq = irq;
+	mutex_init(&data->mutex);
+
+	data->mode = pdata->mode;
+	if (data->mode < CMAMODE_DEFAULT || data->mode > CMAMODE_POFF) {
+		data->mode = CMAMODE_MOTDET;
+		dev_warn(dev,
+			 "Invalid mode specified, assuming Motion Detect\n");
+	}
+
+	data->g_range = pdata->g_range;
+	if (data->g_range != CMARANGE_2G && data->g_range != CMARANGE_8G) {
+		dev_info(dev,
+			 "Invalid G range specified, assuming 8G\n");
+		data->g_range = CMARANGE_8G;
+	}
+
+	input_dev->name = "cma3000-accelerometer";
+	input_dev->id.bustype = bops->bustype;
+	input_dev->open = cma3000_open;
+	input_dev->close = cma3000_close;
+
+	 __set_bit(EV_ABS, input_dev->evbit);
+
+	input_set_abs_params(input_dev, ABS_X,
+			-data->g_range, data->g_range, pdata->fuzz_x, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			-data->g_range, data->g_range, pdata->fuzz_y, 0);
+	input_set_abs_params(input_dev, ABS_Z,
+			-data->g_range, data->g_range, pdata->fuzz_z, 0);
+	input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0);
+
+	input_set_drvdata(input_dev, data);
+
+	error = cma3000_reset(data);
+	if (error)
+		goto err_free_mem;
+
+	rev = CMA3000_READ(data, CMA3000_REVID, "Revid");
+	if (rev < 0) {
+		error = rev;
+		goto err_free_mem;
+	}
+
+	pr_info("CMA3000 Accelerometer: Revision %x\n", rev);
+
+	error = request_threaded_irq(irq, NULL, cma3000_thread_irq,
+				     pdata->irqflags | IRQF_ONESHOT,
+				     "cma3000_d0x", data);
+	if (error) {
+		dev_err(dev, "request_threaded_irq failed\n");
+		goto err_free_mem;
+	}
+
+	error = input_register_device(data->input_dev);
+	if (error) {
+		dev_err(dev, "Unable to register input device\n");
+		goto err_free_irq;
+	}
+
+	return data;
+
+err_free_irq:
+	free_irq(irq, data);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(data);
+err_out:
+	return ERR_PTR(error);
+}
+EXPORT_SYMBOL(cma3000_init);
+
+void cma3000_exit(struct cma3000_accl_data *data)
+{
+	free_irq(data->irq, data);
+	input_unregister_device(data->input_dev);
+	kfree(data);
+}
+EXPORT_SYMBOL(cma3000_exit);
+
+MODULE_DESCRIPTION("CMA3000-D0x Accelerometer Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/cma3000_d0x.h b/ap/os/linux/linux-3.4.x/drivers/input/misc/cma3000_d0x.h
new file mode 100644
index 0000000..2304ce3
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/cma3000_d0x.h
@@ -0,0 +1,42 @@
+/*
+ * VTI CMA3000_D0x Accelerometer driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _INPUT_CMA3000_H
+#define _INPUT_CMA3000_H
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+struct device;
+struct cma3000_accl_data;
+
+struct cma3000_bus_ops {
+	u16 bustype;
+	u8 ctrl_mod;
+	int (*read)(struct device *, u8, char *);
+	int (*write)(struct device *, u8, u8, char *);
+};
+
+struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
+					const struct cma3000_bus_ops *bops);
+void cma3000_exit(struct cma3000_accl_data *);
+void cma3000_suspend(struct cma3000_accl_data *);
+void cma3000_resume(struct cma3000_accl_data *);
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/cma3000_d0x_i2c.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/cma3000_d0x_i2c.c
new file mode 100644
index 0000000..fe9b85f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/cma3000_d0x_i2c.c
@@ -0,0 +1,132 @@
+/*
+ * Implements I2C interface for VTI CMA300_D0x Accelerometer driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input/cma3000.h>
+#include "cma3000_d0x.h"
+
+static int cma3000_i2c_set(struct device *dev,
+			   u8 reg, u8 val, char *msg)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, reg, val);
+	if (ret < 0)
+		dev_err(&client->dev,
+			"%s failed (%s, %d)\n", __func__, msg, ret);
+	return ret;
+}
+
+static int cma3000_i2c_read(struct device *dev, u8 reg, char *msg)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, reg);
+	if (ret < 0)
+		dev_err(&client->dev,
+			"%s failed (%s, %d)\n", __func__, msg, ret);
+	return ret;
+}
+
+static const struct cma3000_bus_ops cma3000_i2c_bops = {
+	.bustype	= BUS_I2C,
+#define CMA3000_BUSI2C     (0 << 4)
+	.ctrl_mod	= CMA3000_BUSI2C,
+	.read		= cma3000_i2c_read,
+	.write		= cma3000_i2c_set,
+};
+
+static int __devinit cma3000_i2c_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct cma3000_accl_data *data;
+
+	data = cma3000_init(&client->dev, client->irq, &cma3000_i2c_bops);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	i2c_set_clientdata(client, data);
+
+	return 0;
+}
+
+static int __devexit cma3000_i2c_remove(struct i2c_client *client)
+{
+	struct cma3000_accl_data *data = i2c_get_clientdata(client);
+
+	cma3000_exit(data);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cma3000_i2c_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct cma3000_accl_data *data = i2c_get_clientdata(client);
+
+	cma3000_suspend(data);
+
+	return 0;
+}
+
+static int cma3000_i2c_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct cma3000_accl_data *data = i2c_get_clientdata(client);
+
+	cma3000_resume(data);
+
+	return 0;
+}
+
+static const struct dev_pm_ops cma3000_i2c_pm_ops = {
+	.suspend	= cma3000_i2c_suspend,
+	.resume		= cma3000_i2c_resume,
+};
+#endif
+
+static const struct i2c_device_id cma3000_i2c_id[] = {
+	{ "cma3000_d01", 0 },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(i2c, cma3000_i2c_id);
+
+static struct i2c_driver cma3000_i2c_driver = {
+	.probe		= cma3000_i2c_probe,
+	.remove		= __devexit_p(cma3000_i2c_remove),
+	.id_table	= cma3000_i2c_id,
+	.driver = {
+		.name	= "cma3000_i2c_accl",
+		.owner	= THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &cma3000_i2c_pm_ops,
+#endif
+	},
+};
+
+module_i2c_driver(cma3000_i2c_driver);
+
+MODULE_DESCRIPTION("CMA3000-D0x Accelerometer I2C Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/cobalt_btns.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/cobalt_btns.c
new file mode 100644
index 0000000..53e43d2
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/cobalt_btns.c
@@ -0,0 +1,166 @@
+/*
+ *  Cobalt button interface driver.
+ *
+ *  Copyright (C) 2007-2008  Yoichi Yuasa <yuasa@linux-mips.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define BUTTONS_POLL_INTERVAL	30	/* msec */
+#define BUTTONS_COUNT_THRESHOLD	3
+#define BUTTONS_STATUS_MASK	0xfe000000
+
+static const unsigned short cobalt_map[] = {
+	KEY_RESERVED,
+	KEY_RESTART,
+	KEY_LEFT,
+	KEY_UP,
+	KEY_DOWN,
+	KEY_RIGHT,
+	KEY_ENTER,
+	KEY_SELECT
+};
+
+struct buttons_dev {
+	struct input_polled_dev *poll_dev;
+	unsigned short keymap[ARRAY_SIZE(cobalt_map)];
+	int count[ARRAY_SIZE(cobalt_map)];
+	void __iomem *reg;
+};
+
+static void handle_buttons(struct input_polled_dev *dev)
+{
+	struct buttons_dev *bdev = dev->private;
+	struct input_dev *input = dev->input;
+	uint32_t status;
+	int i;
+
+	status = ~readl(bdev->reg) >> 24;
+
+	for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) {
+		if (status & (1U << i)) {
+			if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) {
+				input_event(input, EV_MSC, MSC_SCAN, i);
+				input_report_key(input, bdev->keymap[i], 1);
+				input_sync(input);
+			}
+		} else {
+			if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) {
+				input_event(input, EV_MSC, MSC_SCAN, i);
+				input_report_key(input, bdev->keymap[i], 0);
+				input_sync(input);
+			}
+			bdev->count[i] = 0;
+		}
+	}
+}
+
+static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
+{
+	struct buttons_dev *bdev;
+	struct input_polled_dev *poll_dev;
+	struct input_dev *input;
+	struct resource *res;
+	int error, i;
+
+	bdev = kzalloc(sizeof(struct buttons_dev), GFP_KERNEL);
+	poll_dev = input_allocate_polled_device();
+	if (!bdev || !poll_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	memcpy(bdev->keymap, cobalt_map, sizeof(bdev->keymap));
+
+	poll_dev->private = bdev;
+	poll_dev->poll = handle_buttons;
+	poll_dev->poll_interval = BUTTONS_POLL_INTERVAL;
+
+	input = poll_dev->input;
+	input->name = "Cobalt buttons";
+	input->phys = "cobalt/input0";
+	input->id.bustype = BUS_HOST;
+	input->dev.parent = &pdev->dev;
+
+	input->keycode = bdev->keymap;
+	input->keycodemax = ARRAY_SIZE(bdev->keymap);
+	input->keycodesize = sizeof(unsigned short);
+
+	input_set_capability(input, EV_MSC, MSC_SCAN);
+	__set_bit(EV_KEY, input->evbit);
+	for (i = 0; i < ARRAY_SIZE(cobalt_map); i++)
+		__set_bit(bdev->keymap[i], input->keybit);
+	__clear_bit(KEY_RESERVED, input->keybit);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		error = -EBUSY;
+		goto err_free_mem;
+	}
+
+	bdev->poll_dev = poll_dev;
+	bdev->reg = ioremap(res->start, resource_size(res));
+	dev_set_drvdata(&pdev->dev, bdev);
+
+	error = input_register_polled_device(poll_dev);
+	if (error)
+		goto err_iounmap;
+
+	return 0;
+
+ err_iounmap:
+	iounmap(bdev->reg);
+ err_free_mem:
+	input_free_polled_device(poll_dev);
+	kfree(bdev);
+	dev_set_drvdata(&pdev->dev, NULL);
+	return error;
+}
+
+static int __devexit cobalt_buttons_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct buttons_dev *bdev = dev_get_drvdata(dev);
+
+	input_unregister_polled_device(bdev->poll_dev);
+	input_free_polled_device(bdev->poll_dev);
+	iounmap(bdev->reg);
+	kfree(bdev);
+	dev_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
+MODULE_DESCRIPTION("Cobalt button interface driver");
+MODULE_LICENSE("GPL");
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:Cobalt buttons");
+
+static struct platform_driver cobalt_buttons_driver = {
+	.probe	= cobalt_buttons_probe,
+	.remove	= __devexit_p(cobalt_buttons_remove),
+	.driver	= {
+		.name	= "Cobalt buttons",
+		.owner	= THIS_MODULE,
+	},
+};
+module_platform_driver(cobalt_buttons_driver);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/da9052_onkey.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/da9052_onkey.c
new file mode 100644
index 0000000..3c843cd
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/da9052_onkey.c
@@ -0,0 +1,170 @@
+/*
+ * ON pin driver for Dialog DA9052 PMICs
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+struct da9052_onkey {
+	struct da9052 *da9052;
+	struct input_dev *input;
+	struct delayed_work work;
+	unsigned int irq;
+};
+
+static void da9052_onkey_query(struct da9052_onkey *onkey)
+{
+	int key_stat;
+
+	key_stat = da9052_reg_read(onkey->da9052, DA9052_EVENT_B_REG);
+	if (key_stat < 0) {
+		dev_err(onkey->da9052->dev,
+			"Failed to read onkey event %d\n", key_stat);
+	} else {
+		/*
+		 * Since interrupt for deassertion of ONKEY pin is not
+		 * generated, onkey event state determines the onkey
+		 * button state.
+		 */
+		key_stat &= DA9052_EVENTB_ENONKEY;
+		input_report_key(onkey->input, KEY_POWER, key_stat);
+		input_sync(onkey->input);
+	}
+
+	/*
+	 * Interrupt is generated only when the ONKEY pin is asserted.
+	 * Hence the deassertion of the pin is simulated through work queue.
+	 */
+	if (key_stat)
+		schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
+}
+
+static void da9052_onkey_work(struct work_struct *work)
+{
+	struct da9052_onkey *onkey = container_of(work, struct da9052_onkey,
+						  work.work);
+
+	da9052_onkey_query(onkey);
+}
+
+static irqreturn_t da9052_onkey_irq(int irq, void *data)
+{
+	struct da9052_onkey *onkey = data;
+
+	da9052_onkey_query(onkey);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit da9052_onkey_probe(struct platform_device *pdev)
+{
+	struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
+	struct da9052_onkey *onkey;
+	struct input_dev *input_dev;
+	int irq;
+	int error;
+
+	if (!da9052) {
+		dev_err(&pdev->dev, "Failed to get the driver's data\n");
+		return -EINVAL;
+	}
+
+	irq = platform_get_irq_byname(pdev, "ONKEY");
+	if (irq < 0) {
+		dev_err(&pdev->dev,
+			"Failed to get an IRQ for input device, %d\n", irq);
+		return -EINVAL;
+	}
+
+	onkey = kzalloc(sizeof(*onkey), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!onkey || !input_dev) {
+		dev_err(&pdev->dev, "Failed to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	onkey->input = input_dev;
+	onkey->da9052 = da9052;
+	onkey->irq = irq;
+	INIT_DELAYED_WORK(&onkey->work, da9052_onkey_work);
+
+	input_dev->name = "da9052-onkey";
+	input_dev->phys = "da9052-onkey/input0";
+	input_dev->dev.parent = &pdev->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
+	__set_bit(KEY_POWER, input_dev->keybit);
+
+	error = request_threaded_irq(onkey->irq, NULL, da9052_onkey_irq,
+				     IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				     "ONKEY", onkey);
+	if (error < 0) {
+		dev_err(onkey->da9052->dev,
+			"Failed to register ONKEY IRQ %d, error = %d\n",
+			onkey->irq, error);
+		goto err_free_mem;
+	}
+
+	error = input_register_device(onkey->input);
+	if (error) {
+		dev_err(&pdev->dev, "Unable to register input device, %d\n",
+			error);
+		goto err_free_irq;
+	}
+
+	platform_set_drvdata(pdev, onkey);
+	return 0;
+
+err_free_irq:
+	free_irq(onkey->irq, onkey);
+	cancel_delayed_work_sync(&onkey->work);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(onkey);
+
+	return error;
+}
+
+static int __devexit da9052_onkey_remove(struct platform_device *pdev)
+{
+	struct da9052_onkey *onkey = platform_get_drvdata(pdev);
+
+	free_irq(onkey->irq, onkey);
+	cancel_delayed_work_sync(&onkey->work);
+
+	input_unregister_device(onkey->input);
+	kfree(onkey);
+
+	return 0;
+}
+
+static struct platform_driver da9052_onkey_driver = {
+	.probe	= da9052_onkey_probe,
+	.remove	= __devexit_p(da9052_onkey_remove),
+	.driver = {
+		.name	= "da9052-onkey",
+		.owner	= THIS_MODULE,
+	},
+};
+module_platform_driver(da9052_onkey_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("Onkey driver for DA9052");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-onkey");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/dm355evm_keys.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/dm355evm_keys.c
new file mode 100644
index 0000000..35083c6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/dm355evm_keys.c
@@ -0,0 +1,272 @@
+/*
+ * dm355evm_keys.c - support buttons and IR remote on DM355 EVM board
+ *
+ * Copyright (c) 2008 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <linux/i2c/dm355evm_msp.h>
+#include <linux/module.h>
+
+
+/*
+ * The MSP430 firmware on the DM355 EVM monitors on-board pushbuttons
+ * and an IR receptor used for the remote control.  When any key is
+ * pressed, or its autorepeat kicks in, an event is sent.  This driver
+ * read those events from the small (32 event) queue and reports them.
+ *
+ * Note that physically there can only be one of these devices.
+ *
+ * This driver was tested with firmware revision A4.
+ */
+struct dm355evm_keys {
+	struct input_dev	*input;
+	struct device		*dev;
+	int			irq;
+};
+
+/* These initial keycodes can be remapped */
+static const struct key_entry dm355evm_keys[] = {
+	/*
+	 * Pushbuttons on the EVM board ... note that the labels for these
+	 * are SW10/SW11/etc on the PC board.  The left/right orientation
+	 * comes only from the firmware's documentation, and presumes the
+	 * power connector is immediately in front of you and the IR sensor
+	 * is to the right.  (That is, rotate the board counter-clockwise
+	 * by 90 degrees from the SW10/etc and "DM355 EVM" labels.)
+	 */
+	{ KE_KEY, 0x00d8, { KEY_OK } },		/* SW12 */
+	{ KE_KEY, 0x00b8, { KEY_UP } },		/* SW13 */
+	{ KE_KEY, 0x00e8, { KEY_DOWN } },	/* SW11 */
+	{ KE_KEY, 0x0078, { KEY_LEFT } },	/* SW14 */
+	{ KE_KEY, 0x00f0, { KEY_RIGHT } },	/* SW10 */
+
+	/*
+	 * IR buttons ... codes assigned to match the universal remote
+	 * provided with the EVM (Philips PM4S) using DVD code 0020.
+	 *
+	 * These event codes match firmware documentation, but other
+	 * remote controls could easily send more RC5-encoded events.
+	 * The PM4S manual was used in several cases to help select
+	 * a keycode reflecting the intended usage.
+	 *
+	 * RC5 codes are 14 bits, with two start bits (0x3 prefix)
+	 * and a toggle bit (masked out below).
+	 */
+	{ KE_KEY, 0x300c, { KEY_POWER } },	/* NOTE: docs omit this */
+	{ KE_KEY, 0x3000, { KEY_NUMERIC_0 } },
+	{ KE_KEY, 0x3001, { KEY_NUMERIC_1 } },
+	{ KE_KEY, 0x3002, { KEY_NUMERIC_2 } },
+	{ KE_KEY, 0x3003, { KEY_NUMERIC_3 } },
+	{ KE_KEY, 0x3004, { KEY_NUMERIC_4 } },
+	{ KE_KEY, 0x3005, { KEY_NUMERIC_5 } },
+	{ KE_KEY, 0x3006, { KEY_NUMERIC_6 } },
+	{ KE_KEY, 0x3007, { KEY_NUMERIC_7 } },
+	{ KE_KEY, 0x3008, { KEY_NUMERIC_8 } },
+	{ KE_KEY, 0x3009, { KEY_NUMERIC_9 } },
+	{ KE_KEY, 0x3022, { KEY_ENTER } },
+	{ KE_KEY, 0x30ec, { KEY_MODE } },	/* "tv/vcr/..." */
+	{ KE_KEY, 0x300f, { KEY_SELECT } },	/* "info" */
+	{ KE_KEY, 0x3020, { KEY_CHANNELUP } },	/* "up" */
+	{ KE_KEY, 0x302e, { KEY_MENU } },	/* "in/out" */
+	{ KE_KEY, 0x3011, { KEY_VOLUMEDOWN } },	/* "left" */
+	{ KE_KEY, 0x300d, { KEY_MUTE } },	/* "ok" */
+	{ KE_KEY, 0x3010, { KEY_VOLUMEUP } },	/* "right" */
+	{ KE_KEY, 0x301e, { KEY_SUBTITLE } },	/* "cc" */
+	{ KE_KEY, 0x3021, { KEY_CHANNELDOWN } },/* "down" */
+	{ KE_KEY, 0x3022, { KEY_PREVIOUS } },
+	{ KE_KEY, 0x3026, { KEY_SLEEP } },
+	{ KE_KEY, 0x3172, { KEY_REWIND } },	/* NOTE: docs wrongly say 0x30ca */
+	{ KE_KEY, 0x3175, { KEY_PLAY } },
+	{ KE_KEY, 0x3174, { KEY_FASTFORWARD } },
+	{ KE_KEY, 0x3177, { KEY_RECORD } },
+	{ KE_KEY, 0x3176, { KEY_STOP } },
+	{ KE_KEY, 0x3169, { KEY_PAUSE } },
+};
+
+/*
+ * Because we communicate with the MSP430 using I2C, and all I2C calls
+ * in Linux sleep, we use a threaded IRQ handler.  The IRQ itself is
+ * active low, but we go through the GPIO controller so we can trigger
+ * on falling edges and not worry about enabling/disabling the IRQ in
+ * the keypress handling path.
+ */
+static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
+{
+	static u16 last_event;
+	struct dm355evm_keys *keys = _keys;
+	const struct key_entry *ke;
+	unsigned int keycode;
+	int status;
+	u16 event;
+
+	/* For simplicity we ignore INPUT_COUNT and just read
+	 * events until we get the "queue empty" indicator.
+	 * Reading INPUT_LOW decrements the count.
+	 */
+	for (;;) {
+		status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH);
+		if (status < 0) {
+			dev_dbg(keys->dev, "input high err %d\n",
+					status);
+			break;
+		}
+		event = status << 8;
+
+		status = dm355evm_msp_read(DM355EVM_MSP_INPUT_LOW);
+		if (status < 0) {
+			dev_dbg(keys->dev, "input low err %d\n",
+					status);
+			break;
+		}
+		event |= status;
+		if (event == 0xdead)
+			break;
+
+		/* Press and release a button:  two events, same code.
+		 * Press and hold (autorepeat), then release: N events
+		 * (N > 2), same code.  For RC5 buttons the toggle bits
+		 * distinguish (for example) "1-autorepeat" from "1 1";
+		 * but PCB buttons don't support that bit.
+		 *
+		 * So we must synthesize release events.  We do that by
+		 * mapping events to a press/release event pair; then
+		 * to avoid adding extra events, skip the second event
+		 * of each pair.
+		 */
+		if (event == last_event) {
+			last_event = 0;
+			continue;
+		}
+		last_event = event;
+
+		/* ignore the RC5 toggle bit */
+		event &= ~0x0800;
+
+		/* find the key, or report it as unknown */
+		ke = sparse_keymap_entry_from_scancode(keys->input, event);
+		keycode = ke ? ke->keycode : KEY_UNKNOWN;
+		dev_dbg(keys->dev,
+			"input event 0x%04x--> keycode %d\n",
+			event, keycode);
+
+		/* report press + release */
+		input_report_key(keys->input, keycode, 1);
+		input_sync(keys->input);
+		input_report_key(keys->input, keycode, 0);
+		input_sync(keys->input);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*----------------------------------------------------------------------*/
+
+static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
+{
+	struct dm355evm_keys	*keys;
+	struct input_dev	*input;
+	int			status;
+
+	/* allocate instance struct and input dev */
+	keys = kzalloc(sizeof *keys, GFP_KERNEL);
+	input = input_allocate_device();
+	if (!keys || !input) {
+		status = -ENOMEM;
+		goto fail1;
+	}
+
+	keys->dev = &pdev->dev;
+	keys->input = input;
+
+	/* set up "threaded IRQ handler" */
+	status = platform_get_irq(pdev, 0);
+	if (status < 0)
+		goto fail1;
+	keys->irq = status;
+
+	input_set_drvdata(input, keys);
+
+	input->name = "DM355 EVM Controls";
+	input->phys = "dm355evm/input0";
+	input->dev.parent = &pdev->dev;
+
+	input->id.bustype = BUS_I2C;
+	input->id.product = 0x0355;
+	input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV);
+
+	status = sparse_keymap_setup(input, dm355evm_keys, NULL);
+	if (status)
+		goto fail1;
+
+	/* REVISIT:  flush the event queue? */
+
+	status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq,
+			IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keys);
+	if (status < 0)
+		goto fail2;
+
+	/* register */
+	status = input_register_device(input);
+	if (status < 0)
+		goto fail3;
+
+	platform_set_drvdata(pdev, keys);
+
+	return 0;
+
+fail3:
+	free_irq(keys->irq, keys);
+fail2:
+	sparse_keymap_free(input);
+fail1:
+	input_free_device(input);
+	kfree(keys);
+	dev_err(&pdev->dev, "can't register, err %d\n", status);
+
+	return status;
+}
+
+static int __devexit dm355evm_keys_remove(struct platform_device *pdev)
+{
+	struct dm355evm_keys	*keys = platform_get_drvdata(pdev);
+
+	free_irq(keys->irq, keys);
+	sparse_keymap_free(keys->input);
+	input_unregister_device(keys->input);
+	kfree(keys);
+
+	return 0;
+}
+
+/* REVISIT:  add suspend/resume when DaVinci supports it.  The IRQ should
+ * be able to wake up the system.  When device_may_wakeup(&pdev->dev), call
+ * enable_irq_wake() on suspend, and disable_irq_wake() on resume.
+ */
+
+/*
+ * I2C is used to talk to the MSP430, but this platform device is
+ * exposed by an MFD driver that manages I2C communications.
+ */
+static struct platform_driver dm355evm_keys_driver = {
+	.probe		= dm355evm_keys_probe,
+	.remove		= __devexit_p(dm355evm_keys_remove),
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "dm355evm_keys",
+	},
+};
+module_platform_driver(dm355evm_keys_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/gp2ap002a00f.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/gp2ap002a00f.c
new file mode 100644
index 0000000..b6664cf
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/gp2ap002a00f.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2011 Sony Ericsson Mobile Communications Inc.
+ *
+ * Author: Courtney Cavin <courtney.cavin@sonyericsson.com>
+ * Prepared for up-stream by: Oskar Andero <oskar.andero@sonyericsson.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/input/gp2ap002a00f.h>
+
+struct gp2a_data {
+	struct input_dev *input;
+	const struct gp2a_platform_data *pdata;
+	struct i2c_client *i2c_client;
+};
+
+enum gp2a_addr {
+	GP2A_ADDR_PROX	= 0x0,
+	GP2A_ADDR_GAIN	= 0x1,
+	GP2A_ADDR_HYS	= 0x2,
+	GP2A_ADDR_CYCLE	= 0x3,
+	GP2A_ADDR_OPMOD	= 0x4,
+	GP2A_ADDR_CON	= 0x6
+};
+
+enum gp2a_controls {
+	/* Software Shutdown control: 0 = shutdown, 1 = normal operation */
+	GP2A_CTRL_SSD	= 0x01
+};
+
+static int gp2a_report(struct gp2a_data *dt)
+{
+	int vo = gpio_get_value(dt->pdata->vout_gpio);
+
+	input_report_switch(dt->input, SW_FRONT_PROXIMITY, !vo);
+	input_sync(dt->input);
+
+	return 0;
+}
+
+static irqreturn_t gp2a_irq(int irq, void *handle)
+{
+	struct gp2a_data *dt = handle;
+
+	gp2a_report(dt);
+
+	return IRQ_HANDLED;
+}
+
+static int gp2a_enable(struct gp2a_data *dt)
+{
+	return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD,
+					 GP2A_CTRL_SSD);
+}
+
+static int gp2a_disable(struct gp2a_data *dt)
+{
+	return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD,
+					 0x00);
+}
+
+static int gp2a_device_open(struct input_dev *dev)
+{
+	struct gp2a_data *dt = input_get_drvdata(dev);
+	int error;
+
+	error = gp2a_enable(dt);
+	if (error < 0) {
+		dev_err(&dt->i2c_client->dev,
+			"unable to activate, err %d\n", error);
+		return error;
+	}
+
+	gp2a_report(dt);
+
+	return 0;
+}
+
+static void gp2a_device_close(struct input_dev *dev)
+{
+	struct gp2a_data *dt = input_get_drvdata(dev);
+	int error;
+
+	error = gp2a_disable(dt);
+	if (error < 0)
+		dev_err(&dt->i2c_client->dev,
+			"unable to deactivate, err %d\n", error);
+}
+
+static int __devinit gp2a_initialize(struct gp2a_data *dt)
+{
+	int error;
+
+	error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_GAIN,
+					  0x08);
+	if (error < 0)
+		return error;
+
+	error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_HYS,
+					  0xc2);
+	if (error < 0)
+		return error;
+
+	error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_CYCLE,
+					  0x04);
+	if (error < 0)
+		return error;
+
+	error = gp2a_disable(dt);
+
+	return error;
+}
+
+static int __devinit gp2a_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	const struct gp2a_platform_data *pdata = client->dev.platform_data;
+	struct gp2a_data *dt;
+	int error;
+
+	if (!pdata)
+		return -EINVAL;
+
+	if (pdata->hw_setup) {
+		error = pdata->hw_setup(client);
+		if (error < 0)
+			return error;
+	}
+
+	error = gpio_request_one(pdata->vout_gpio, GPIOF_IN, GP2A_I2C_NAME);
+	if (error)
+		goto err_hw_shutdown;
+
+	dt = kzalloc(sizeof(struct gp2a_data), GFP_KERNEL);
+	if (!dt) {
+		error = -ENOMEM;
+		goto err_free_gpio;
+	}
+
+	dt->pdata = pdata;
+	dt->i2c_client = client;
+
+	error = gp2a_initialize(dt);
+	if (error < 0)
+		goto err_free_mem;
+
+	dt->input = input_allocate_device();
+	if (!dt->input) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	input_set_drvdata(dt->input, dt);
+
+	dt->input->open = gp2a_device_open;
+	dt->input->close = gp2a_device_close;
+	dt->input->name = GP2A_I2C_NAME;
+	dt->input->id.bustype = BUS_I2C;
+	dt->input->dev.parent = &client->dev;
+
+	input_set_capability(dt->input, EV_SW, SW_FRONT_PROXIMITY);
+
+	error = request_threaded_irq(client->irq, NULL, gp2a_irq,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+				IRQF_ONESHOT,
+			GP2A_I2C_NAME, dt);
+	if (error) {
+		dev_err(&client->dev, "irq request failed\n");
+		goto err_free_input_dev;
+	}
+
+	error = input_register_device(dt->input);
+	if (error) {
+		dev_err(&client->dev, "device registration failed\n");
+		goto err_free_irq;
+	}
+
+	device_init_wakeup(&client->dev, pdata->wakeup);
+	i2c_set_clientdata(client, dt);
+
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, dt);
+err_free_input_dev:
+	input_free_device(dt->input);
+err_free_mem:
+	kfree(dt);
+err_free_gpio:
+	gpio_free(pdata->vout_gpio);
+err_hw_shutdown:
+	if (pdata->hw_shutdown)
+		pdata->hw_shutdown(client);
+	return error;
+}
+
+static int __devexit gp2a_remove(struct i2c_client *client)
+{
+	struct gp2a_data *dt = i2c_get_clientdata(client);
+	const struct gp2a_platform_data *pdata = dt->pdata;
+
+	device_init_wakeup(&client->dev, false);
+
+	free_irq(client->irq, dt);
+
+	input_unregister_device(dt->input);
+	kfree(dt);
+
+	gpio_free(pdata->vout_gpio);
+
+	if (pdata->hw_shutdown)
+		pdata->hw_shutdown(client);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int gp2a_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct gp2a_data *dt = i2c_get_clientdata(client);
+	int retval = 0;
+
+	if (device_may_wakeup(&client->dev)) {
+		enable_irq_wake(client->irq);
+	} else {
+		mutex_lock(&dt->input->mutex);
+		if (dt->input->users)
+			retval = gp2a_disable(dt);
+		mutex_unlock(&dt->input->mutex);
+	}
+
+	return retval;
+}
+
+static int gp2a_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct gp2a_data *dt = i2c_get_clientdata(client);
+	int retval = 0;
+
+	if (device_may_wakeup(&client->dev)) {
+		disable_irq_wake(client->irq);
+	} else {
+		mutex_lock(&dt->input->mutex);
+		if (dt->input->users)
+			retval = gp2a_enable(dt);
+		mutex_unlock(&dt->input->mutex);
+	}
+
+	return retval;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(gp2a_pm, gp2a_suspend, gp2a_resume);
+
+static const struct i2c_device_id gp2a_i2c_id[] = {
+	{ GP2A_I2C_NAME, 0 },
+	{ }
+};
+
+static struct i2c_driver gp2a_i2c_driver = {
+	.driver = {
+		.name	= GP2A_I2C_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &gp2a_pm,
+	},
+	.probe		= gp2a_probe,
+	.remove		= __devexit_p(gp2a_remove),
+	.id_table	= gp2a_i2c_id,
+};
+
+module_i2c_driver(gp2a_i2c_driver);
+
+MODULE_AUTHOR("Courtney Cavin <courtney.cavin@sonyericsson.com>");
+MODULE_DESCRIPTION("Sharp GP2AP002A00F I2C Proximity/Opto sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/gpio_tilt_polled.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/gpio_tilt_polled.c
new file mode 100644
index 0000000..277a057
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/gpio_tilt_polled.c
@@ -0,0 +1,213 @@
+/*
+ *  Driver for tilt switches connected via GPIO lines
+ *  not capable of generating interrupts
+ *
+ *  Copyright (C) 2011 Heiko Stuebner <heiko@sntech.de>
+ *
+ *  based on: drivers/input/keyboard/gpio_keys_polled.c
+ *
+ *  Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/input/gpio_tilt.h>
+
+#define DRV_NAME	"gpio-tilt-polled"
+
+struct gpio_tilt_polled_dev {
+	struct input_polled_dev *poll_dev;
+	struct device *dev;
+	const struct gpio_tilt_platform_data *pdata;
+
+	int last_state;
+
+	int threshold;
+	int count;
+};
+
+static void gpio_tilt_polled_poll(struct input_polled_dev *dev)
+{
+	struct gpio_tilt_polled_dev *tdev = dev->private;
+	const struct gpio_tilt_platform_data *pdata = tdev->pdata;
+	struct input_dev *input = dev->input;
+	struct gpio_tilt_state *tilt_state = NULL;
+	int state, i;
+
+	if (tdev->count < tdev->threshold) {
+		tdev->count++;
+	} else {
+		state = 0;
+		for (i = 0; i < pdata->nr_gpios; i++)
+			state |= (!!gpio_get_value(pdata->gpios[i].gpio) << i);
+
+		if (state != tdev->last_state) {
+			for (i = 0; i < pdata->nr_states; i++)
+				if (pdata->states[i].gpios == state)
+					tilt_state = &pdata->states[i];
+
+			if (tilt_state) {
+				for (i = 0; i < pdata->nr_axes; i++)
+					input_report_abs(input,
+							 pdata->axes[i].axis,
+							 tilt_state->axes[i]);
+
+				input_sync(input);
+			}
+
+			tdev->count = 0;
+			tdev->last_state = state;
+		}
+	}
+}
+
+static void gpio_tilt_polled_open(struct input_polled_dev *dev)
+{
+	struct gpio_tilt_polled_dev *tdev = dev->private;
+	const struct gpio_tilt_platform_data *pdata = tdev->pdata;
+
+	if (pdata->enable)
+		pdata->enable(tdev->dev);
+
+	/* report initial state of the axes */
+	tdev->last_state = -1;
+	tdev->count = tdev->threshold;
+	gpio_tilt_polled_poll(tdev->poll_dev);
+}
+
+static void gpio_tilt_polled_close(struct input_polled_dev *dev)
+{
+	struct gpio_tilt_polled_dev *tdev = dev->private;
+	const struct gpio_tilt_platform_data *pdata = tdev->pdata;
+
+	if (pdata->disable)
+		pdata->disable(tdev->dev);
+}
+
+static int __devinit gpio_tilt_polled_probe(struct platform_device *pdev)
+{
+	const struct gpio_tilt_platform_data *pdata = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct gpio_tilt_polled_dev *tdev;
+	struct input_polled_dev *poll_dev;
+	struct input_dev *input;
+	int error, i;
+
+	if (!pdata || !pdata->poll_interval)
+		return -EINVAL;
+
+	tdev = kzalloc(sizeof(struct gpio_tilt_polled_dev), GFP_KERNEL);
+	if (!tdev) {
+		dev_err(dev, "no memory for private data\n");
+		return -ENOMEM;
+	}
+
+	error = gpio_request_array(pdata->gpios, pdata->nr_gpios);
+	if (error) {
+		dev_err(dev,
+			"Could not request tilt GPIOs: %d\n", error);
+		goto err_free_tdev;
+	}
+
+	poll_dev = input_allocate_polled_device();
+	if (!poll_dev) {
+		dev_err(dev, "no memory for polled device\n");
+		error = -ENOMEM;
+		goto err_free_gpios;
+	}
+
+	poll_dev->private = tdev;
+	poll_dev->poll = gpio_tilt_polled_poll;
+	poll_dev->poll_interval = pdata->poll_interval;
+	poll_dev->open = gpio_tilt_polled_open;
+	poll_dev->close = gpio_tilt_polled_close;
+
+	input = poll_dev->input;
+
+	input->name = pdev->name;
+	input->phys = DRV_NAME"/input0";
+	input->dev.parent = &pdev->dev;
+
+	input->id.bustype = BUS_HOST;
+	input->id.vendor = 0x0001;
+	input->id.product = 0x0001;
+	input->id.version = 0x0100;
+
+	__set_bit(EV_ABS, input->evbit);
+	for (i = 0; i < pdata->nr_axes; i++)
+		input_set_abs_params(input, pdata->axes[i].axis,
+				     pdata->axes[i].min, pdata->axes[i].max,
+				     pdata->axes[i].fuzz, pdata->axes[i].flat);
+
+	tdev->threshold = DIV_ROUND_UP(pdata->debounce_interval,
+				       pdata->poll_interval);
+
+	tdev->poll_dev = poll_dev;
+	tdev->dev = dev;
+	tdev->pdata = pdata;
+
+	error = input_register_polled_device(poll_dev);
+	if (error) {
+		dev_err(dev, "unable to register polled device, err=%d\n",
+			error);
+		goto err_free_polldev;
+	}
+
+	platform_set_drvdata(pdev, tdev);
+
+	return 0;
+
+err_free_polldev:
+	input_free_polled_device(poll_dev);
+err_free_gpios:
+	gpio_free_array(pdata->gpios, pdata->nr_gpios);
+err_free_tdev:
+	kfree(tdev);
+
+	return error;
+}
+
+static int __devexit gpio_tilt_polled_remove(struct platform_device *pdev)
+{
+	struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev);
+	const struct gpio_tilt_platform_data *pdata = tdev->pdata;
+
+	platform_set_drvdata(pdev, NULL);
+
+	input_unregister_polled_device(tdev->poll_dev);
+	input_free_polled_device(tdev->poll_dev);
+
+	gpio_free_array(pdata->gpios, pdata->nr_gpios);
+
+	kfree(tdev);
+
+	return 0;
+}
+
+static struct platform_driver gpio_tilt_polled_driver = {
+	.probe	= gpio_tilt_polled_probe,
+	.remove	= __devexit_p(gpio_tilt_polled_remove),
+	.driver	= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(gpio_tilt_polled_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_DESCRIPTION("Polled GPIO tilt driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/hp_sdc_rtc.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/hp_sdc_rtc.c
new file mode 100644
index 0000000..0b4f542
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/hp_sdc_rtc.c
@@ -0,0 +1,727 @@
+/*
+ * HP i8042 SDC + MSM-58321 BBRTC driver.
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *
+ * References:
+ * System Device Controller Microprocessor Firmware Theory of Operation
+ *      for Part Number 1820-4784 Revision B.  Dwg No. A-1820-4784-2
+ * efirtc.c by Stephane Eranian/Hewlett Packard
+ *
+ */
+
+#include <linux/hp_sdc.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/miscdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/rtc.h>
+#include <linux/mutex.h>
+#include <linux/semaphore.h>
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION("HP i8042 SDC + MSM-58321 RTC Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define RTC_VERSION "1.10d"
+
+static DEFINE_MUTEX(hp_sdc_rtc_mutex);
+static unsigned long epoch = 2000;
+
+static struct semaphore i8042tregs;
+
+static hp_sdc_irqhook hp_sdc_rtc_isr;
+
+static struct fasync_struct *hp_sdc_rtc_async_queue;
+
+static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait);
+
+static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf,
+			       size_t count, loff_t *ppos);
+
+static long hp_sdc_rtc_unlocked_ioctl(struct file *file,
+				      unsigned int cmd, unsigned long arg);
+
+static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait);
+
+static int hp_sdc_rtc_open(struct inode *inode, struct file *file);
+static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on);
+
+static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off,
+				int count, int *eof, void *data);
+
+static void hp_sdc_rtc_isr (int irq, void *dev_id, 
+			    uint8_t status, uint8_t data) 
+{
+	return;
+}
+
+static int hp_sdc_rtc_do_read_bbrtc (struct rtc_time *rtctm)
+{
+	struct semaphore tsem;
+	hp_sdc_transaction t;
+	uint8_t tseq[91];
+	int i;
+	
+	i = 0;
+	while (i < 91) {
+		tseq[i++] = HP_SDC_ACT_DATAREG |
+			HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN;
+		tseq[i++] = 0x01;			/* write i8042[0x70] */
+	  	tseq[i]   = i / 7;			/* BBRTC reg address */
+		i++;
+		tseq[i++] = HP_SDC_CMD_DO_RTCR;		/* Trigger command   */
+		tseq[i++] = 2;		/* expect 1 stat/dat pair back.   */
+		i++; i++;               /* buffer for stat/dat pair       */
+	}
+	tseq[84] |= HP_SDC_ACT_SEMAPHORE;
+	t.endidx =		91;
+	t.seq =			tseq;
+	t.act.semaphore =	&tsem;
+	sema_init(&tsem, 0);
+	
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	
+	down_interruptible(&tsem);  /* Put ourselves to sleep for results. */
+	
+	/* Check for nonpresence of BBRTC */
+	if (!((tseq[83] | tseq[90] | tseq[69] | tseq[76] |
+	       tseq[55] | tseq[62] | tseq[34] | tseq[41] |
+	       tseq[20] | tseq[27] | tseq[6]  | tseq[13]) & 0x0f))
+		return -1;
+
+	memset(rtctm, 0, sizeof(struct rtc_time));
+	rtctm->tm_year = (tseq[83] & 0x0f) + (tseq[90] & 0x0f) * 10;
+	rtctm->tm_mon  = (tseq[69] & 0x0f) + (tseq[76] & 0x0f) * 10;
+	rtctm->tm_mday = (tseq[55] & 0x0f) + (tseq[62] & 0x0f) * 10;
+	rtctm->tm_wday = (tseq[48] & 0x0f);
+	rtctm->tm_hour = (tseq[34] & 0x0f) + (tseq[41] & 0x0f) * 10;
+	rtctm->tm_min  = (tseq[20] & 0x0f) + (tseq[27] & 0x0f) * 10;
+	rtctm->tm_sec  = (tseq[6]  & 0x0f) + (tseq[13] & 0x0f) * 10;
+	
+	return 0;
+}
+
+static int hp_sdc_rtc_read_bbrtc (struct rtc_time *rtctm)
+{
+	struct rtc_time tm, tm_last;
+	int i = 0;
+
+	/* MSM-58321 has no read latch, so must read twice and compare. */
+
+	if (hp_sdc_rtc_do_read_bbrtc(&tm_last)) return -1;
+	if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1;
+
+	while (memcmp(&tm, &tm_last, sizeof(struct rtc_time))) {
+		if (i++ > 4) return -1;
+		memcpy(&tm_last, &tm, sizeof(struct rtc_time));
+		if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1;
+	}
+
+	memcpy(rtctm, &tm, sizeof(struct rtc_time));
+
+	return 0;
+}
+
+
+static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg)
+{
+	hp_sdc_transaction t;
+	uint8_t tseq[26] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN,
+		0,
+		HP_SDC_CMD_READ_T1, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T2, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T3, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T4, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T5, 2, 0, 0
+	};
+
+	t.endidx = numreg * 5;
+
+	tseq[1] = loadcmd;
+	tseq[t.endidx - 4] |= HP_SDC_ACT_SEMAPHORE; /* numreg assumed > 1 */
+
+	t.seq =			tseq;
+	t.act.semaphore =	&i8042tregs;
+
+	down_interruptible(&i8042tregs);  /* Sleep if output regs in use. */
+
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	
+	down_interruptible(&i8042tregs);  /* Sleep until results come back. */
+	up(&i8042tregs);
+
+	return (tseq[5] | 
+		((uint64_t)(tseq[10]) << 8)  | ((uint64_t)(tseq[15]) << 16) |
+		((uint64_t)(tseq[20]) << 24) | ((uint64_t)(tseq[25]) << 32));
+}
+
+
+/* Read the i8042 real-time clock */
+static inline int hp_sdc_rtc_read_rt(struct timeval *res) {
+	int64_t raw;
+	uint32_t tenms; 
+	unsigned int days;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_RT, 5);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+	days  = (unsigned int)(raw >> 24) & 0xffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec =  (time_t)(tenms / 100) + days * 86400;
+
+	return 0;
+}
+
+
+/* Read the i8042 fast handshake timer */
+static inline int hp_sdc_rtc_read_fhs(struct timeval *res) {
+	int64_t raw;
+	unsigned int tenms;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_FHS, 2);
+	if (raw < 0) return -1;
+
+	tenms = (unsigned int)raw & 0xffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Read the i8042 match timer (a.k.a. alarm) */
+static inline int hp_sdc_rtc_read_mt(struct timeval *res) {
+	int64_t raw;	
+	uint32_t tenms; 
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_MT, 3);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Read the i8042 delay timer */
+static inline int hp_sdc_rtc_read_dt(struct timeval *res) {
+	int64_t raw;
+	uint32_t tenms;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_DT, 3);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Read the i8042 cycle timer (a.k.a. periodic) */
+static inline int hp_sdc_rtc_read_ct(struct timeval *res) {
+	int64_t raw;
+	uint32_t tenms;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_CT, 3);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Set the i8042 real-time clock */
+static int hp_sdc_rtc_set_rt (struct timeval *setto)
+{
+	uint32_t tenms;
+	unsigned int days;
+	hp_sdc_transaction t;
+	uint8_t tseq[11] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		HP_SDC_CMD_SET_RTMS, 3, 0, 0, 0,
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		HP_SDC_CMD_SET_RTD, 2, 0, 0 
+	};
+
+	t.endidx = 10;
+
+	if (0xffff < setto->tv_sec / 86400) return -1;
+	days = setto->tv_sec / 86400;
+	if (0xffff < setto->tv_usec / 1000000 / 86400) return -1;
+	days += ((setto->tv_sec % 86400) + setto->tv_usec / 1000000) / 86400;
+	if (days > 0xffff) return -1;
+
+	if (0xffffff < setto->tv_sec) return -1;
+	tenms  = setto->tv_sec * 100;
+	if (0xffffff < setto->tv_usec / 10000) return -1;
+	tenms += setto->tv_usec / 10000;
+	if (tenms > 0xffffff) return -1;
+
+	tseq[3] = (uint8_t)(tenms & 0xff);
+	tseq[4] = (uint8_t)((tenms >> 8)  & 0xff);
+	tseq[5] = (uint8_t)((tenms >> 16) & 0xff);
+
+	tseq[9] = (uint8_t)(days & 0xff);
+	tseq[10] = (uint8_t)((days >> 8) & 0xff);
+
+	t.seq =	tseq;
+
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	return 0;
+}
+
+/* Set the i8042 fast handshake timer */
+static int hp_sdc_rtc_set_fhs (struct timeval *setto)
+{
+	uint32_t tenms;
+	hp_sdc_transaction t;
+	uint8_t tseq[5] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		HP_SDC_CMD_SET_FHS, 2, 0, 0
+	};
+
+	t.endidx = 4;
+
+	if (0xffff < setto->tv_sec) return -1;
+	tenms  = setto->tv_sec * 100;
+	if (0xffff < setto->tv_usec / 10000) return -1;
+	tenms += setto->tv_usec / 10000;
+	if (tenms > 0xffff) return -1;
+
+	tseq[3] = (uint8_t)(tenms & 0xff);
+	tseq[4] = (uint8_t)((tenms >> 8)  & 0xff);
+
+	t.seq =	tseq;
+
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	return 0;
+}
+
+
+/* Set the i8042 match timer (a.k.a. alarm) */
+#define hp_sdc_rtc_set_mt (setto) \
+	hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_MT)
+
+/* Set the i8042 delay timer */
+#define hp_sdc_rtc_set_dt (setto) \
+	hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_DT)
+
+/* Set the i8042 cycle timer (a.k.a. periodic) */
+#define hp_sdc_rtc_set_ct (setto) \
+	hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_CT)
+
+/* Set one of the i8042 3-byte wide timers */
+static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd)
+{
+	uint32_t tenms;
+	hp_sdc_transaction t;
+	uint8_t tseq[6] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		0, 3, 0, 0, 0
+	};
+
+	t.endidx = 6;
+
+	if (0xffffff < setto->tv_sec) return -1;
+	tenms  = setto->tv_sec * 100;
+	if (0xffffff < setto->tv_usec / 10000) return -1;
+	tenms += setto->tv_usec / 10000;
+	if (tenms > 0xffffff) return -1;
+
+	tseq[1] = setcmd;
+	tseq[3] = (uint8_t)(tenms & 0xff);
+	tseq[4] = (uint8_t)((tenms >> 8)  & 0xff);
+	tseq[5] = (uint8_t)((tenms >> 16)  & 0xff);
+
+	t.seq =			tseq;
+
+	if (hp_sdc_enqueue_transaction(&t)) { 
+		return -1;
+	}
+	return 0;
+}
+
+static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf,
+			       size_t count, loff_t *ppos) {
+	ssize_t retval;
+
+        if (count < sizeof(unsigned long))
+                return -EINVAL;
+
+	retval = put_user(68, (unsigned long __user *)buf);
+	return retval;
+}
+
+static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait)
+{
+        unsigned long l;
+
+	l = 0;
+        if (l != 0)
+                return POLLIN | POLLRDNORM;
+        return 0;
+}
+
+static int hp_sdc_rtc_open(struct inode *inode, struct file *file)
+{
+        return 0;
+}
+
+static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on)
+{
+        return fasync_helper (fd, filp, on, &hp_sdc_rtc_async_queue);
+}
+
+static int hp_sdc_rtc_proc_output (char *buf)
+{
+#define YN(bit) ("no")
+#define NY(bit) ("yes")
+        char *p;
+        struct rtc_time tm;
+	struct timeval tv;
+
+	memset(&tm, 0, sizeof(struct rtc_time));
+
+	p = buf;
+
+	if (hp_sdc_rtc_read_bbrtc(&tm)) {
+		p += sprintf(p, "BBRTC\t\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p,
+			     "rtc_time\t: %02d:%02d:%02d\n"
+			     "rtc_date\t: %04d-%02d-%02d\n"
+			     "rtc_epoch\t: %04lu\n",
+			     tm.tm_hour, tm.tm_min, tm.tm_sec,
+			     tm.tm_year + 1900, tm.tm_mon + 1, 
+			     tm.tm_mday, epoch);
+	}
+
+	if (hp_sdc_rtc_read_rt(&tv)) {
+		p += sprintf(p, "i8042 rtc\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "i8042 rtc\t: %ld.%02d seconds\n", 
+			     tv.tv_sec, (int)tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_fhs(&tv)) {
+		p += sprintf(p, "handshake\t: READ FAILED!\n");
+	} else {
+        	p += sprintf(p, "handshake\t: %ld.%02d seconds\n", 
+			     tv.tv_sec, (int)tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_mt(&tv)) {
+		p += sprintf(p, "alarm\t\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "alarm\t\t: %ld.%02d seconds\n", 
+			     tv.tv_sec, (int)tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_dt(&tv)) {
+		p += sprintf(p, "delay\t\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "delay\t\t: %ld.%02d seconds\n", 
+			     tv.tv_sec, (int)tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_ct(&tv)) {
+		p += sprintf(p, "periodic\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "periodic\t: %ld.%02d seconds\n", 
+			     tv.tv_sec, (int)tv.tv_usec/1000);
+	}
+
+        p += sprintf(p,
+                     "DST_enable\t: %s\n"
+                     "BCD\t\t: %s\n"
+                     "24hr\t\t: %s\n"
+                     "square_wave\t: %s\n"
+                     "alarm_IRQ\t: %s\n"
+                     "update_IRQ\t: %s\n"
+                     "periodic_IRQ\t: %s\n"
+		     "periodic_freq\t: %ld\n"
+                     "batt_status\t: %s\n",
+                     YN(RTC_DST_EN),
+                     NY(RTC_DM_BINARY),
+                     YN(RTC_24H),
+                     YN(RTC_SQWE),
+                     YN(RTC_AIE),
+                     YN(RTC_UIE),
+                     YN(RTC_PIE),
+                     1UL,
+                     1 ? "okay" : "dead");
+
+        return  p - buf;
+#undef YN
+#undef NY
+}
+
+static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data)
+{
+	int len = hp_sdc_rtc_proc_output (page);
+        if (len <= off+count) *eof = 1;
+        *start = page + off;
+        len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+        return len;
+}
+
+static int hp_sdc_rtc_ioctl(struct file *file, 
+			    unsigned int cmd, unsigned long arg)
+{
+#if 1
+	return -EINVAL;
+#else
+	
+        struct rtc_time wtime; 
+	struct timeval ttime;
+	int use_wtime = 0;
+
+	/* This needs major work. */
+
+        switch (cmd) {
+
+        case RTC_AIE_OFF:       /* Mask alarm int. enab. bit    */
+        case RTC_AIE_ON:        /* Allow alarm interrupts.      */
+	case RTC_PIE_OFF:       /* Mask periodic int. enab. bit */
+        case RTC_PIE_ON:        /* Allow periodic ints          */
+        case RTC_UIE_ON:        /* Allow ints for RTC updates.  */
+        case RTC_UIE_OFF:       /* Allow ints for RTC updates.  */
+        {
+		/* We cannot mask individual user timers and we
+		   cannot tell them apart when they occur, so it 
+		   would be disingenuous to succeed these IOCTLs */
+		return -EINVAL;
+        }
+        case RTC_ALM_READ:      /* Read the present alarm time */
+        {
+		if (hp_sdc_rtc_read_mt(&ttime)) return -EFAULT;
+		if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT;
+
+		wtime.tm_hour = ttime.tv_sec / 3600;  ttime.tv_sec %= 3600;
+		wtime.tm_min  = ttime.tv_sec / 60;    ttime.tv_sec %= 60;
+		wtime.tm_sec  = ttime.tv_sec;
+                
+		break;
+        }
+        case RTC_IRQP_READ:     /* Read the periodic IRQ rate.  */
+        {
+                return put_user(hp_sdc_rtc_freq, (unsigned long *)arg);
+        }
+        case RTC_IRQP_SET:      /* Set periodic IRQ rate.       */
+        {
+                /* 
+                 * The max we can do is 100Hz.
+		 */
+
+                if ((arg < 1) || (arg > 100)) return -EINVAL;
+		ttime.tv_sec = 0;
+		ttime.tv_usec = 1000000 / arg;
+		if (hp_sdc_rtc_set_ct(&ttime)) return -EFAULT;
+		hp_sdc_rtc_freq = arg;
+                return 0;
+        }
+        case RTC_ALM_SET:       /* Store a time into the alarm */
+        {
+                /*
+                 * This expects a struct hp_sdc_rtc_time. Writing 0xff means
+                 * "don't care" or "match all" for PC timers.  The HP SDC
+		 * does not support that perk, but it could be emulated fairly
+		 * easily.  Only the tm_hour, tm_min and tm_sec are used.
+		 * We could do it with 10ms accuracy with the HP SDC, if the 
+		 * rtc interface left us a way to do that.
+                 */
+                struct hp_sdc_rtc_time alm_tm;
+
+                if (copy_from_user(&alm_tm, (struct hp_sdc_rtc_time*)arg,
+                                   sizeof(struct hp_sdc_rtc_time)))
+                       return -EFAULT;
+
+                if (alm_tm.tm_hour > 23) return -EINVAL;
+		if (alm_tm.tm_min  > 59) return -EINVAL;
+		if (alm_tm.tm_sec  > 59) return -EINVAL;  
+
+		ttime.sec = alm_tm.tm_hour * 3600 + 
+		  alm_tm.tm_min * 60 + alm_tm.tm_sec;
+		ttime.usec = 0;
+		if (hp_sdc_rtc_set_mt(&ttime)) return -EFAULT;
+                return 0;
+        }
+        case RTC_RD_TIME:       /* Read the time/date from RTC  */
+        {
+		if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT;
+                break;
+        }
+        case RTC_SET_TIME:      /* Set the RTC */
+        {
+                struct rtc_time hp_sdc_rtc_tm;
+                unsigned char mon, day, hrs, min, sec, leap_yr;
+                unsigned int yrs;
+
+                if (!capable(CAP_SYS_TIME))
+                        return -EACCES;
+		if (copy_from_user(&hp_sdc_rtc_tm, (struct rtc_time *)arg,
+                                   sizeof(struct rtc_time)))
+                        return -EFAULT;
+
+                yrs = hp_sdc_rtc_tm.tm_year + 1900;
+                mon = hp_sdc_rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
+                day = hp_sdc_rtc_tm.tm_mday;
+                hrs = hp_sdc_rtc_tm.tm_hour;
+                min = hp_sdc_rtc_tm.tm_min;
+                sec = hp_sdc_rtc_tm.tm_sec;
+
+                if (yrs < 1970)
+                        return -EINVAL;
+
+                leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+                if ((mon > 12) || (day == 0))
+                        return -EINVAL;
+                if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+                        return -EINVAL;
+		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+                        return -EINVAL;
+
+                if ((yrs -= eH) > 255)    /* They are unsigned */
+                        return -EINVAL;
+
+
+                return 0;
+        }
+        case RTC_EPOCH_READ:    /* Read the epoch.      */
+        {
+                return put_user (epoch, (unsigned long *)arg);
+        }
+        case RTC_EPOCH_SET:     /* Set the epoch.       */
+        {
+                /* 
+                 * There were no RTC clocks before 1900.
+                 */
+                if (arg < 1900)
+		  return -EINVAL;
+		if (!capable(CAP_SYS_TIME))
+		  return -EACCES;
+		
+                epoch = arg;
+                return 0;
+        }
+        default:
+                return -EINVAL;
+        }
+        return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+#endif
+}
+
+static long hp_sdc_rtc_unlocked_ioctl(struct file *file,
+				      unsigned int cmd, unsigned long arg)
+{
+	int ret;
+
+	mutex_lock(&hp_sdc_rtc_mutex);
+	ret = hp_sdc_rtc_ioctl(file, cmd, arg);
+	mutex_unlock(&hp_sdc_rtc_mutex);
+
+	return ret;
+}
+
+
+static const struct file_operations hp_sdc_rtc_fops = {
+        .owner =		THIS_MODULE,
+        .llseek =		no_llseek,
+        .read =			hp_sdc_rtc_read,
+        .poll =			hp_sdc_rtc_poll,
+        .unlocked_ioctl =	hp_sdc_rtc_unlocked_ioctl,
+        .open =			hp_sdc_rtc_open,
+        .fasync =		hp_sdc_rtc_fasync,
+};
+
+static struct miscdevice hp_sdc_rtc_dev = {
+        .minor =	RTC_MINOR,
+        .name =		"rtc_HIL",
+        .fops =		&hp_sdc_rtc_fops
+};
+
+static int __init hp_sdc_rtc_init(void)
+{
+	int ret;
+
+#ifdef __mc68000__
+	if (!MACH_IS_HP300)
+		return -ENODEV;
+#endif
+
+	sema_init(&i8042tregs, 1);
+
+	if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr)))
+		return ret;
+	if (misc_register(&hp_sdc_rtc_dev) != 0)
+		printk(KERN_INFO "Could not register misc. dev for i8042 rtc\n");
+
+        create_proc_read_entry ("driver/rtc", 0, NULL,
+				hp_sdc_rtc_read_proc, NULL);
+
+	printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded "
+			 "(RTC v " RTC_VERSION ")\n");
+
+	return 0;
+}
+
+static void __exit hp_sdc_rtc_exit(void)
+{
+	remove_proc_entry ("driver/rtc", NULL);
+        misc_deregister(&hp_sdc_rtc_dev);
+	hp_sdc_release_timer_irq(hp_sdc_rtc_isr);
+        printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support unloaded\n");
+}
+
+module_init(hp_sdc_rtc_init);
+module_exit(hp_sdc_rtc_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/ixp4xx-beeper.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/ixp4xx-beeper.c
new file mode 100644
index 0000000..50e2830
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/ixp4xx-beeper.c
@@ -0,0 +1,172 @@
+/*
+ * Generic IXP4xx beeper driver
+ *
+ * Copyright (C) 2005 Tower Technologies
+ *
+ * based on nslu2-io.c
+ *  Copyright (C) 2004 Karen Spearel
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ * Maintainers: http://www.nslu2-linux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <mach/hardware.h>
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("ixp4xx beeper driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ixp4xx-beeper");
+
+static DEFINE_SPINLOCK(beep_lock);
+
+static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&beep_lock, flags);
+
+	 if (count) {
+		gpio_line_config(pin, IXP4XX_GPIO_OUT);
+		gpio_line_set(pin, IXP4XX_GPIO_LOW);
+
+		*IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
+	} else {
+		gpio_line_config(pin, IXP4XX_GPIO_IN);
+		gpio_line_set(pin, IXP4XX_GPIO_HIGH);
+
+		*IXP4XX_OSRT2 = 0;
+	}
+
+	spin_unlock_irqrestore(&beep_lock, flags);
+}
+
+static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	unsigned int pin = (unsigned int) input_get_drvdata(dev);
+	unsigned int count = 0;
+
+	if (type != EV_SND)
+		return -1;
+
+	switch (code) {
+		case SND_BELL:
+			if (value)
+				value = 1000;
+		case SND_TONE:
+			break;
+		default:
+			return -1;
+	}
+
+	if (value > 20 && value < 32767)
+		count = (IXP4XX_TIMER_FREQ / (value * 4)) - 1;
+
+	ixp4xx_spkr_control(pin, count);
+
+	return 0;
+}
+
+static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id)
+{
+	/* clear interrupt */
+	*IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND;
+
+	/* flip the beeper output */
+	*IXP4XX_GPIO_GPOUTR ^= (1 << (unsigned int) dev_id);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
+{
+	struct input_dev *input_dev;
+	int err;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	input_set_drvdata(input_dev, (void *) dev->id);
+
+	input_dev->name = "ixp4xx beeper",
+	input_dev->phys = "ixp4xx/gpio";
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor  = 0x001f;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &dev->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_SND);
+	input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+	input_dev->event = ixp4xx_spkr_event;
+
+	err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,
+			  IRQF_NO_SUSPEND, "ixp4xx-beeper",
+			  (void *) dev->id);
+	if (err)
+		goto err_free_device;
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_free_irq;
+
+	platform_set_drvdata(dev, input_dev);
+
+	return 0;
+
+ err_free_irq:
+	free_irq(IRQ_IXP4XX_TIMER2, dev);
+ err_free_device:
+	input_free_device(input_dev);
+
+	return err;
+}
+
+static int __devexit ixp4xx_spkr_remove(struct platform_device *dev)
+{
+	struct input_dev *input_dev = platform_get_drvdata(dev);
+	unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
+
+	input_unregister_device(input_dev);
+	platform_set_drvdata(dev, NULL);
+
+	/* turn the speaker off */
+	disable_irq(IRQ_IXP4XX_TIMER2);
+	ixp4xx_spkr_control(pin, 0);
+
+	free_irq(IRQ_IXP4XX_TIMER2, dev);
+
+	return 0;
+}
+
+static void ixp4xx_spkr_shutdown(struct platform_device *dev)
+{
+	struct input_dev *input_dev = platform_get_drvdata(dev);
+	unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
+
+	/* turn off the speaker */
+	disable_irq(IRQ_IXP4XX_TIMER2);
+	ixp4xx_spkr_control(pin, 0);
+}
+
+static struct platform_driver ixp4xx_spkr_platform_driver = {
+	.driver		= {
+		.name	= "ixp4xx-beeper",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ixp4xx_spkr_probe,
+	.remove		= __devexit_p(ixp4xx_spkr_remove),
+	.shutdown	= ixp4xx_spkr_shutdown,
+};
+module_platform_driver(ixp4xx_spkr_platform_driver);
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/keyspan_remote.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/keyspan_remote.c
new file mode 100644
index 0000000..d99151a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/keyspan_remote.c
@@ -0,0 +1,588 @@
+/*
+ * keyspan_remote: USB driver for the Keyspan DMR
+ *
+ * Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.com)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ *
+ * This driver has been put together with the support of Innosys, Inc.
+ * and Keyspan, Inc the manufacturers of the Keyspan USB DMR product.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb/input.h>
+
+#define DRIVER_VERSION	"v0.1"
+#define DRIVER_AUTHOR	"Michael Downey <downey@zymeta.com>"
+#define DRIVER_DESC	"Driver for the USB Keyspan remote control."
+#define DRIVER_LICENSE	"GPL"
+
+/* Parameters that can be passed to the driver. */
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+/* Vendor and product ids */
+#define USB_KEYSPAN_VENDOR_ID		0x06CD
+#define USB_KEYSPAN_PRODUCT_UIA11	0x0202
+
+/* Defines for converting the data from the remote. */
+#define ZERO		0x18
+#define ZERO_MASK	0x1F	/* 5 bits for a 0 */
+#define ONE		0x3C
+#define ONE_MASK	0x3F	/* 6 bits for a 1 */
+#define SYNC		0x3F80
+#define SYNC_MASK	0x3FFF	/* 14 bits for a SYNC sequence */
+#define STOP		0x00
+#define STOP_MASK	0x1F	/* 5 bits for the STOP sequence */
+#define GAP		0xFF
+
+#define RECV_SIZE	8	/* The UIA-11 type have a 8 byte limit. */
+
+/*
+ * Table that maps the 31 possible keycodes to input keys.
+ * Currently there are 15 and 17 button models so RESERVED codes
+ * are blank areas in the mapping.
+ */
+static const unsigned short keyspan_key_table[] = {
+	KEY_RESERVED,		/* 0 is just a place holder. */
+	KEY_RESERVED,
+	KEY_STOP,
+	KEY_PLAYCD,
+	KEY_RESERVED,
+	KEY_PREVIOUSSONG,
+	KEY_REWIND,
+	KEY_FORWARD,
+	KEY_NEXTSONG,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_PAUSE,
+	KEY_VOLUMEUP,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_VOLUMEDOWN,
+	KEY_RESERVED,
+	KEY_UP,
+	KEY_RESERVED,
+	KEY_MUTE,
+	KEY_LEFT,
+	KEY_ENTER,
+	KEY_RIGHT,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_DOWN,
+	KEY_RESERVED,
+	KEY_KPASTERISK,
+	KEY_RESERVED,
+	KEY_MENU
+};
+
+/* table of devices that work with this driver */
+static struct usb_device_id keyspan_table[] = {
+	{ USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) },
+	{ }					/* Terminating entry */
+};
+
+/* Structure to store all the real stuff that a remote sends to us. */
+struct keyspan_message {
+	u16	system;
+	u8	button;
+	u8	toggle;
+};
+
+/* Structure used for all the bit testing magic needed to be done. */
+struct bit_tester {
+	u32	tester;
+	int	len;
+	int	pos;
+	int	bits_left;
+	u8	buffer[32];
+};
+
+/* Structure to hold all of our driver specific stuff */
+struct usb_keyspan {
+	char				name[128];
+	char				phys[64];
+	unsigned short			keymap[ARRAY_SIZE(keyspan_key_table)];
+	struct usb_device		*udev;
+	struct input_dev		*input;
+	struct usb_interface		*interface;
+	struct usb_endpoint_descriptor	*in_endpoint;
+	struct urb*			irq_urb;
+	int				open;
+	dma_addr_t			in_dma;
+	unsigned char			*in_buffer;
+
+	/* variables used to parse messages from remote. */
+	struct bit_tester		data;
+	int				stage;
+	int				toggle;
+};
+
+static struct usb_driver keyspan_driver;
+
+/*
+ * Debug routine that prints out what we've received from the remote.
+ */
+static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/
+{
+	char codes[4 * RECV_SIZE];
+	int i;
+
+	for (i = 0; i < RECV_SIZE; i++)
+		snprintf(codes + i * 3, 4, "%02x ", dev->in_buffer[i]);
+
+	dev_info(&dev->udev->dev, "%s\n", codes);
+}
+
+/*
+ * Routine that manages the bit_tester structure.  It makes sure that there are
+ * at least bits_needed bits loaded into the tester.
+ */
+static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed)
+{
+	if (dev->data.bits_left >= bits_needed)
+		return 0;
+
+	/*
+	 * Somehow we've missed the last message. The message will be repeated
+	 * though so it's not too big a deal
+	 */
+	if (dev->data.pos >= dev->data.len) {
+		dev_dbg(&dev->udev->dev,
+			"%s - Error ran out of data. pos: %d, len: %d\n",
+			__func__, dev->data.pos, dev->data.len);
+		return -1;
+	}
+
+	/* Load as much as we can into the tester. */
+	while ((dev->data.bits_left + 7 < (sizeof(dev->data.tester) * 8)) &&
+	       (dev->data.pos < dev->data.len)) {
+		dev->data.tester += (dev->data.buffer[dev->data.pos++] << dev->data.bits_left);
+		dev->data.bits_left += 8;
+	}
+
+	return 0;
+}
+
+static void keyspan_report_button(struct usb_keyspan *remote, int button, int press)
+{
+	struct input_dev *input = remote->input;
+
+	input_event(input, EV_MSC, MSC_SCAN, button);
+	input_report_key(input, remote->keymap[button], press);
+	input_sync(input);
+}
+
+/*
+ * Routine that handles all the logic needed to parse out the message from the remote.
+ */
+static void keyspan_check_data(struct usb_keyspan *remote)
+{
+	int i;
+	int found = 0;
+	struct keyspan_message message;
+
+	switch(remote->stage) {
+	case 0:
+		/*
+		 * In stage 0 we want to find the start of a message.  The remote sends a 0xFF as filler.
+		 * So the first byte that isn't a FF should be the start of a new message.
+		 */
+		for (i = 0; i < RECV_SIZE && remote->in_buffer[i] == GAP; ++i);
+
+		if (i < RECV_SIZE) {
+			memcpy(remote->data.buffer, remote->in_buffer, RECV_SIZE);
+			remote->data.len = RECV_SIZE;
+			remote->data.pos = 0;
+			remote->data.tester = 0;
+			remote->data.bits_left = 0;
+			remote->stage = 1;
+		}
+		break;
+
+	case 1:
+		/*
+		 * Stage 1 we should have 16 bytes and should be able to detect a
+		 * SYNC.  The SYNC is 14 bits, 7 0's and then 7 1's.
+		 */
+		memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
+		remote->data.len += RECV_SIZE;
+
+		found = 0;
+		while ((remote->data.bits_left >= 14 || remote->data.pos < remote->data.len) && !found) {
+			for (i = 0; i < 8; ++i) {
+				if (keyspan_load_tester(remote, 14) != 0) {
+					remote->stage = 0;
+					return;
+				}
+
+				if ((remote->data.tester & SYNC_MASK) == SYNC) {
+					remote->data.tester = remote->data.tester >> 14;
+					remote->data.bits_left -= 14;
+					found = 1;
+					break;
+				} else {
+					remote->data.tester = remote->data.tester >> 1;
+					--remote->data.bits_left;
+				}
+			}
+		}
+
+		if (!found) {
+			remote->stage = 0;
+			remote->data.len = 0;
+		} else {
+			remote->stage = 2;
+		}
+		break;
+
+	case 2:
+		/*
+		 * Stage 2 we should have 24 bytes which will be enough for a full
+		 * message.  We need to parse out the system code, button code,
+		 * toggle code, and stop.
+		 */
+		memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
+		remote->data.len += RECV_SIZE;
+
+		message.system = 0;
+		for (i = 0; i < 9; i++) {
+			keyspan_load_tester(remote, 6);
+
+			if ((remote->data.tester & ZERO_MASK) == ZERO) {
+				message.system = message.system << 1;
+				remote->data.tester = remote->data.tester >> 5;
+				remote->data.bits_left -= 5;
+			} else if ((remote->data.tester & ONE_MASK) == ONE) {
+				message.system = (message.system << 1) + 1;
+				remote->data.tester = remote->data.tester >> 6;
+				remote->data.bits_left -= 6;
+			} else {
+				err("%s - Unknown sequence found in system data.\n", __func__);
+				remote->stage = 0;
+				return;
+			}
+		}
+
+		message.button = 0;
+		for (i = 0; i < 5; i++) {
+			keyspan_load_tester(remote, 6);
+
+			if ((remote->data.tester & ZERO_MASK) == ZERO) {
+				message.button = message.button << 1;
+				remote->data.tester = remote->data.tester >> 5;
+				remote->data.bits_left -= 5;
+			} else if ((remote->data.tester & ONE_MASK) == ONE) {
+				message.button = (message.button << 1) + 1;
+				remote->data.tester = remote->data.tester >> 6;
+				remote->data.bits_left -= 6;
+			} else {
+				err("%s - Unknown sequence found in button data.\n", __func__);
+				remote->stage = 0;
+				return;
+			}
+		}
+
+		keyspan_load_tester(remote, 6);
+		if ((remote->data.tester & ZERO_MASK) == ZERO) {
+			message.toggle = 0;
+			remote->data.tester = remote->data.tester >> 5;
+			remote->data.bits_left -= 5;
+		} else if ((remote->data.tester & ONE_MASK) == ONE) {
+			message.toggle = 1;
+			remote->data.tester = remote->data.tester >> 6;
+			remote->data.bits_left -= 6;
+		} else {
+			err("%s - Error in message, invalid toggle.\n", __func__);
+			remote->stage = 0;
+			return;
+		}
+
+		keyspan_load_tester(remote, 5);
+		if ((remote->data.tester & STOP_MASK) == STOP) {
+			remote->data.tester = remote->data.tester >> 5;
+			remote->data.bits_left -= 5;
+		} else {
+			err("Bad message received, no stop bit found.\n");
+		}
+
+		dev_dbg(&remote->udev->dev,
+			"%s found valid message: system: %d, button: %d, toggle: %d\n",
+			__func__, message.system, message.button, message.toggle);
+
+		if (message.toggle != remote->toggle) {
+			keyspan_report_button(remote, message.button, 1);
+			keyspan_report_button(remote, message.button, 0);
+			remote->toggle = message.toggle;
+		}
+
+		remote->stage = 0;
+		break;
+	}
+}
+
+/*
+ * Routine for sending all the initialization messages to the remote.
+ */
+static int keyspan_setup(struct usb_device* dev)
+{
+	int retval = 0;
+
+	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+				 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0);
+	if (retval) {
+		dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n",
+			__func__, retval);
+		return(retval);
+	}
+
+	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+				 0x44, 0x40, 0x0, 0x0, NULL, 0, 0);
+	if (retval) {
+		dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n",
+			__func__, retval);
+		return(retval);
+	}
+
+	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+				 0x22, 0x40, 0x0, 0x0, NULL, 0, 0);
+	if (retval) {
+		dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n",
+			__func__, retval);
+		return(retval);
+	}
+
+	dev_dbg(&dev->dev, "%s - Setup complete.\n", __func__);
+	return(retval);
+}
+
+/*
+ * Routine used to handle a new message that has come in.
+ */
+static void keyspan_irq_recv(struct urb *urb)
+{
+	struct usb_keyspan *dev = urb->context;
+	int retval;
+
+	/* Check our status in case we need to bail out early. */
+	switch (urb->status) {
+	case 0:
+		break;
+
+	/* Device went away so don't keep trying to read from it. */
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+
+	default:
+		goto resubmit;
+		break;
+	}
+
+	if (debug)
+		keyspan_print(dev);
+
+	keyspan_check_data(dev);
+
+resubmit:
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err ("%s - usb_submit_urb failed with result: %d", __func__, retval);
+}
+
+static int keyspan_open(struct input_dev *dev)
+{
+	struct usb_keyspan *remote = input_get_drvdata(dev);
+
+	remote->irq_urb->dev = remote->udev;
+	if (usb_submit_urb(remote->irq_urb, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+static void keyspan_close(struct input_dev *dev)
+{
+	struct usb_keyspan *remote = input_get_drvdata(dev);
+
+	usb_kill_urb(remote->irq_urb);
+}
+
+static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_interface *iface)
+{
+
+	struct usb_endpoint_descriptor *endpoint;
+	int i;
+
+	for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
+		endpoint = &iface->endpoint[i].desc;
+
+		if (usb_endpoint_is_int_in(endpoint)) {
+			/* we found our interrupt in endpoint */
+			return endpoint;
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * Routine that sets up the driver to handle a specific USB device detected on the bus.
+ */
+static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_keyspan *remote;
+	struct input_dev *input_dev;
+	int i, error;
+
+	endpoint = keyspan_get_in_endpoint(interface->cur_altsetting);
+	if (!endpoint)
+		return -ENODEV;
+
+	remote = kzalloc(sizeof(*remote), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!remote || !input_dev) {
+		error = -ENOMEM;
+		goto fail1;
+	}
+
+	remote->udev = udev;
+	remote->input = input_dev;
+	remote->interface = interface;
+	remote->in_endpoint = endpoint;
+	remote->toggle = -1;	/* Set to -1 so we will always not match the toggle from the first remote message. */
+
+	remote->in_buffer = usb_alloc_coherent(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma);
+	if (!remote->in_buffer) {
+		error = -ENOMEM;
+		goto fail1;
+	}
+
+	remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!remote->irq_urb) {
+		error = -ENOMEM;
+		goto fail2;
+	}
+
+	error = keyspan_setup(udev);
+	if (error) {
+		error = -ENODEV;
+		goto fail3;
+	}
+
+	if (udev->manufacturer)
+		strlcpy(remote->name, udev->manufacturer, sizeof(remote->name));
+
+	if (udev->product) {
+		if (udev->manufacturer)
+			strlcat(remote->name, " ", sizeof(remote->name));
+		strlcat(remote->name, udev->product, sizeof(remote->name));
+	}
+
+	if (!strlen(remote->name))
+		snprintf(remote->name, sizeof(remote->name),
+			 "USB Keyspan Remote %04x:%04x",
+			 le16_to_cpu(udev->descriptor.idVendor),
+			 le16_to_cpu(udev->descriptor.idProduct));
+
+	usb_make_path(udev, remote->phys, sizeof(remote->phys));
+	strlcat(remote->phys, "/input0", sizeof(remote->phys));
+	memcpy(remote->keymap, keyspan_key_table, sizeof(remote->keymap));
+
+	input_dev->name = remote->name;
+	input_dev->phys = remote->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &interface->dev;
+	input_dev->keycode = remote->keymap;
+	input_dev->keycodesize = sizeof(unsigned short);
+	input_dev->keycodemax = ARRAY_SIZE(remote->keymap);
+
+	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+	__set_bit(EV_KEY, input_dev->evbit);
+	for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++)
+		__set_bit(keyspan_key_table[i], input_dev->keybit);
+	__clear_bit(KEY_RESERVED, input_dev->keybit);
+
+	input_set_drvdata(input_dev, remote);
+
+	input_dev->open = keyspan_open;
+	input_dev->close = keyspan_close;
+
+	/*
+	 * Initialize the URB to access the device.
+	 * The urb gets sent to the device in keyspan_open()
+	 */
+	usb_fill_int_urb(remote->irq_urb,
+			 remote->udev,
+			 usb_rcvintpipe(remote->udev, endpoint->bEndpointAddress),
+			 remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote,
+			 endpoint->bInterval);
+	remote->irq_urb->transfer_dma = remote->in_dma;
+	remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* we can register the device now, as it is ready */
+	error = input_register_device(remote->input);
+	if (error)
+		goto fail3;
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, remote);
+
+	return 0;
+
+ fail3:	usb_free_urb(remote->irq_urb);
+ fail2:	usb_free_coherent(udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
+ fail1:	kfree(remote);
+	input_free_device(input_dev);
+
+	return error;
+}
+
+/*
+ * Routine called when a device is disconnected from the USB.
+ */
+static void keyspan_disconnect(struct usb_interface *interface)
+{
+	struct usb_keyspan *remote;
+
+	remote = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	if (remote) {	/* We have a valid driver structure so clean up everything we allocated. */
+		input_unregister_device(remote->input);
+		usb_kill_urb(remote->irq_urb);
+		usb_free_urb(remote->irq_urb);
+		usb_free_coherent(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
+		kfree(remote);
+	}
+}
+
+/*
+ * Standard driver set up sections
+ */
+static struct usb_driver keyspan_driver =
+{
+	.name =		"keyspan_remote",
+	.probe =	keyspan_probe,
+	.disconnect =	keyspan_disconnect,
+	.id_table =	keyspan_table
+};
+
+module_usb_driver(keyspan_driver);
+
+MODULE_DEVICE_TABLE(usb, keyspan_table);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/kxtj9.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/kxtj9.c
new file mode 100644
index 0000000..f46139f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/kxtj9.c
@@ -0,0 +1,674 @@
+/*
+ * Copyright (C) 2011 Kionix, Inc.
+ * Written by Chris Hudson <chudson@kionix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input/kxtj9.h>
+#include <linux/input-polldev.h>
+
+#define NAME			"kxtj9"
+#define G_MAX			8000
+/* OUTPUT REGISTERS */
+#define XOUT_L			0x06
+#define WHO_AM_I		0x0F
+/* CONTROL REGISTERS */
+#define INT_REL			0x1A
+#define CTRL_REG1		0x1B
+#define INT_CTRL1		0x1E
+#define DATA_CTRL		0x21
+/* CONTROL REGISTER 1 BITS */
+#define PC1_OFF			0x7F
+#define PC1_ON			(1 << 7)
+/* Data ready funtion enable bit: set during probe if using irq mode */
+#define DRDYE			(1 << 5)
+/* DATA CONTROL REGISTER BITS */
+#define ODR12_5F		0
+#define ODR25F			1
+#define ODR50F			2
+#define ODR100F		3
+#define ODR200F		4
+#define ODR400F		5
+#define ODR800F		6
+/* INTERRUPT CONTROL REGISTER 1 BITS */
+/* Set these during probe if using irq mode */
+#define KXTJ9_IEL		(1 << 3)
+#define KXTJ9_IEA		(1 << 4)
+#define KXTJ9_IEN		(1 << 5)
+/* INPUT_ABS CONSTANTS */
+#define FUZZ			3
+#define FLAT			3
+/* RESUME STATE INDICES */
+#define RES_DATA_CTRL		0
+#define RES_CTRL_REG1		1
+#define RES_INT_CTRL1		2
+#define RESUME_ENTRIES		3
+
+/*
+ * The following table lists the maximum appropriate poll interval for each
+ * available output data rate.
+ */
+static const struct {
+	unsigned int cutoff;
+	u8 mask;
+} kxtj9_odr_table[] = {
+	{ 3,	ODR800F },
+	{ 5,	ODR400F },
+	{ 10,	ODR200F },
+	{ 20,	ODR100F },
+	{ 40,	ODR50F  },
+	{ 80,	ODR25F  },
+	{ 0,	ODR12_5F},
+};
+
+struct kxtj9_data {
+	struct i2c_client *client;
+	struct kxtj9_platform_data pdata;
+	struct input_dev *input_dev;
+#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE
+	struct input_polled_dev *poll_dev;
+#endif
+	unsigned int last_poll_interval;
+	u8 shift;
+	u8 ctrl_reg1;
+	u8 data_ctrl;
+	u8 int_ctrl;
+};
+
+static int kxtj9_i2c_read(struct kxtj9_data *tj9, u8 addr, u8 *data, int len)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr = tj9->client->addr,
+			.flags = tj9->client->flags,
+			.len = 1,
+			.buf = &addr,
+		},
+		{
+			.addr = tj9->client->addr,
+			.flags = tj9->client->flags | I2C_M_RD,
+			.len = len,
+			.buf = data,
+		},
+	};
+
+	return i2c_transfer(tj9->client->adapter, msgs, 2);
+}
+
+static void kxtj9_report_acceleration_data(struct kxtj9_data *tj9)
+{
+	s16 acc_data[3]; /* Data bytes from hardware xL, xH, yL, yH, zL, zH */
+	s16 x, y, z;
+	int err;
+
+	err = kxtj9_i2c_read(tj9, XOUT_L, (u8 *)acc_data, 6);
+	if (err < 0)
+		dev_err(&tj9->client->dev, "accelerometer data read failed\n");
+
+	x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]);
+	y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]);
+	z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]);
+
+	x >>= tj9->shift;
+	y >>= tj9->shift;
+	z >>= tj9->shift;
+
+	input_report_abs(tj9->input_dev, ABS_X, tj9->pdata.negate_x ? -x : x);
+	input_report_abs(tj9->input_dev, ABS_Y, tj9->pdata.negate_y ? -y : y);
+	input_report_abs(tj9->input_dev, ABS_Z, tj9->pdata.negate_z ? -z : z);
+	input_sync(tj9->input_dev);
+}
+
+static irqreturn_t kxtj9_isr(int irq, void *dev)
+{
+	struct kxtj9_data *tj9 = dev;
+	int err;
+
+	/* data ready is the only possible interrupt type */
+	kxtj9_report_acceleration_data(tj9);
+
+	err = i2c_smbus_read_byte_data(tj9->client, INT_REL);
+	if (err < 0)
+		dev_err(&tj9->client->dev,
+			"error clearing interrupt status: %d\n", err);
+
+	return IRQ_HANDLED;
+}
+
+static int kxtj9_update_g_range(struct kxtj9_data *tj9, u8 new_g_range)
+{
+	switch (new_g_range) {
+	case KXTJ9_G_2G:
+		tj9->shift = 4;
+		break;
+	case KXTJ9_G_4G:
+		tj9->shift = 3;
+		break;
+	case KXTJ9_G_8G:
+		tj9->shift = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	tj9->ctrl_reg1 &= 0xe7;
+	tj9->ctrl_reg1 |= new_g_range;
+
+	return 0;
+}
+
+static int kxtj9_update_odr(struct kxtj9_data *tj9, unsigned int poll_interval)
+{
+	int err;
+	int i;
+
+	/* Use the lowest ODR that can support the requested poll interval */
+	for (i = 0; i < ARRAY_SIZE(kxtj9_odr_table); i++) {
+		tj9->data_ctrl = kxtj9_odr_table[i].mask;
+		if (poll_interval < kxtj9_odr_table[i].cutoff)
+			break;
+	}
+
+	err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0);
+	if (err < 0)
+		return err;
+
+	err = i2c_smbus_write_byte_data(tj9->client, DATA_CTRL, tj9->data_ctrl);
+	if (err < 0)
+		return err;
+
+	err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int kxtj9_device_power_on(struct kxtj9_data *tj9)
+{
+	if (tj9->pdata.power_on)
+		return tj9->pdata.power_on();
+
+	return 0;
+}
+
+static void kxtj9_device_power_off(struct kxtj9_data *tj9)
+{
+	int err;
+
+	tj9->ctrl_reg1 &= PC1_OFF;
+	err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
+	if (err < 0)
+		dev_err(&tj9->client->dev, "soft power off failed\n");
+
+	if (tj9->pdata.power_off)
+		tj9->pdata.power_off();
+}
+
+static int kxtj9_enable(struct kxtj9_data *tj9)
+{
+	int err;
+
+	err = kxtj9_device_power_on(tj9);
+	if (err < 0)
+		return err;
+
+	/* ensure that PC1 is cleared before updating control registers */
+	err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0);
+	if (err < 0)
+		return err;
+
+	/* only write INT_CTRL_REG1 if in irq mode */
+	if (tj9->client->irq) {
+		err = i2c_smbus_write_byte_data(tj9->client,
+						INT_CTRL1, tj9->int_ctrl);
+		if (err < 0)
+			return err;
+	}
+
+	err = kxtj9_update_g_range(tj9, tj9->pdata.g_range);
+	if (err < 0)
+		return err;
+
+	/* turn on outputs */
+	tj9->ctrl_reg1 |= PC1_ON;
+	err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
+	if (err < 0)
+		return err;
+
+	err = kxtj9_update_odr(tj9, tj9->last_poll_interval);
+	if (err < 0)
+		return err;
+
+	/* clear initial interrupt if in irq mode */
+	if (tj9->client->irq) {
+		err = i2c_smbus_read_byte_data(tj9->client, INT_REL);
+		if (err < 0) {
+			dev_err(&tj9->client->dev,
+				"error clearing interrupt: %d\n", err);
+			goto fail;
+		}
+	}
+
+	return 0;
+
+fail:
+	kxtj9_device_power_off(tj9);
+	return err;
+}
+
+static void kxtj9_disable(struct kxtj9_data *tj9)
+{
+	kxtj9_device_power_off(tj9);
+}
+
+static int kxtj9_input_open(struct input_dev *input)
+{
+	struct kxtj9_data *tj9 = input_get_drvdata(input);
+
+	return kxtj9_enable(tj9);
+}
+
+static void kxtj9_input_close(struct input_dev *dev)
+{
+	struct kxtj9_data *tj9 = input_get_drvdata(dev);
+
+	kxtj9_disable(tj9);
+}
+
+static void __devinit kxtj9_init_input_device(struct kxtj9_data *tj9,
+					      struct input_dev *input_dev)
+{
+	__set_bit(EV_ABS, input_dev->evbit);
+	input_set_abs_params(input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT);
+	input_set_abs_params(input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT);
+	input_set_abs_params(input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT);
+
+	input_dev->name = "kxtj9_accel";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &tj9->client->dev;
+}
+
+static int __devinit kxtj9_setup_input_device(struct kxtj9_data *tj9)
+{
+	struct input_dev *input_dev;
+	int err;
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		dev_err(&tj9->client->dev, "input device allocate failed\n");
+		return -ENOMEM;
+	}
+
+	tj9->input_dev = input_dev;
+
+	input_dev->open = kxtj9_input_open;
+	input_dev->close = kxtj9_input_close;
+	input_set_drvdata(input_dev, tj9);
+
+	kxtj9_init_input_device(tj9, input_dev);
+
+	err = input_register_device(tj9->input_dev);
+	if (err) {
+		dev_err(&tj9->client->dev,
+			"unable to register input polled device %s: %d\n",
+			tj9->input_dev->name, err);
+		input_free_device(tj9->input_dev);
+		return err;
+	}
+
+	return 0;
+}
+
+/*
+ * When IRQ mode is selected, we need to provide an interface to allow the user
+ * to change the output data rate of the part.  For consistency, we are using
+ * the set_poll method, which accepts a poll interval in milliseconds, and then
+ * calls update_odr() while passing this value as an argument.  In IRQ mode, the
+ * data outputs will not be read AT the requested poll interval, rather, the
+ * lowest ODR that can support the requested interval.  The client application
+ * will be responsible for retrieving data from the input node at the desired
+ * interval.
+ */
+
+/* Returns currently selected poll interval (in ms) */
+static ssize_t kxtj9_get_poll(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct kxtj9_data *tj9 = i2c_get_clientdata(client);
+
+	return sprintf(buf, "%d\n", tj9->last_poll_interval);
+}
+
+/* Allow users to select a new poll interval (in ms) */
+static ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct kxtj9_data *tj9 = i2c_get_clientdata(client);
+	struct input_dev *input_dev = tj9->input_dev;
+	unsigned int interval;
+	int error;
+
+	error = kstrtouint(buf, 10, &interval);
+	if (error < 0)
+		return error;
+
+	/* Lock the device to prevent races with open/close (and itself) */
+	mutex_lock(&input_dev->mutex);
+
+	disable_irq(client->irq);
+
+	/*
+	 * Set current interval to the greater of the minimum interval or
+	 * the requested interval
+	 */
+	tj9->last_poll_interval = max(interval, tj9->pdata.min_interval);
+
+	kxtj9_update_odr(tj9, tj9->last_poll_interval);
+
+	enable_irq(client->irq);
+	mutex_unlock(&input_dev->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(poll, S_IRUGO|S_IWUSR, kxtj9_get_poll, kxtj9_set_poll);
+
+static struct attribute *kxtj9_attributes[] = {
+	&dev_attr_poll.attr,
+	NULL
+};
+
+static struct attribute_group kxtj9_attribute_group = {
+	.attrs = kxtj9_attributes
+};
+
+
+#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE
+static void kxtj9_poll(struct input_polled_dev *dev)
+{
+	struct kxtj9_data *tj9 = dev->private;
+	unsigned int poll_interval = dev->poll_interval;
+
+	kxtj9_report_acceleration_data(tj9);
+
+	if (poll_interval != tj9->last_poll_interval) {
+		kxtj9_update_odr(tj9, poll_interval);
+		tj9->last_poll_interval = poll_interval;
+	}
+}
+
+static void kxtj9_polled_input_open(struct input_polled_dev *dev)
+{
+	struct kxtj9_data *tj9 = dev->private;
+
+	kxtj9_enable(tj9);
+}
+
+static void kxtj9_polled_input_close(struct input_polled_dev *dev)
+{
+	struct kxtj9_data *tj9 = dev->private;
+
+	kxtj9_disable(tj9);
+}
+
+static int __devinit kxtj9_setup_polled_device(struct kxtj9_data *tj9)
+{
+	int err;
+	struct input_polled_dev *poll_dev;
+	poll_dev = input_allocate_polled_device();
+
+	if (!poll_dev) {
+		dev_err(&tj9->client->dev,
+			"Failed to allocate polled device\n");
+		return -ENOMEM;
+	}
+
+	tj9->poll_dev = poll_dev;
+	tj9->input_dev = poll_dev->input;
+
+	poll_dev->private = tj9;
+	poll_dev->poll = kxtj9_poll;
+	poll_dev->open = kxtj9_polled_input_open;
+	poll_dev->close = kxtj9_polled_input_close;
+
+	kxtj9_init_input_device(tj9, poll_dev->input);
+
+	err = input_register_polled_device(poll_dev);
+	if (err) {
+		dev_err(&tj9->client->dev,
+			"Unable to register polled device, err=%d\n", err);
+		input_free_polled_device(poll_dev);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __devexit kxtj9_teardown_polled_device(struct kxtj9_data *tj9)
+{
+	input_unregister_polled_device(tj9->poll_dev);
+	input_free_polled_device(tj9->poll_dev);
+}
+
+#else
+
+static inline int kxtj9_setup_polled_device(struct kxtj9_data *tj9)
+{
+	return -ENOSYS;
+}
+
+static inline void kxtj9_teardown_polled_device(struct kxtj9_data *tj9)
+{
+}
+
+#endif
+
+static int __devinit kxtj9_verify(struct kxtj9_data *tj9)
+{
+	int retval;
+
+	retval = kxtj9_device_power_on(tj9);
+	if (retval < 0)
+		return retval;
+
+	retval = i2c_smbus_read_byte_data(tj9->client, WHO_AM_I);
+	if (retval < 0) {
+		dev_err(&tj9->client->dev, "read err int source\n");
+		goto out;
+	}
+
+	retval = (retval != 0x07 && retval != 0x08) ? -EIO : 0;
+
+out:
+	kxtj9_device_power_off(tj9);
+	return retval;
+}
+
+static int __devinit kxtj9_probe(struct i2c_client *client,
+				 const struct i2c_device_id *id)
+{
+	const struct kxtj9_platform_data *pdata = client->dev.platform_data;
+	struct kxtj9_data *tj9;
+	int err;
+
+	if (!i2c_check_functionality(client->adapter,
+				I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_err(&client->dev, "client is not i2c capable\n");
+		return -ENXIO;
+	}
+
+	if (!pdata) {
+		dev_err(&client->dev, "platform data is NULL; exiting\n");
+		return -EINVAL;
+	}
+
+	tj9 = kzalloc(sizeof(*tj9), GFP_KERNEL);
+	if (!tj9) {
+		dev_err(&client->dev,
+			"failed to allocate memory for module data\n");
+		return -ENOMEM;
+	}
+
+	tj9->client = client;
+	tj9->pdata = *pdata;
+
+	if (pdata->init) {
+		err = pdata->init();
+		if (err < 0)
+			goto err_free_mem;
+	}
+
+	err = kxtj9_verify(tj9);
+	if (err < 0) {
+		dev_err(&client->dev, "device not recognized\n");
+		goto err_pdata_exit;
+	}
+
+	i2c_set_clientdata(client, tj9);
+
+	tj9->ctrl_reg1 = tj9->pdata.res_12bit | tj9->pdata.g_range;
+	tj9->last_poll_interval = tj9->pdata.init_interval;
+
+	if (client->irq) {
+		/* If in irq mode, populate INT_CTRL_REG1 and enable DRDY. */
+		tj9->int_ctrl |= KXTJ9_IEN | KXTJ9_IEA | KXTJ9_IEL;
+		tj9->ctrl_reg1 |= DRDYE;
+
+		err = kxtj9_setup_input_device(tj9);
+		if (err)
+			goto err_pdata_exit;
+
+		err = request_threaded_irq(client->irq, NULL, kxtj9_isr,
+					   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					   "kxtj9-irq", tj9);
+		if (err) {
+			dev_err(&client->dev, "request irq failed: %d\n", err);
+			goto err_destroy_input;
+		}
+
+		err = sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group);
+		if (err) {
+			dev_err(&client->dev, "sysfs create failed: %d\n", err);
+			goto err_free_irq;
+		}
+
+	} else {
+		err = kxtj9_setup_polled_device(tj9);
+		if (err)
+			goto err_pdata_exit;
+	}
+
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, tj9);
+err_destroy_input:
+	input_unregister_device(tj9->input_dev);
+err_pdata_exit:
+	if (tj9->pdata.exit)
+		tj9->pdata.exit();
+err_free_mem:
+	kfree(tj9);
+	return err;
+}
+
+static int __devexit kxtj9_remove(struct i2c_client *client)
+{
+	struct kxtj9_data *tj9 = i2c_get_clientdata(client);
+
+	if (client->irq) {
+		sysfs_remove_group(&client->dev.kobj, &kxtj9_attribute_group);
+		free_irq(client->irq, tj9);
+		input_unregister_device(tj9->input_dev);
+	} else {
+		kxtj9_teardown_polled_device(tj9);
+	}
+
+	if (tj9->pdata.exit)
+		tj9->pdata.exit();
+
+	kfree(tj9);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int kxtj9_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct kxtj9_data *tj9 = i2c_get_clientdata(client);
+	struct input_dev *input_dev = tj9->input_dev;
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		kxtj9_disable(tj9);
+
+	mutex_unlock(&input_dev->mutex);
+	return 0;
+}
+
+static int kxtj9_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct kxtj9_data *tj9 = i2c_get_clientdata(client);
+	struct input_dev *input_dev = tj9->input_dev;
+	int retval = 0;
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		kxtj9_enable(tj9);
+
+	mutex_unlock(&input_dev->mutex);
+	return retval;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
+
+static const struct i2c_device_id kxtj9_id[] = {
+	{ NAME, 0 },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(i2c, kxtj9_id);
+
+static struct i2c_driver kxtj9_driver = {
+	.driver = {
+		.name	= NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &kxtj9_pm_ops,
+	},
+	.probe		= kxtj9_probe,
+	.remove		= __devexit_p(kxtj9_remove),
+	.id_table	= kxtj9_id,
+};
+
+module_i2c_driver(kxtj9_driver);
+
+MODULE_DESCRIPTION("KXTJ9 accelerometer driver");
+MODULE_AUTHOR("Chris Hudson <chudson@kionix.com>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/m68kspkr.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/m68kspkr.c
new file mode 100644
index 0000000..0c64d9b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/m68kspkr.c
@@ -0,0 +1,151 @@
+/*
+ *  m68k beeper driver for Linux
+ *
+ *  Copyright (c) 2002 Richard Zidlicky
+ *  Copyright (c) 2002 Vojtech Pavlik
+ *  Copyright (c) 1992 Orest Zborowski
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+
+MODULE_AUTHOR("Richard Zidlicky <rz@linux-m68k.org>");
+MODULE_DESCRIPTION("m68k beeper driver");
+MODULE_LICENSE("GPL");
+
+static struct platform_device *m68kspkr_platform_device;
+
+static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	unsigned int count = 0;
+
+	if (type != EV_SND)
+		return -1;
+
+	switch (code) {
+		case SND_BELL: if (value) value = 1000;
+		case SND_TONE: break;
+		default: return -1;
+	}
+
+	if (value > 20 && value < 32767)
+		count = 1193182 / value;
+
+	mach_beep(count, -1);
+
+	return 0;
+}
+
+static int __devinit m68kspkr_probe(struct platform_device *dev)
+{
+	struct input_dev *input_dev;
+	int err;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	input_dev->name = "m68k beeper";
+	input_dev->phys = "m68k/generic";
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor  = 0x001f;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &dev->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_SND);
+	input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+	input_dev->event = m68kspkr_event;
+
+	err = input_register_device(input_dev);
+	if (err) {
+		input_free_device(input_dev);
+		return err;
+	}
+
+	platform_set_drvdata(dev, input_dev);
+
+	return 0;
+}
+
+static int __devexit m68kspkr_remove(struct platform_device *dev)
+{
+	struct input_dev *input_dev = platform_get_drvdata(dev);
+
+	input_unregister_device(input_dev);
+	platform_set_drvdata(dev, NULL);
+	/* turn off the speaker */
+	m68kspkr_event(NULL, EV_SND, SND_BELL, 0);
+
+	return 0;
+}
+
+static void m68kspkr_shutdown(struct platform_device *dev)
+{
+	/* turn off the speaker */
+	m68kspkr_event(NULL, EV_SND, SND_BELL, 0);
+}
+
+static struct platform_driver m68kspkr_platform_driver = {
+	.driver		= {
+		.name	= "m68kspkr",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= m68kspkr_probe,
+	.remove		= __devexit_p(m68kspkr_remove),
+	.shutdown	= m68kspkr_shutdown,
+};
+
+static int __init m68kspkr_init(void)
+{
+	int err;
+
+	if (!mach_beep) {
+		printk(KERN_INFO "m68kspkr: no lowlevel beep support\n");
+		return -ENODEV;
+        }
+
+	err = platform_driver_register(&m68kspkr_platform_driver);
+	if (err)
+		return err;
+
+	m68kspkr_platform_device = platform_device_alloc("m68kspkr", -1);
+	if (!m68kspkr_platform_device) {
+		err = -ENOMEM;
+		goto err_unregister_driver;
+	}
+
+	err = platform_device_add(m68kspkr_platform_device);
+	if (err)
+		goto err_free_device;
+
+	return 0;
+
+ err_free_device:
+	platform_device_put(m68kspkr_platform_device);
+ err_unregister_driver:
+	platform_driver_unregister(&m68kspkr_platform_driver);
+
+	return err;
+}
+
+static void __exit m68kspkr_exit(void)
+{
+	platform_device_unregister(m68kspkr_platform_device);
+	platform_driver_unregister(&m68kspkr_platform_driver);
+}
+
+module_init(m68kspkr_init);
+module_exit(m68kspkr_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/max8925_onkey.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/max8925_onkey.c
new file mode 100644
index 0000000..0a12b74
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/max8925_onkey.c
@@ -0,0 +1,204 @@
+/**
+ * MAX8925 ONKEY driver
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ *      Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max8925.h>
+#include <linux/slab.h>
+
+#define SW_INPUT		(1 << 7)	/* 0/1 -- up/down */
+#define HARDRESET_EN		(1 << 7)
+#define PWREN_EN		(1 << 7)
+
+struct max8925_onkey_info {
+	struct input_dev	*idev;
+	struct i2c_client	*i2c;
+	struct device		*dev;
+	unsigned int		irq[2];
+};
+
+/*
+ * MAX8925 gives us an interrupt when ONKEY is pressed or released.
+ * max8925_set_bits() operates I2C bus and may sleep. So implement
+ * it in thread IRQ handler.
+ */
+static irqreturn_t max8925_onkey_handler(int irq, void *data)
+{
+	struct max8925_onkey_info *info = data;
+	int state;
+
+	state = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS);
+
+	input_report_key(info->idev, KEY_POWER, state & SW_INPUT);
+	input_sync(info->idev);
+
+	dev_dbg(info->dev, "onkey state:%d\n", state);
+
+	/* Enable hardreset to halt if system isn't shutdown on time */
+	max8925_set_bits(info->i2c, MAX8925_SYSENSEL,
+			 HARDRESET_EN, HARDRESET_EN);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit max8925_onkey_probe(struct platform_device *pdev)
+{
+	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+	struct max8925_onkey_info *info;
+	struct input_dev *input;
+	int irq[2], error;
+
+	irq[0] = platform_get_irq(pdev, 0);
+	if (irq[0] < 0) {
+		dev_err(&pdev->dev, "No IRQ resource!\n");
+		return -EINVAL;
+	}
+
+	irq[1] = platform_get_irq(pdev, 1);
+	if (irq[1] < 0) {
+		dev_err(&pdev->dev, "No IRQ resource!\n");
+		return -EINVAL;
+	}
+
+	info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!info || !input) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	info->idev = input;
+	info->i2c = chip->i2c;
+	info->dev = &pdev->dev;
+	info->irq[0] = irq[0];
+	info->irq[1] = irq[1];
+
+	input->name = "max8925_on";
+	input->phys = "max8925_on/input0";
+	input->id.bustype = BUS_I2C;
+	input->dev.parent = &pdev->dev;
+	input_set_capability(input, EV_KEY, KEY_POWER);
+
+	irq[0] += chip->irq_base;
+	irq[1] += chip->irq_base;
+
+	error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler,
+				     IRQF_ONESHOT, "onkey-down", info);
+	if (error < 0) {
+		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+			irq[0], error);
+		goto err_free_mem;
+	}
+
+	error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler,
+				     IRQF_ONESHOT, "onkey-up", info);
+	if (error < 0) {
+		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+			irq[1], error);
+		goto err_free_irq0;
+	}
+
+	error = input_register_device(info->idev);
+	if (error) {
+		dev_err(chip->dev, "Can't register input device: %d\n", error);
+		goto err_free_irq1;
+	}
+
+	platform_set_drvdata(pdev, info);
+	device_init_wakeup(&pdev->dev, 1);
+
+	return 0;
+
+err_free_irq1:
+	free_irq(irq[1], info);
+err_free_irq0:
+	free_irq(irq[0], info);
+err_free_mem:
+	input_free_device(input);
+	kfree(info);
+
+	return error;
+}
+
+static int __devexit max8925_onkey_remove(struct platform_device *pdev)
+{
+	struct max8925_onkey_info *info = platform_get_drvdata(pdev);
+	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	free_irq(info->irq[0] + chip->irq_base, info);
+	free_irq(info->irq[1] + chip->irq_base, info);
+	input_unregister_device(info->idev);
+	kfree(info);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max8925_onkey_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct max8925_onkey_info *info = platform_get_drvdata(pdev);
+	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev)) {
+		chip->wakeup_flag |= 1 << info->irq[0];
+		chip->wakeup_flag |= 1 << info->irq[1];
+	}
+
+	return 0;
+}
+
+static int max8925_onkey_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct max8925_onkey_info *info = platform_get_drvdata(pdev);
+	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev)) {
+		chip->wakeup_flag &= ~(1 << info->irq[0]);
+		chip->wakeup_flag &= ~(1 << info->irq[1]);
+	}
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max8925_onkey_pm_ops, max8925_onkey_suspend, max8925_onkey_resume);
+
+static struct platform_driver max8925_onkey_driver = {
+	.driver		= {
+		.name	= "max8925-onkey",
+		.owner	= THIS_MODULE,
+		.pm	= &max8925_onkey_pm_ops,
+	},
+	.probe		= max8925_onkey_probe,
+	.remove		= __devexit_p(max8925_onkey_remove),
+};
+module_platform_driver(max8925_onkey_driver);
+
+MODULE_DESCRIPTION("Maxim MAX8925 ONKEY driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/max8997_haptic.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/max8997_haptic.c
new file mode 100644
index 0000000..05b7b8b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/max8997_haptic.c
@@ -0,0 +1,407 @@
+/*
+ * MAX8997-haptic controller driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Donggeun Kim <dg77.kim@samsung.com>
+ *
+ * This program is not provided / owned by Maxim Integrated Products.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/pwm.h>
+#include <linux/input.h>
+#include <linux/mfd/max8997-private.h>
+#include <linux/mfd/max8997.h>
+#include <linux/regulator/consumer.h>
+
+/* Haptic configuration 2 register */
+#define MAX8997_MOTOR_TYPE_SHIFT	7
+#define MAX8997_ENABLE_SHIFT		6
+#define MAX8997_MODE_SHIFT		5
+
+/* Haptic driver configuration register */
+#define MAX8997_CYCLE_SHIFT		6
+#define MAX8997_SIG_PERIOD_SHIFT	4
+#define MAX8997_SIG_DUTY_SHIFT		2
+#define MAX8997_PWM_DUTY_SHIFT		0
+
+struct max8997_haptic {
+	struct device *dev;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct regulator *regulator;
+
+	struct work_struct work;
+	struct mutex mutex;
+
+	bool enabled;
+	unsigned int level;
+
+	struct pwm_device *pwm;
+	unsigned int pwm_period;
+	enum max8997_haptic_pwm_divisor pwm_divisor;
+
+	enum max8997_haptic_motor_type type;
+	enum max8997_haptic_pulse_mode mode;
+
+	unsigned int internal_mode_pattern;
+	unsigned int pattern_cycle;
+	unsigned int pattern_signal_period;
+};
+
+static int max8997_haptic_set_duty_cycle(struct max8997_haptic *chip)
+{
+	int ret = 0;
+
+	if (chip->mode == MAX8997_EXTERNAL_MODE) {
+		unsigned int duty = chip->pwm_period * chip->level / 100;
+		ret = pwm_config(chip->pwm, duty, chip->pwm_period);
+	} else {
+		int i;
+		u8 duty_index = 0;
+
+		for (i = 0; i <= 64; i++) {
+			if (chip->level <= i * 100 / 64) {
+				duty_index = i;
+				break;
+			}
+		}
+		switch (chip->internal_mode_pattern) {
+		case 0:
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index);
+			break;
+		case 1:
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index);
+			break;
+		case 2:
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index);
+			break;
+		case 3:
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index);
+			break;
+		default:
+			break;
+		}
+	}
+	return ret;
+}
+
+static void max8997_haptic_configure(struct max8997_haptic *chip)
+{
+	u8 value;
+
+	value = chip->type << MAX8997_MOTOR_TYPE_SHIFT |
+		chip->enabled << MAX8997_ENABLE_SHIFT |
+		chip->mode << MAX8997_MODE_SHIFT | chip->pwm_divisor;
+	max8997_write_reg(chip->client, MAX8997_HAPTIC_REG_CONF2, value);
+
+	if (chip->mode == MAX8997_INTERNAL_MODE && chip->enabled) {
+		value = chip->internal_mode_pattern << MAX8997_CYCLE_SHIFT |
+			chip->internal_mode_pattern << MAX8997_SIG_PERIOD_SHIFT |
+			chip->internal_mode_pattern << MAX8997_SIG_DUTY_SHIFT |
+			chip->internal_mode_pattern << MAX8997_PWM_DUTY_SHIFT;
+		max8997_write_reg(chip->client,
+			MAX8997_HAPTIC_REG_DRVCONF, value);
+
+		switch (chip->internal_mode_pattern) {
+		case 0:
+			value = chip->pattern_cycle << 4;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_CYCLECONF1, value);
+			value = chip->pattern_signal_period;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGCONF1, value);
+			break;
+
+		case 1:
+			value = chip->pattern_cycle;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_CYCLECONF1, value);
+			value = chip->pattern_signal_period;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGCONF2, value);
+			break;
+
+		case 2:
+			value = chip->pattern_cycle << 4;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_CYCLECONF2, value);
+			value = chip->pattern_signal_period;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGCONF3, value);
+			break;
+
+		case 3:
+			value = chip->pattern_cycle;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_CYCLECONF2, value);
+			value = chip->pattern_signal_period;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGCONF4, value);
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
+static void max8997_haptic_enable(struct max8997_haptic *chip)
+{
+	int error;
+
+	mutex_lock(&chip->mutex);
+
+	error = max8997_haptic_set_duty_cycle(chip);
+	if (error) {
+		dev_err(chip->dev, "set_pwm_cycle failed, error: %d\n", error);
+		goto out;
+	}
+
+	if (!chip->enabled) {
+		chip->enabled = true;
+		regulator_enable(chip->regulator);
+		max8997_haptic_configure(chip);
+		if (chip->mode == MAX8997_EXTERNAL_MODE)
+			pwm_enable(chip->pwm);
+	}
+
+out:
+	mutex_unlock(&chip->mutex);
+}
+
+static void max8997_haptic_disable(struct max8997_haptic *chip)
+{
+	mutex_lock(&chip->mutex);
+
+	if (chip->enabled) {
+		chip->enabled = false;
+		max8997_haptic_configure(chip);
+		if (chip->mode == MAX8997_EXTERNAL_MODE)
+			pwm_disable(chip->pwm);
+		regulator_disable(chip->regulator);
+	}
+
+	mutex_unlock(&chip->mutex);
+}
+
+static void max8997_haptic_play_effect_work(struct work_struct *work)
+{
+	struct max8997_haptic *chip =
+			container_of(work, struct max8997_haptic, work);
+
+	if (chip->level)
+		max8997_haptic_enable(chip);
+	else
+		max8997_haptic_disable(chip);
+}
+
+static int max8997_haptic_play_effect(struct input_dev *dev, void *data,
+				  struct ff_effect *effect)
+{
+	struct max8997_haptic *chip = input_get_drvdata(dev);
+
+	chip->level = effect->u.rumble.strong_magnitude;
+	if (!chip->level)
+		chip->level = effect->u.rumble.weak_magnitude;
+
+	schedule_work(&chip->work);
+
+	return 0;
+}
+
+static void max8997_haptic_close(struct input_dev *dev)
+{
+	struct max8997_haptic *chip = input_get_drvdata(dev);
+
+	cancel_work_sync(&chip->work);
+	max8997_haptic_disable(chip);
+}
+
+static int __devinit max8997_haptic_probe(struct platform_device *pdev)
+{
+	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	const struct max8997_platform_data *pdata =
+					dev_get_platdata(iodev->dev);
+	const struct max8997_haptic_platform_data *haptic_pdata =
+					pdata->haptic_pdata;
+	struct max8997_haptic *chip;
+	struct input_dev *input_dev;
+	int error;
+
+	if (!haptic_pdata) {
+		dev_err(&pdev->dev, "no haptic platform data\n");
+		return -EINVAL;
+	}
+
+	chip = kzalloc(sizeof(struct max8997_haptic), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!chip || !input_dev) {
+		dev_err(&pdev->dev, "unable to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	INIT_WORK(&chip->work, max8997_haptic_play_effect_work);
+	mutex_init(&chip->mutex);
+
+	chip->client = iodev->haptic;
+	chip->dev = &pdev->dev;
+	chip->input_dev = input_dev;
+	chip->pwm_period = haptic_pdata->pwm_period;
+	chip->type = haptic_pdata->type;
+	chip->mode = haptic_pdata->mode;
+	chip->pwm_divisor = haptic_pdata->pwm_divisor;
+
+	switch (chip->mode) {
+	case MAX8997_INTERNAL_MODE:
+		chip->internal_mode_pattern =
+				haptic_pdata->internal_mode_pattern;
+		chip->pattern_cycle = haptic_pdata->pattern_cycle;
+		chip->pattern_signal_period =
+				haptic_pdata->pattern_signal_period;
+		break;
+
+	case MAX8997_EXTERNAL_MODE:
+		chip->pwm = pwm_request(haptic_pdata->pwm_channel_id,
+					"max8997-haptic");
+		if (IS_ERR(chip->pwm)) {
+			error = PTR_ERR(chip->pwm);
+			dev_err(&pdev->dev,
+				"unable to request PWM for haptic, error: %d\n",
+				error);
+			goto err_free_mem;
+		}
+		break;
+
+	default:
+		dev_err(&pdev->dev,
+			"Invalid chip mode specified (%d)\n", chip->mode);
+		error = -EINVAL;
+		goto err_free_mem;
+	}
+
+	chip->regulator = regulator_get(&pdev->dev, "inmotor");
+	if (IS_ERR(chip->regulator)) {
+		error = PTR_ERR(chip->regulator);
+		dev_err(&pdev->dev,
+			"unable to get regulator, error: %d\n",
+			error);
+		goto err_free_pwm;
+	}
+
+	input_dev->name = "max8997-haptic";
+	input_dev->id.version = 1;
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->close = max8997_haptic_close;
+	input_set_drvdata(input_dev, chip);
+	input_set_capability(input_dev, EV_FF, FF_RUMBLE);
+
+	error = input_ff_create_memless(input_dev, NULL,
+				max8997_haptic_play_effect);
+	if (error) {
+		dev_err(&pdev->dev,
+			"unable to create FF device, error: %d\n",
+			error);
+		goto err_put_regulator;
+	}
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(&pdev->dev,
+			"unable to register input device, error: %d\n",
+			error);
+		goto err_destroy_ff;
+	}
+
+	platform_set_drvdata(pdev, chip);
+	return 0;
+
+err_destroy_ff:
+	input_ff_destroy(input_dev);
+err_put_regulator:
+	regulator_put(chip->regulator);
+err_free_pwm:
+	if (chip->mode == MAX8997_EXTERNAL_MODE)
+		pwm_free(chip->pwm);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(chip);
+
+	return error;
+}
+
+static int __devexit max8997_haptic_remove(struct platform_device *pdev)
+{
+	struct max8997_haptic *chip = platform_get_drvdata(pdev);
+
+	input_unregister_device(chip->input_dev);
+	regulator_put(chip->regulator);
+
+	if (chip->mode == MAX8997_EXTERNAL_MODE)
+		pwm_free(chip->pwm);
+
+	kfree(chip);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max8997_haptic_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct max8997_haptic *chip = platform_get_drvdata(pdev);
+
+	max8997_haptic_disable(chip);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max8997_haptic_pm_ops, max8997_haptic_suspend, NULL);
+
+static const struct platform_device_id max8997_haptic_id[] = {
+	{ "max8997-haptic", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, max8997_haptic_id);
+
+static struct platform_driver max8997_haptic_driver = {
+	.driver	= {
+		.name	= "max8997-haptic",
+		.owner	= THIS_MODULE,
+		.pm	= &max8997_haptic_pm_ops,
+	},
+	.probe		= max8997_haptic_probe,
+	.remove		= __devexit_p(max8997_haptic_remove),
+	.id_table	= max8997_haptic_id,
+};
+module_platform_driver(max8997_haptic_driver);
+
+MODULE_ALIAS("platform:max8997-haptic");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_DESCRIPTION("max8997_haptic driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/mc13783-pwrbutton.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/mc13783-pwrbutton.c
new file mode 100644
index 0000000..8428f1e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/mc13783-pwrbutton.c
@@ -0,0 +1,272 @@
+/**
+ * Copyright (C) 2011 Philippe Rétornaz
+ *
+ * Based on twl4030-pwrbutton driver by:
+ *     Peter De Schrijver <peter.de-schrijver@nokia.com>
+ *     Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/mc13783.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+struct mc13783_pwrb {
+	struct input_dev *pwr;
+	struct mc13xxx *mc13783;
+#define MC13783_PWRB_B1_POL_INVERT	(1 << 0)
+#define MC13783_PWRB_B2_POL_INVERT	(1 << 1)
+#define MC13783_PWRB_B3_POL_INVERT	(1 << 2)
+	int flags;
+	unsigned short keymap[3];
+};
+
+#define MC13783_REG_INTERRUPT_SENSE_1		5
+#define MC13783_IRQSENSE1_ONOFD1S		(1 << 3)
+#define MC13783_IRQSENSE1_ONOFD2S		(1 << 4)
+#define MC13783_IRQSENSE1_ONOFD3S		(1 << 5)
+
+#define MC13783_REG_POWER_CONTROL_2		15
+#define MC13783_POWER_CONTROL_2_ON1BDBNC	4
+#define MC13783_POWER_CONTROL_2_ON2BDBNC	6
+#define MC13783_POWER_CONTROL_2_ON3BDBNC	8
+#define MC13783_POWER_CONTROL_2_ON1BRSTEN	(1 << 1)
+#define MC13783_POWER_CONTROL_2_ON2BRSTEN	(1 << 2)
+#define MC13783_POWER_CONTROL_2_ON3BRSTEN	(1 << 3)
+
+static irqreturn_t button_irq(int irq, void *_priv)
+{
+	struct mc13783_pwrb *priv = _priv;
+	int val;
+
+	mc13xxx_irq_ack(priv->mc13783, irq);
+	mc13xxx_reg_read(priv->mc13783, MC13783_REG_INTERRUPT_SENSE_1, &val);
+
+	switch (irq) {
+	case MC13783_IRQ_ONOFD1:
+		val = val & MC13783_IRQSENSE1_ONOFD1S ? 1 : 0;
+		if (priv->flags & MC13783_PWRB_B1_POL_INVERT)
+			val ^= 1;
+		input_report_key(priv->pwr, priv->keymap[0], val);
+		break;
+
+	case MC13783_IRQ_ONOFD2:
+		val = val & MC13783_IRQSENSE1_ONOFD2S ? 1 : 0;
+		if (priv->flags & MC13783_PWRB_B2_POL_INVERT)
+			val ^= 1;
+		input_report_key(priv->pwr, priv->keymap[1], val);
+		break;
+
+	case MC13783_IRQ_ONOFD3:
+		val = val & MC13783_IRQSENSE1_ONOFD3S ? 1 : 0;
+		if (priv->flags & MC13783_PWRB_B3_POL_INVERT)
+			val ^= 1;
+		input_report_key(priv->pwr, priv->keymap[2], val);
+		break;
+	}
+
+	input_sync(priv->pwr);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit mc13783_pwrbutton_probe(struct platform_device *pdev)
+{
+	const struct mc13xxx_buttons_platform_data *pdata;
+	struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
+	struct input_dev *pwr;
+	struct mc13783_pwrb *priv;
+	int err = 0;
+	int reg = 0;
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "missing platform data\n");
+		return -ENODEV;
+	}
+
+	pwr = input_allocate_device();
+	if (!pwr) {
+		dev_dbg(&pdev->dev, "Can't allocate power button\n");
+		return -ENOMEM;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		err = -ENOMEM;
+		dev_dbg(&pdev->dev, "Can't allocate power button\n");
+		goto free_input_dev;
+	}
+
+	reg |= (pdata->b1on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON1BDBNC;
+	reg |= (pdata->b2on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON2BDBNC;
+	reg |= (pdata->b3on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON3BDBNC;
+
+	priv->pwr = pwr;
+	priv->mc13783 = mc13783;
+
+	mc13xxx_lock(mc13783);
+
+	if (pdata->b1on_flags & MC13783_BUTTON_ENABLE) {
+		priv->keymap[0] = pdata->b1on_key;
+		if (pdata->b1on_key != KEY_RESERVED)
+			__set_bit(pdata->b1on_key, pwr->keybit);
+
+		if (pdata->b1on_flags & MC13783_BUTTON_POL_INVERT)
+			priv->flags |= MC13783_PWRB_B1_POL_INVERT;
+
+		if (pdata->b1on_flags & MC13783_BUTTON_RESET_EN)
+			reg |= MC13783_POWER_CONTROL_2_ON1BRSTEN;
+
+		err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD1,
+					  button_irq, "b1on", priv);
+		if (err) {
+			dev_dbg(&pdev->dev, "Can't request irq\n");
+			goto free_priv;
+		}
+	}
+
+	if (pdata->b2on_flags & MC13783_BUTTON_ENABLE) {
+		priv->keymap[1] = pdata->b2on_key;
+		if (pdata->b2on_key != KEY_RESERVED)
+			__set_bit(pdata->b2on_key, pwr->keybit);
+
+		if (pdata->b2on_flags & MC13783_BUTTON_POL_INVERT)
+			priv->flags |= MC13783_PWRB_B2_POL_INVERT;
+
+		if (pdata->b2on_flags & MC13783_BUTTON_RESET_EN)
+			reg |= MC13783_POWER_CONTROL_2_ON2BRSTEN;
+
+		err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD2,
+					  button_irq, "b2on", priv);
+		if (err) {
+			dev_dbg(&pdev->dev, "Can't request irq\n");
+			goto free_irq_b1;
+		}
+	}
+
+	if (pdata->b3on_flags & MC13783_BUTTON_ENABLE) {
+		priv->keymap[2] = pdata->b3on_key;
+		if (pdata->b3on_key != KEY_RESERVED)
+			__set_bit(pdata->b3on_key, pwr->keybit);
+
+		if (pdata->b3on_flags & MC13783_BUTTON_POL_INVERT)
+			priv->flags |= MC13783_PWRB_B3_POL_INVERT;
+
+		if (pdata->b3on_flags & MC13783_BUTTON_RESET_EN)
+			reg |= MC13783_POWER_CONTROL_2_ON3BRSTEN;
+
+		err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD3,
+					  button_irq, "b3on", priv);
+		if (err) {
+			dev_dbg(&pdev->dev, "Can't request irq: %d\n", err);
+			goto free_irq_b2;
+		}
+	}
+
+	mc13xxx_reg_rmw(mc13783, MC13783_REG_POWER_CONTROL_2, 0x3FE, reg);
+
+	mc13xxx_unlock(mc13783);
+
+	pwr->name = "mc13783_pwrbutton";
+	pwr->phys = "mc13783_pwrbutton/input0";
+	pwr->dev.parent = &pdev->dev;
+
+	pwr->keycode = priv->keymap;
+	pwr->keycodemax = ARRAY_SIZE(priv->keymap);
+	pwr->keycodesize = sizeof(priv->keymap[0]);
+	__set_bit(EV_KEY, pwr->evbit);
+
+	err = input_register_device(pwr);
+	if (err) {
+		dev_dbg(&pdev->dev, "Can't register power button: %d\n", err);
+		goto free_irq;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	return 0;
+
+free_irq:
+	mc13xxx_lock(mc13783);
+
+	if (pdata->b3on_flags & MC13783_BUTTON_ENABLE)
+		mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD3, priv);
+
+free_irq_b2:
+	if (pdata->b2on_flags & MC13783_BUTTON_ENABLE)
+		mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD2, priv);
+
+free_irq_b1:
+	if (pdata->b1on_flags & MC13783_BUTTON_ENABLE)
+		mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD1, priv);
+
+free_priv:
+	mc13xxx_unlock(mc13783);
+	kfree(priv);
+
+free_input_dev:
+	input_free_device(pwr);
+
+	return err;
+}
+
+static int __devexit mc13783_pwrbutton_remove(struct platform_device *pdev)
+{
+	struct mc13783_pwrb *priv = platform_get_drvdata(pdev);
+	const struct mc13xxx_buttons_platform_data *pdata;
+
+	pdata = dev_get_platdata(&pdev->dev);
+
+	mc13xxx_lock(priv->mc13783);
+
+	if (pdata->b3on_flags & MC13783_BUTTON_ENABLE)
+		mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD3, priv);
+	if (pdata->b2on_flags & MC13783_BUTTON_ENABLE)
+		mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD2, priv);
+	if (pdata->b1on_flags & MC13783_BUTTON_ENABLE)
+		mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD1, priv);
+
+	mc13xxx_unlock(priv->mc13783);
+
+	input_unregister_device(priv->pwr);
+	kfree(priv);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver mc13783_pwrbutton_driver = {
+	.probe		= mc13783_pwrbutton_probe,
+	.remove		= __devexit_p(mc13783_pwrbutton_remove),
+	.driver		= {
+		.name	= "mc13783-pwrbutton",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(mc13783_pwrbutton_driver);
+
+MODULE_ALIAS("platform:mc13783-pwrbutton");
+MODULE_DESCRIPTION("MC13783 Power Button");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Philippe Retornaz");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/Makefile b/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/Makefile
new file mode 100755
index 0000000..ed73e3a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/Makefile
@@ -0,0 +1,7 @@
+#

+# Makefile for the da217 drivers

+#

+

+#obj-$(CONFIG_GSENSOR_MIR3DA) += gsensor_mir3da.o

+obj-y += gsensor_mir3da.o

+gsensor_mir3da-objs := mir3da_cust.o mir3da_core.o 

diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_core.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_core.c
new file mode 100755
index 0000000..4e4a114
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_core.c
@@ -0,0 +1,1978 @@
+/* Core file for MiraMEMS 3-Axis Accelerometer's driver. 
+ *
+ * mir3da_core.c - Linux kernel modules for 3-Axis Accelerometer
+ *
+ * Copyright (C) 2011-2013 MiraMEMS Sensing Technology Co., Ltd.
+ *
+ * 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 "mir3da_core.h"
+#include "mir3da_cust.h"
+
+#define MIR3DA_REG_ADDR(REG)                ((REG)&0xFF)
+
+#define MIR3DA_OFFSET_THRESHOLD             20
+#define PEAK_LVL                            800                        
+#define STICK_LSB                           2000
+#define AIX_HISTORY_SIZE                    20
+
+typedef struct reg_obj_s {
+    
+    short               addr;
+    unsigned char       mask;
+    unsigned char       value;
+    
+} reg_obj_t;
+
+struct gsensor_data_fmt_s {
+
+    unsigned char       msbw;
+    unsigned char       lsbw;
+    unsigned char       endian;                         /* 0: little endian; 1: big endian */
+};
+
+struct gsensor_data_obj_s {
+
+#define MIR3DA_DATA_LEN         6
+    reg_obj_t                   data_sect[MIR3DA_DATA_LEN];
+    struct gsensor_data_fmt_s   data_fmt;
+};
+
+struct gsensor_obj_s {
+    
+    char                        asic[10];
+
+    reg_obj_t                   chip_id;
+    reg_obj_t                   mod_id;
+    reg_obj_t                   soft_reset;
+    reg_obj_t                   power;
+
+#define MIR3DA_INIT_SECT_LEN    11
+#define MIR3DA_OFF_SECT_LEN     MIR3DA_OFFSET_LEN
+#define MIR3DA_ODR_SECT_LEN     3
+
+    reg_obj_t                   init_sect[MIR3DA_INIT_SECT_LEN];
+    reg_obj_t                   offset_sect[MIR3DA_OFF_SECT_LEN];
+    reg_obj_t                   odr_sect[MIR3DA_ODR_SECT_LEN];  
+    
+    struct gsensor_data_obj_s   data;
+
+    int                         (*calibrate)(MIR_HANDLE handle, int z_dir);
+    int                         (*auto_calibrate)(MIR_HANDLE handle, int xyz[3]);
+    int                         (*int_ops)(MIR_HANDLE handle, mir_int_ops_t *ops);
+    int                         (*get_reg_data)(MIR_HANDLE handle, char *buf);
+};
+
+struct gsensor_drv_s {
+    
+    struct general_op_s         *method;
+
+    struct gsensor_obj_s        *obj;
+};
+
+typedef enum _asic_type{
+    ASIC_NONE,  
+    ASIC_2511,
+    ASIC_2512B,
+    ASIC_2513A,
+	ASIC_2516,    
+} asic_type;
+
+typedef enum _mems_type{
+    MEMS_NONE,  
+    MEMS_T4,
+    MEMS_T9,
+    MEMS_TV03,
+    MEMS_RTO3,
+    MEMS_GT2,
+    MEMS_GT3,
+} mems_type;
+
+typedef enum _package_type{
+    PACKAGE_NONE,   
+    PACKAGE_2X2_12PIN,
+    PACKAGE_3X3_10PIN,
+    PACKAGE_3X3_16PIN,
+} package_type;
+
+struct  chip_info_s{
+    unsigned char    reg_value;
+    package_type     package;
+    asic_type        asic;
+    mems_type        mems;
+};
+
+struct  chip_info_s gsensor_chip_info;
+
+static struct chip_info_s         mir3da_chip_info_list[]=
+{
+    {0x00,PACKAGE_2X2_12PIN,ASIC_2512B,MEMS_TV03},
+    {0x01,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T4},
+    {0x02,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T9},
+    {0x03,PACKAGE_3X3_10PIN,ASIC_2511,MEMS_T4},
+    {0x04,PACKAGE_3X3_10PIN,ASIC_2511,MEMS_T9},
+    {0x05,PACKAGE_3X3_10PIN,ASIC_2511,MEMS_T4},
+    {0x06,PACKAGE_3X3_10PIN,ASIC_2511,MEMS_T9},
+    {0x07,PACKAGE_3X3_16PIN,ASIC_2511,MEMS_T4},
+    {0x08,PACKAGE_3X3_16PIN,ASIC_2511,MEMS_T9},
+    {0x09,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T4},
+    {0x0c,PACKAGE_2X2_12PIN,ASIC_2512B,MEMS_T9},
+    {0x33,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T9},
+    {0x34,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T9},
+    {0x35,PACKAGE_2X2_12PIN,ASIC_2511,MEMS_T9},
+};
+
+#define MIR3DA_NSA_INIT_SECTION                         { NSA_REG_G_RANGE,              0x03,   0x00    },                                  \
+                                                        { NSA_REG_POWERMODE_BW,         0xFF,   0x1e    },                                  \
+                                                        { NSA_REG_ODR_AXIS_DISABLE,     0xFF,   0x07    },                                  \
+                                                        { NSA_REG_INTERRUPT_SETTINGS2,  0xFF,   0x00    },                                  \
+                                                        { NSA_REG_INTERRUPT_MAPPING2,   0xFF,   0x00    },                                  \
+                                                        { NSA_REG_ENGINEERING_MODE,     0xFF,   0x83    },                                  \
+                                                        { NSA_REG_ENGINEERING_MODE,     0xFF,   0x69    },                                  \
+                                                        { NSA_REG_ENGINEERING_MODE,     0xFF,   0xBD    },                                  \
+                                                        { NSA_REG_INT_PIN_CONFIG,       0x0F,   0x05    },                                  \
+                                                        { -1,                           0x00,   0x00    },                                  \
+                                                        { -1,                           0x00,   0x00    },                                  \
+                                                        
+                                                                                                 
+#define MIR3DA_NSA_OFFSET_SECTION                       { NSA_REG_COARSE_OFFSET_TRIM_X, 0xFF,   0x00    },                                  \
+                                                        { NSA_REG_COARSE_OFFSET_TRIM_Y, 0xFF,   0x00    },                                  \
+                                                        { NSA_REG_COARSE_OFFSET_TRIM_Z, 0xFF,   0x00    },                                  \
+                                                        { NSA_REG_FINE_OFFSET_TRIM_X,   0xFF,   0x00    },                                  \
+                                                        { NSA_REG_FINE_OFFSET_TRIM_Y,   0xFF,   0x00    },                                  \
+                                                        { NSA_REG_FINE_OFFSET_TRIM_Z,   0xFF,   0x00    },                                  \
+                                                        { NSA_REG_CUSTOM_OFFSET_X,      0xFF,   0x00    },                                  \
+                                                        { NSA_REG_CUSTOM_OFFSET_Y,      0xFF,   0x00    },                                  \
+                                                        { NSA_REG_CUSTOM_OFFSET_Z,      0xFF,   0x00    },                                  \
+
+#define MIR3DA_NSA_ODR_SECTION                          { NSA_REG_ODR_AXIS_DISABLE,     0x0F,   0x06    },                                  \
+                                                        { NSA_REG_ODR_AXIS_DISABLE,     0x0F,   0x07    },                                  \
+                                                        { NSA_REG_ODR_AXIS_DISABLE,     0x0F,   0x08    },                                  \
+
+
+#define MIR3DA_NSA_DATA_SECTION                       { { NSA_REG_ACC_X_LSB,            0xFF,   0x00    },                                  \
+                                                        { NSA_REG_ACC_X_MSB,            0xFF,   0x00    },                                  \
+                                                        { NSA_REG_ACC_Y_LSB,            0xFF,   0x00    },                                  \
+                                                        { NSA_REG_ACC_Y_MSB,            0xFF,   0x00    },                                  \
+                                                        { NSA_REG_ACC_Z_LSB,            0xFF,   0x00    },                                  \
+                                                        { NSA_REG_ACC_Z_MSB,            0xFF,   0x00    } },                                \
+                                                        { 8,                            4,      0       }
+                                         
+int mir3da_irq_init(MIR_HANDLE handle);                                         
+static int NSA_NTO_calibrate(MIR_HANDLE handle, int z_dir);
+static int NSA_NTO_auto_calibrate(MIR_HANDLE handle, int xyz[3]);
+#if MIR3DA_AUTO_CALIBRATE
+static int mir3da_auto_calibrate(MIR_HANDLE handle, int x, int y, int z);
+#endif /* !MIR3DA_AUTO_CALIBRATE */
+static int NSA_interrupt_ops(MIR_HANDLE handle, mir_int_ops_t *ops);
+static int NSA_get_reg_data(MIR_HANDLE handle, char *buf);
+
+#define MIR_NSA_NTO                     { "NSA_NTO",    { NSA_REG_WHO_AM_I,             0xFF,   0x13    },                                  \
+                                                        { NSA_REG_FIFO_CTRL,            0xFF,   0x00    },                                  \
+                                                        { NSA_REG_SPI_I2C,              0x24,   0x24    },                                  \
+                                                        { NSA_REG_POWERMODE_BW,         0x80,   0x80    },                                  \
+                                                        { MIR3DA_NSA_INIT_SECTION                       },                                  \
+                                                        { MIR3DA_NSA_OFFSET_SECTION                     },                                  \
+                                                        { MIR3DA_NSA_ODR_SECTION                        },                                  \
+                                                        { MIR3DA_NSA_DATA_SECTION                       },                                  \
+                                                          NSA_NTO_calibrate                              ,                                  \
+                                                          NSA_NTO_auto_calibrate                         ,                                  \
+                                                          NSA_interrupt_ops                              ,                                  \
+                                                          NSA_get_reg_data                               ,                                  \
+                                        }
+/**************************************************************** COMMON ***************************************************************************/
+#define MIR3DA_GSENSOR_SCHEME           MIR3DA_SUPPORT_CHIP_LIST
+
+#if YZ_CROSS_TALK_ENABLE 
+static short yzcross;
+#endif
+
+/* this level can be modified while runtime through system attribute */
+int                                 Log_level = DEBUG_ERR|DEBUG_ASSERT|DEBUG_MSG|DEBUG_FUNC|DEBUG_DATA;
+int                                gsensor_mod = -1;        /* Initial value */
+int                                gsensor_type = -1;        /* Initial value */
+static struct gsensor_obj_s         mir3da_gsensor[] = { MIR3DA_GSENSOR_SCHEME };
+struct gsensor_drv_s                mir3da_gsensor_drv;
+int									is_da217 = -1;
+
+#define MI_DATA(format, ...)            if(DEBUG_DATA&Log_level){mir3da_gsensor_drv.method->myprintf(MI_TAG format "\n", ## __VA_ARGS__);}
+#define MI_MSG(format, ...)             if(DEBUG_MSG&Log_level){mir3da_gsensor_drv.method->myprintf(MI_TAG format "\n", ## __VA_ARGS__);}
+#define MI_ERR(format, ...)             if(DEBUG_ERR&Log_level){mir3da_gsensor_drv.method->myprintf(MI_TAG format "\n", ## __VA_ARGS__);}
+#define MI_FUN                          if(DEBUG_FUNC&Log_level){mir3da_gsensor_drv.method->myprintf(MI_TAG "%s is called, line: %d\n", __FUNCTION__,__LINE__);}
+#define MI_ASSERT(expr)                 \
+    if (!(expr)) {\
+        mir3da_gsensor_drv.method->myprintf("Assertion failed! %s,%d,%s,%s\n",\
+            __FILE__, __LINE__, __func__, #expr);\
+    }
+
+#ifndef MTK_ANDROID_M
+#define abs(x) ({ long __x = (x); (__x < 0) ? -__x : __x; })
+#endif 
+
+#if FILTER_AVERAGE_ENHANCE
+typedef struct FilterAverageContextTag{
+    int sample_l;
+    int sample_h;
+    int filter_param_l;
+    int filter_param_h;
+    int filter_threhold;
+
+    int refN_l;
+    int refN_h;
+        
+} FilterAverageContext;
+
+typedef struct mir3da_core_ctx_s{
+    struct mir3da_filter_param_s    filter_param;
+    FilterAverageContext            tFac[3];   
+} mir3da_core_ctx;
+
+static mir3da_core_ctx       core_ctx;
+#endif 
+
+#if MIR3DA_SENS_TEMP_SOLUTION
+static int bSensZoom = 0;
+#endif
+
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+static int is_cali = 0;
+char bLoad = FILE_CHECKING;
+static char readOffsetCnt=0;
+static char readsubfileCnt=0;
+static unsigned char original_offset[9];
+static int mir3da_write_offset_to_file(unsigned char* offset);
+static int mir3da_read_offset_from_file(unsigned char* offset);
+void manual_load_cali_file(MIR_HANDLE handle);
+#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */
+
+#if MIR3DA_STK_TEMP_SOLUTION
+static short aixHistort[AIX_HISTORY_SIZE*3] = {0};
+static short aixHistoryIndex = 0;
+char bxstk = 0;
+char bystk = 0;
+char bzstk = 0;
+
+static void addAixHistory(short x,short y,short z){
+    aixHistort[aixHistoryIndex++] = x;
+    aixHistort[aixHistoryIndex++] = y;
+    aixHistort[aixHistoryIndex++] = z;    
+    aixHistoryIndex = (aixHistoryIndex)%(AIX_HISTORY_SIZE*3);
+}
+
+static char isXStick(void){
+	int i=0,j=0,temp=0;
+	for (i = 0; i < AIX_HISTORY_SIZE; i++){
+	    if ((abs(aixHistort[i*3]) < STICK_LSB)&&(aixHistort[i*3] != 0)){
+	        break;
+	    }
+	}
+
+       for(j = 0; j< AIX_HISTORY_SIZE; j++){
+		temp |= aixHistort[j*3];
+       }
+
+       if(0 == temp)
+		return 1;
+  
+ 	return i == AIX_HISTORY_SIZE; 
+}
+
+static char isYStick(void){
+	int i=0,j=0,temp=0;
+	for (i = 0; i < AIX_HISTORY_SIZE; i++){
+	    if ((abs(aixHistort[i*3+1]) < STICK_LSB)&&(aixHistort[i*3+1] != 0)){
+	        break;
+	    }
+	}
+
+       for(j = 0; j < AIX_HISTORY_SIZE; j++){
+		temp |= aixHistort[j*3+1];
+       }
+
+       if(0 == temp)
+		return 1;	
+	   
+	return i == AIX_HISTORY_SIZE;
+}
+
+static char isZStick(void){
+	int i=0,j=0,temp=0;
+	for (i = 0; i < AIX_HISTORY_SIZE; i++){
+	    if ((abs(aixHistort[i*3+2]) < STICK_LSB)&&(aixHistort[i*3+2] != 0)){
+	        break;
+	    }
+	}
+
+       for(j = 0; j < AIX_HISTORY_SIZE; j++){
+		temp |= aixHistort[j*3+2];
+       }
+
+       if(0 == temp)
+		return 1;
+
+	return i == AIX_HISTORY_SIZE; 
+}
+
+ int squareRoot(int val){
+    int r = 0;
+    int shift;
+    
+    if (val < 0){
+        return 0;
+    }
+    
+    for(shift=0;shift<32;shift+=2)
+    { 
+        int x=0x40000000l >> shift;
+        if(x + r <= val)
+        { 
+            val -= x + r;
+            r = (r >> 1) | x;
+        } else{ 
+            r = r >> 1;
+        }
+    }
+    
+    return r;
+}
+#endif /* ! MIR3DA_STK_TEMP_SOLUTION */
+
+#if FILTER_AVERAGE_ENHANCE
+static short filter_average(short preAve, short sample, int paramN, int* refNum)
+{
+ #if FILTER_AVERAGE_EX
+    if( abs(sample-preAve) > PEAK_LVL  && *refNum < 3  ){ 
+         MI_DATA("Hit, sample = %d, preAve = %d, refN =%d\n", sample, preAve, *refNum);
+         sample = preAve;
+         (*refNum) ++;
+    }else{
+         if (*refNum == 3){
+                preAve = sample;
+         }
+         
+         *refNum  = 0;
+    }
+#endif
+
+    return preAve + (sample - preAve)/paramN;
+}
+
+static int filter_average_enhance(FilterAverageContext* fac, short sample)
+{
+    if (fac == 0){
+        MI_ERR("0 parameter fac");
+        return 0;
+    }
+
+    if (fac->filter_param_l == fac->filter_param_h){
+        fac->sample_l = fac->sample_h = filter_average(fac->sample_l, sample, fac->filter_param_l, &fac->refN_l);
+    }else{
+        fac->sample_l = filter_average(fac->sample_l, sample, fac->filter_param_l,  &fac->refN_l);
+        fac->sample_h= filter_average(fac->sample_h, sample, fac->filter_param_h, &fac->refN_h);  
+        if (abs(fac->sample_l- fac->sample_h) > fac->filter_threhold){
+            MI_DATA("adjust, fac->sample_l = %d, fac->sample_h = %d\n", fac->sample_l, fac->sample_h); 
+            fac->sample_h = fac->sample_l;            
+        }
+     }
+
+    return fac->sample_h;    
+}
+#endif /* ! FILTER_AVERAGE_ENHANCE */
+
+int mir3da_register_read(MIR_HANDLE handle, short addr, unsigned char *data)
+{
+    int     res = 0;
+
+    res = mir3da_gsensor_drv.method->smi.read(handle, MIR3DA_REG_ADDR(addr), data);
+	
+    return res;
+}
+
+int mir3da_register_read_continuously(MIR_HANDLE handle, short addr, unsigned char count, unsigned char *data)
+{
+    int     res = 0;
+
+    res = (count==mir3da_gsensor_drv.method->smi.read_block(handle, MIR3DA_REG_ADDR(addr), count, data)) ? 0 : 1;
+
+    return res;
+}
+
+int mir3da_register_write(MIR_HANDLE handle, short addr, unsigned char data)
+{
+    int     res = 0;
+	
+    res = mir3da_gsensor_drv.method->smi.write(handle, MIR3DA_REG_ADDR(addr), data);
+
+    return res;
+}
+
+int mir3da_register_mask_write(MIR_HANDLE handle, short addr, unsigned char mask, unsigned char data)
+{
+    int     res = 0;
+    unsigned char      tmp_data;
+
+    res = mir3da_register_read(handle, addr, &tmp_data);
+    if(res) {
+        return res;
+    }
+
+    tmp_data &= ~mask; 
+    tmp_data |= data & mask;
+    res = mir3da_register_write(handle, addr, tmp_data);
+
+    return res;
+}
+
+static int mir3da_read_raw_data(MIR_HANDLE handle, short *x, short *y, short *z)
+{
+    unsigned char    tmp_data[6] = {0};
+
+    if (mir3da_register_read_continuously(handle, mir3da_gsensor_drv.obj[gsensor_mod].data.data_sect[0].addr, 6, tmp_data) != 0) {
+        MI_ERR("i2c block read failed\n");
+        return -1;
+    }
+
+    *x = ((short)(tmp_data[1] << mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.msbw | tmp_data[0]))>> (8-mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.lsbw);
+    *y = ((short)(tmp_data[3] << mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.msbw | tmp_data[2]))>> (8-mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.lsbw);
+    *z = ((short)(tmp_data[5] << mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.msbw | tmp_data[4]))>> (8-mir3da_gsensor_drv.obj[gsensor_mod].data.data_fmt.lsbw);
+
+    //MI_DATA("mir3da_raw: x=%d, y=%d, z=%d",  *x, *y, *z);
+    
+#if MIR3DA_SENS_TEMP_SOLUTION
+    if (bSensZoom == 1){
+        *z = (*z )*5/4;
+        MI_DATA("SensZoom take effect, Zoomed Z = %d", *z);
+    }
+#endif
+
+#if YZ_CROSS_TALK_ENABLE 
+    if(yzcross)
+      *y=*y-(*z)*yzcross/100;
+#endif
+    
+    return 0;
+}
+
+static int remap[8][4] = {{0,0,0,0},
+                    {0,1,0,1},
+                    {1,1,0,0},
+                    {1,0,0,1},
+                    {1,0,1,0},
+                    {0,0,1,1},
+                    {0,1,1,0},
+                    {1,1,1,1}};
+                    
+int mir3da_direction_remap(short *x,short *y, short *z, int direction)
+{
+    short temp = 0;
+    
+    *x = *x - ((*x) * remap[direction][0]*2);
+    *y = *y - ((*y) * remap[direction][1]*2);
+    *z = *z - ((*z) * remap[direction][2]*2);
+    
+    if(remap[direction][3])
+    {
+        temp = *x;
+        *x = *y;
+        *y = temp;
+    }
+    
+    if(remap[direction][2])
+        return -1;
+    
+    return 1;
+}
+
+int mir3da_read_data(MIR_HANDLE handle, short *x, short *y, short *z)
+{
+    int    rst = 0;
+	static int resume_times=0;
+
+#if MIR3DA_SUPPORT_MULTI_LAYOUT
+    short temp =0;
+#endif  
+
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+    if(is_cali){
+        *x = *y = *z = 0;
+        return 0;
+    }
+
+    manual_load_cali_file(handle);
+#endif
+
+    rst = mir3da_read_raw_data(handle, x, y, z);
+    if (rst != 0){
+        MI_ERR("mir3da_read_raw_data failed, rst = %d", rst);
+        return rst;
+    }
+
+#if MIR3DA_AUTO_CALIBRATE
+#if MIR3DA_SUPPORT_FAST_AUTO_CALI       
+    if((mir3da_gsensor_drv.method->support_fast_auto_cali() &&(bLoad !=FILE_EXIST))||(bLoad ==FILE_NO_EXIST))
+#else
+    if(bLoad ==FILE_NO_EXIST)
+#endif  
+    {   
+       mir3da_auto_calibrate(handle, *x, *y, *z);
+    }
+#endif
+    
+#if MIR3DA_STK_TEMP_SOLUTION   
+    addAixHistory(*x,*y,*z);
+
+    bxstk = isXStick();
+    bystk = isYStick();
+    bzstk = isZStick();
+
+    if((gsensor_chip_info.mems==MEMS_TV03 ||gsensor_chip_info.mems==MEMS_RTO3)
+   	&&(gsensor_chip_info.reg_value != 0x4B)
+   	&&(gsensor_chip_info.reg_value != 0x8C)
+   	&&(gsensor_chip_info.reg_value != 0xCA))
+    {
+	   if ((bxstk + bystk+ bzstk) >0){
+		   if(resume_times<20){
+			   resume_times++;
+			   MI_DATA("IN USE STK & resume!!\n");
+			   mir3da_chip_resume(handle);
+		   }
+	   }else
+		   resume_times = 0;
+    }
+    else
+    {
+	    if ((bxstk + bystk+ bzstk) < 2){
+	        if(bxstk)
+	        *x = squareRoot(1024*1024 - (*y)*(*y) - (*z)*(*z));
+	    if(bystk)
+	        *y = squareRoot(1024*1024 - (*x)*(*x) - (*z)*(*z));
+	    if(bzstk)
+	        *z = squareRoot(1024*1024 - (*x)*(*x) - (*y)*(*y));
+	    }else{
+	        // MI_ERR( "CHIP ERR !MORE STK!\n"); 
+	        return 0;
+	    }
+    }
+#endif
+
+
+#if FILTER_AVERAGE_ENHANCE
+    *x = filter_average_enhance(&core_ctx.tFac[0], *x);
+    *y = filter_average_enhance(&core_ctx.tFac[1], *y);
+    *z = filter_average_enhance(&core_ctx.tFac[2], *z);
+    MI_DATA("mir3da_filt: x=%d, y=%d, z=%d",  *x, *y, *z);
+#endif
+
+
+#if MIR3DA_SUPPORT_MULTI_LAYOUT
+    if(gsensor_chip_info.package ==PACKAGE_2X2_12PIN ){
+        *x =*x;  
+        *y =*z;
+        *z =*z;
+    }else if(gsensor_chip_info.package ==PACKAGE_3X3_10PIN){
+        temp = *x;
+        *x = *y;
+        *y = temp;
+        *z =*z; 
+    }else if(gsensor_chip_info.package ==PACKAGE_3X3_16PIN){
+        temp = -1*(*x);
+        *x = -1*(*y);
+        *y = temp;
+        *z =*z; 
+    }
+#endif
+
+	if((gsensor_chip_info.reg_value == 0x4B)
+		||(gsensor_chip_info.reg_value == 0x8C)
+   		||(gsensor_chip_info.reg_value == 0xCA)
+   		||(gsensor_chip_info.mems == MEMS_GT2))
+	{
+		*z = 0;
+#if MIR3DA_STK_TEMP_SOLUTION   
+		bzstk = 1;
+#endif
+
+	}
+
+    return 0;
+}
+
+unsigned short last_step_counter = 0;
+unsigned int total_step_counter = 0;
+int mir3da_read_step_counter(MIR_HANDLE handle, unsigned int *cnt)
+{
+    int    rst = 0;
+    unsigned char    tmp_data[2] = {0};
+	unsigned short step_cnt;
+
+    if (mir3da_register_read_continuously(handle, NSA_REG_STEPS_MSB, 2, tmp_data) != 0) {
+        MI_ERR("i2c block read failed\n");
+        return -1;
+    }
+	
+	/* maybe circle from 0 after long times */
+	step_cnt = (unsigned short)((tmp_data[0] << 8) | tmp_data[1]);
+#if 0
+	if(step_cnt < last_step_counter)
+		total_step_counter += (0xffff + step_cnt - last_step_counter);
+	else
+		total_step_counter += (step_cnt - last_step_counter); 
+
+	last_step_counter = step_cnt;
+
+	*cnt = total_step_counter/2;
+
+	/* ????? we may create a timer for wakeup, 
+	        maybe create alarm  by app */
+#else
+	*cnt = step_cnt/2;
+#endif
+    return 0;
+}
+
+int mir3da_reset_step_counter(MIR_HANDLE handle)
+{
+	int res = 0;
+    res = mir3da_register_write(handle, NSA_REG_RESET_STEP, 0x80);
+
+    return res;
+}
+
+/* 0 - idle  1 - walk  2 - run */
+int mir3da_read_step_status(MIR_HANDLE handle)
+{
+    int    rst = 0;
+    unsigned char    tmp_data = 0;
+
+    if (mir3da_register_read(handle, NSA_REG_ORIENT_STATUS, &tmp_data) != 0) {
+        MI_ERR("i2c read failed\n");
+        return -1;
+    }
+	
+	/* maybe circle from 0 after long times */
+	tmp_data &= 0x3;
+	if(tmp_data == 3)
+    	return 0;
+	else
+		return (int)tmp_data;
+}
+
+int cycle_read_xyz(MIR_HANDLE handle, int* x, int* y, int* z, int ncycle)
+{
+    unsigned int j = 0;
+    short raw_x,raw_y,raw_z;    
+	int ret = 0;
+    *x = *y = *z = 0;
+
+    for (j = 0; j < ncycle; j++)
+    {
+        raw_x = raw_y = raw_z = 0;
+        ret = mir3da_read_raw_data (handle, &raw_x, &raw_y, &raw_z);
+		if (ret < 0)
+			return -1;
+        (*x) += raw_x;
+        (*y) += raw_y;
+        (*z) += raw_z;
+
+        mir3da_gsensor_drv.method->msdelay(5);
+    }
+    
+    (*x) /= ncycle;
+    (*y) /= ncycle;
+    (*z) /= ncycle;
+    
+    return 0;
+}
+
+int mir3da_read_offset(MIR_HANDLE handle, unsigned char* offset)
+{
+    int     i, res = 0;
+    
+    for(i=0;i<MIR3DA_OFF_SECT_LEN;i++) {
+        if( mir3da_gsensor_drv.obj[gsensor_mod].offset_sect[i].addr < 0 ) {
+            break;
+        }
+
+        res = mir3da_register_read(handle, mir3da_gsensor_drv.obj[gsensor_mod].offset_sect[i].addr, &offset[i]);
+        if(res != 0) {
+            return res;
+        } 
+    }
+    
+    return res;
+}
+
+int mir3da_write_offset(MIR_HANDLE handle, unsigned char* offset)
+{
+    int     i, res = 0;
+
+    for(i=0;i<MIR3DA_OFF_SECT_LEN;i++) {
+        if( mir3da_gsensor_drv.obj[gsensor_mod].offset_sect[i].addr < 0 ) {
+            break;
+        }
+
+        res = mir3da_register_write(handle, mir3da_gsensor_drv.obj[gsensor_mod].offset_sect[i].addr, offset[i]);
+        if(res != 0) {
+            return res;
+        } 
+    }
+
+    return res;
+}
+
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+static int mir3da_write_offset_to_file(unsigned char* offset)
+{
+    int     ret = 0;
+    
+    if(0 == mir3da_gsensor_drv.method->data_save)
+        return 0;
+        
+    ret = mir3da_gsensor_drv.method->data_save(offset);
+    
+    MI_MSG("====sensor_sync_write, offset = 0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x", offset[0],offset[1],offset[2],offset[3],offset[4],offset[5],offset[6],offset[7],offset[8]);
+    
+    return ret;
+}
+
+static int mir3da_read_offset_from_file(unsigned char* offset)
+{
+    int     ret = 0;
+    int     i=0,sum=0;
+
+    if(0 == mir3da_gsensor_drv.method->data_get)
+        return -1;
+    
+    ret = mir3da_gsensor_drv.method->data_get(offset);
+
+    for(i=0;i<MIR3DA_OFF_SECT_LEN;i++){
+        sum += offset[i];
+    }
+
+    if(sum==0)
+       return -1;   
+
+    MI_MSG("====sensor_sync_read, offset = 0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x", offset[0],offset[1],offset[2],offset[3],offset[4],offset[5],offset[6],offset[7],offset[8]);
+    
+    return ret;
+}
+
+void manual_load_cali_file(MIR_HANDLE handle)
+{ 
+	unsigned char  offset[MIR3DA_OFFSET_LEN] = {0};
+	
+	if (bLoad ==FILE_CHECKING){
+		
+		readOffsetCnt++;	
+		
+ 		if(readOffsetCnt%8 == 0){
+            
+			readOffsetCnt =0;
+
+			MI_ERR("====444 manual_load_cali_file(), bLoad = %d, readOffsetCnt=%d.\n", bLoad, readOffsetCnt); 
+
+			if(mir3da_gsensor_drv.method->data_check()){
+
+				readsubfileCnt++;
+
+				if(!mir3da_read_offset_from_file(offset)) {
+					MI_ERR("========= FILE EXIST & WRITE OFFSET!");
+					mir3da_write_offset(handle, offset);
+					bLoad = FILE_EXIST;
+				}else if(5 == readsubfileCnt){
+					MI_ERR("========= NO FILE EXIST!");					
+					bLoad = FILE_NO_EXIST;	
+				}
+			}else{
+				MI_ERR("========= FILE CHECKING....");				
+				bLoad = FILE_CHECKING;
+				readsubfileCnt =0;
+			}
+	     }
+    }
+}
+
+static void mir3da_cali_off_to_lsb(int off, int *coarse, int coarse_step, int *fine, int fine_step)
+{
+    *coarse = off/coarse_step;
+    *fine = 100*(off-(*coarse)*coarse_step)/fine_step;
+    
+    MI_MSG("off = %d; delta_coarse = %d; delta_fine = %d", off, *coarse, *fine);
+}
+
+#if MIR3DA_AUTO_CALIBRATE
+static int NSA_once_calibrate(MIR_HANDLE handle, int coarse_step[3], int fine_step[3], int xyz[3])
+{
+    int     coarse[3] = {0};
+    int     coarse_delta[3] = {0};
+    int     fine[3] = {0};
+    int     fine_delta[3] = {0};
+    int     target[3] = {0};
+    int     i;
+    unsigned char   offset_data[9] = {0};
+
+    if(mir3da_read_offset(handle, offset_data)){
+        MI_ERR("Get old offset failed !");
+        return -1;
+    }
+    coarse[0] = offset_data[0] & 0x3f;
+    coarse[1] = offset_data[1] & 0x3f;
+    coarse[2] = offset_data[2] & 0x3f;
+    fine[0] = (((int)offset_data[0] << 2) & 0x300)|offset_data[3];
+    fine[1] = (((int)offset_data[1] << 2) & 0x300)|offset_data[4];
+    fine[2] = (((int)offset_data[2] << 2) & 0x300)|offset_data[5];
+    
+    MI_MSG("Old coarse_x = %d; coarse_y = %d; coarse_z = %d; fine_x = %d; fine_y = %d; fine_z = %d;", coarse[0], coarse[1], coarse[2], fine[0], fine[1], fine[2]);
+        
+    /* 0 means auto detect z direction assume z axis is verticle */
+    if ((abs(target[0]) + abs(target[1]) + abs(target[2])) == 0){
+        target[2] = (xyz[2] > 0) ? 1024 : (-1024);
+    }
+    
+    for(i = 0;i < 3; i++){
+        coarse_step[i] *= coarse[i] >= 32 ? (-1) : 1;
+        mir3da_cali_off_to_lsb((xyz[i]-target[i]), &coarse_delta[i], coarse_step[i], &fine_delta[i], fine_step[i]);
+        
+        coarse[i] += coarse_delta[i];
+        fine[i] += fine_delta[i];
+        offset_data[i] = coarse[i]|((fine[i]>>2)&0xc0);
+        offset_data[i+3] = fine[i]&0xFF;
+    }
+    
+    if(mir3da_write_offset(handle, offset_data)){
+        MI_ERR("Update offset failed !");
+        return -1;
+    }
+    /* Discard unstable data after offset register changed */
+    cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5);
+    if(cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 10)){
+        return -1;
+    }
+    MI_MSG("---calibrate_Done, x = %d, y = %d, z = %d, coarse_x = %d, coarse_y = %d, coarse_z = %d, fine_x = %d, fine_y = %d, fine_z = %d", xyz[0], xyz[1], xyz[2], coarse[0], coarse[1], coarse[2], fine[0], fine[1], fine[2]);
+    
+    return mir3da_write_offset_to_file(offset_data);
+}
+#endif /* !MIR3DA_AUTO_CALIBRATE */
+
+static int NSA_calibrate(MIR_HANDLE handle, int coarse_step[3], int fine_step[3], int fine_max, int target[3])
+{
+    int             i = 0, j = 0;
+    unsigned char   ncycle = 20;
+    unsigned char   nLoop = 20;
+    unsigned char   offset_data[9] = {0};
+    unsigned char   fine_ok_map = 0;
+    
+    int             xyz[3] = {0};  
+    int             coarse[3] = {0};
+    int             coarse_delta[3] = {0};
+    int             fine[3] = {0};
+    int             fine_delta[3] = {0};
+    
+    if( (abs(target[0]) + abs(target[1]) + abs(target[2])) != 0 && (abs(target[0]) + abs(target[1]) + abs(target[2])) != 1024 ) {
+        MI_ERR("Invalid argument !");
+        return -1;
+    }
+        
+    /* 0 means auto detect z direction assume z axis is verticle */
+    if ((abs(target[0]) + abs(target[1]) + abs(target[2])) == 0){
+       if(cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5)){
+            MI_ERR("check z direction failed\n");
+            return -1;
+       }
+       target[2] = (xyz[2] > 0) ? 1024 : (-1024);
+    }
+
+    MI_MSG("---Start Calibrate, trim target %d, %d, %d---\n", target[0], target[1], target[2]);
+
+    // Stage1: Coarse tune once
+    MI_MSG("---Stage1, coarse tune---");            
+    // change to 16G mode
+    if(mir3da_register_mask_write(handle, NSA_REG_G_RANGE, 0x03, 3)){
+        MI_ERR("i2c mask write failed !\n");
+        return -1;
+    }
+
+    /* reset coarse offset register */
+    mir3da_write_offset(handle, offset_data);  
+    /* Discard unstable data after offset register changed */
+    cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5);
+  
+    if( cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], ncycle) ){
+        goto EXIT_16G_MOD;
+    }
+
+    for(i = 0; i < 3; i++){
+        /* check rule */
+        xyz[i] *= 8;
+
+        coarse[i] = ((xyz[i]-target[i]) > 0) ? 0 : 32;
+
+        MI_MSG("xyz[%d] = %d, coarse[%d] = 0x%x", i, xyz[i], i, coarse[i]);
+        
+        coarse_step[i] *= coarse[i] >= 32 ? (-1) : 1;
+        mir3da_cali_off_to_lsb((xyz[i]-target[i]), &coarse_delta[i], coarse_step[i], &fine_delta[i], fine_step[i]);
+
+        coarse[i] += coarse_delta[i];
+        fine[i] += fine_delta[i];
+        mir3da_register_mask_write(handle, NSA_REG_COARSE_OFFSET_TRIM_X+i, 0x3f, (unsigned char)coarse[i]);
+    }
+    
+    /* Discard unstable data after offset register changed */
+    cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5);
+    if(cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5)){
+        return -1;
+    }
+    for(i = 0; i < 3; i++){   
+        fine[i] += (xyz[i] > 0) ? 0 : fine_max;
+        mir3da_register_write(handle, NSA_REG_FINE_OFFSET_TRIM_X+i, (unsigned char)(fine[i]&0xff));
+        mir3da_register_mask_write(handle, NSA_REG_COARSE_OFFSET_TRIM_X+i, 0xc0, (unsigned char)(0xc0&(fine[i]>>2)));
+    }
+
+EXIT_16G_MOD:
+    // change back to 2G mode
+    if(mir3da_register_mask_write(handle, NSA_REG_G_RANGE, 0x03, 0)){
+        MI_ERR("i2c mask write failed !\n");
+        return -1;
+    }
+    /* Discard unstable data after offset register changed */
+    cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5);
+    if(cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], ncycle)){
+        return -1;
+    }
+    MI_MSG("---Stage1, coarse tune done: x = %d, y = %d, z = %d, coarse_x = %d, coarse_y = %d, coarse_z = %d, fine_x = %d, fine_y = %d, fine_z = %d", xyz[0], xyz[1], xyz[2], coarse[0], coarse[1], coarse[2], fine[0], fine[1], fine[2]);
+    
+    // Stage2: Fine tune
+    MI_MSG("---Stage2, Fine tune---");
+    for (i = 0; i < nLoop; i++){
+    
+        if( 0x07==(fine_ok_map & 0x07) ){
+            break;
+        }
+        /* Discard unstable data after offset register changed */
+        cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 5);
+        MI_MSG("---Stage2, Fine loop %d", i);
+        if(cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], ncycle)){
+            return -1;
+        }
+        
+        for(j = 0; j < 3; j++){
+            MI_MSG("xyz[%d] = %d, caorse[%d] = 0x%x, fine[%d] = 0x%x", j, xyz[j], j, coarse[j], j, fine[j]);
+            if( abs(xyz[j]-target[j]) < MIR3DA_OFFSET_THRESHOLD ){
+                fine_ok_map |= (1<<j);
+                offset_data[j] = coarse[j]|((fine[j]>>2)&0xc0);
+                offset_data[j+3] = fine[j];
+                continue;        
+            }
+            mir3da_cali_off_to_lsb((xyz[j]-target[j]), &coarse_delta[j], coarse_step[j], &fine_delta[j], fine_step[j]);
+
+            coarse[j] += coarse_delta[j];
+            fine[j] += fine_delta[j];
+            mir3da_register_write(handle, NSA_REG_FINE_OFFSET_TRIM_X+j, (unsigned char)(fine[j]&0xff));
+            mir3da_register_mask_write(handle, NSA_REG_COARSE_OFFSET_TRIM_X+j, 0xFF, (unsigned char)(0xc0&(fine[j]>>2))|coarse[j]);
+        }                       
+    }
+    MI_MSG("---Stage2, Fine tune done: x = %d, y = %d, z = %d, coarse_x = %d, coarse_y = %d, coarse_z = %d, fine_x = %d, fine_y = %d, fine_z = %d", xyz[0], xyz[1], xyz[2], coarse[0], coarse[1], coarse[2], fine[0], fine[1], fine[2]);
+    
+    if( 0x07==(fine_ok_map & 0x07) ){
+        goto SUCCESS_EXIT;
+    }
+#if MIR3DA_STK_TEMP_SOLUTION
+    if( 0x03==(fine_ok_map & 0x07) ){
+        goto SUCCESS_EXIT;
+    }
+#endif
+    
+    MI_MSG("---calibrate Failed !---");
+    return -1;
+    
+SUCCESS_EXIT:
+    MI_MSG("---calibrate OK !---");
+    return mir3da_write_offset_to_file(offset_data);
+}
+
+static int NSA_NTO_cali_step_calc(MIR_HANDLE handle, int coarse[3], int x100_fine[3], int x100_cust[3])
+{
+    int                i;
+    unsigned int       total_gain[3] = {0}; 
+    unsigned char      coarse_gain = 0;
+    unsigned char      fine_gain[3] = {0};
+    unsigned int       const coarse_gain_map[] = {1000, 1125, 1250, 1375, 500, 625, 750, 875};   /* *1000  */
+    unsigned char      const fine_dig_gain_map[] = {1, 2, 4, 8};
+        
+    if(mir3da_register_read_continuously(handle, NSA_REG_SENSITIVITY_TRIM_X, 3, fine_gain) != 0){
+        MI_ERR("i2c block read failed\n");
+        return -1;
+    }
+
+    if(mir3da_register_read(handle, NSA_REG_SENS_COARSE_TRIM, &coarse_gain) != 0){
+        MI_ERR("i2c block read failed\n");
+        return -1;
+    }
+    
+    for(i = 0;i < 3;i++) {        
+        // *100*1000
+        total_gain[i] = ((1000 + (fine_gain[i]&0x1F)*1000/32)/15) * fine_dig_gain_map[((fine_gain[i]>>5)&0x03)] * coarse_gain_map[coarse_gain&0x07]; 
+        coarse[i] = (int)(total_gain[i] * 500 / 100000);
+        x100_fine[i] = (int)(total_gain[i] * 293 / 100000);
+        x100_cust[i] = (int)(total_gain[i] * 390 / 100000);
+    }
+    MI_MSG("coarse_step_x = %d, coarse_step_y = %d, coarse_step_z = %d\n", coarse[0], coarse[1], coarse[2]);
+    MI_MSG("fine_step_x = %d, fine_step_y = %d, fine_step_z = %d\n", x100_fine[0], x100_fine[1], x100_fine[2]);
+    MI_MSG("custom_step_x = %d, custom_step_y = %d, custom_step_z = %d\n", x100_cust[0], x100_cust[1], x100_cust[2]);
+    
+    return 0;    
+}
+#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */
+
+static int NSA_NTO_calibrate(MIR_HANDLE handle, int z_dir)
+{
+    int     result = 0;
+
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+        int     coarse_step[3] = {0};
+        int     fine_step[3] = {0};
+        int     custom_step[3] = {0};
+        int     target[3] = {0};
+
+   unsigned char     swap_plarity_old = 0;  
+   
+    /* compute step */
+    if( NSA_NTO_cali_step_calc(handle, coarse_step, fine_step, custom_step) ) {
+        MI_ERR("Compute step failed !");
+        return -1; 
+    }
+    target[2] = z_dir*1024;
+
+    // save swap/plarity old setting
+    if(mir3da_register_read(handle, NSA_REG_SWAP_POLARITY, &swap_plarity_old)){
+        MI_ERR("Get SWAP/PLARITY setting failed !");
+        return -1;
+    }
+
+	if((gsensor_chip_info.asic == ASIC_2512B)||(gsensor_chip_info.asic == ASIC_2513A)||(gsensor_chip_info.asic == ASIC_2516)){
+			coarse_step[2] = 2 *coarse_step[2];
+			target[2] = ((swap_plarity_old & (1<<1)) == 0) ? (-target[2]) :target[2];
+			if(mir3da_register_mask_write(handle, NSA_REG_SWAP_POLARITY, 0x0F, 0x0E)){
+					MI_ERR("Set Plarity failed !");
+					return -1;
+			}
+	}else if(gsensor_chip_info.asic == ASIC_2511){
+	        target[2] = ((swap_plarity_old & (1<<1)) != 0) ? (-target[2]) :target[2];
+			if(mir3da_register_mask_write(handle, NSA_REG_SWAP_POLARITY, 0x0F, 0x00)){
+					MI_ERR("Set Plarity failed !");
+					return -1;
+			}
+	}   
+
+    result=NSA_calibrate(handle, coarse_step, fine_step, 0x3ff, target);
+
+    // Restore swap/plarity setting
+    if(mir3da_register_mask_write(handle, NSA_REG_SWAP_POLARITY, 0x0F, swap_plarity_old&0x0F)){
+        MI_ERR("Restore SWAP/PLARITY setting failed !");
+        return -1;
+    }
+#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */
+    return result;
+}
+
+static int NSA_NTO_auto_calibrate(MIR_HANDLE handle, int xyz[3])
+{
+    int     result = 0;
+
+#if MIR3DA_AUTO_CALIBRATE
+    int     coarse_step[3];
+    int     fine_step[3];
+    int     custom_step[3] = {0};
+   unsigned char     swap_plarity_old = 0;
+    int     temp=0;  
+
+    /* compute step */
+    if( NSA_NTO_cali_step_calc(handle, coarse_step, fine_step, custom_step) ) {
+        MI_ERR("Compute step failed !");
+        return -1; 
+    }
+
+    // save swap/plarity old setting
+    if(mir3da_register_read(handle, NSA_REG_SWAP_POLARITY, &swap_plarity_old)){
+        MI_ERR("Get SWAP/PLARITY setting failed !");
+        return -1;
+    }
+
+        if(gsensor_chip_info.asic == ASIC_2512B){
+                coarse_step[2] = 2 *coarse_step[2];
+
+                if((swap_plarity_old & (1<<0))){
+                   temp = xyz[0];
+                   xyz[0] = ((swap_plarity_old & (1<<2)) == 0) ? (-xyz[1]) :xyz[1];
+                   xyz[1] = ((swap_plarity_old & (1<<3)) == 0) ? (-temp) :temp;
+                }else{
+                   xyz[0] = ((swap_plarity_old & (1<<3)) == 0) ? (-xyz[0]) :xyz[0];
+                   xyz[1] = ((swap_plarity_old & (1<<2)) == 0) ? (-xyz[1]) :xyz[1];
+                }
+                xyz[2] = ((swap_plarity_old & (1<<1)) == 0) ? (-xyz[2]) :xyz[2];
+        }else if(gsensor_chip_info.asic == ASIC_2511){
+                if((swap_plarity_old & (1<<0))){
+                   temp = xyz[0];
+                   xyz[0] = ((swap_plarity_old & (1<<2)) != 0) ? (-xyz[1]) :xyz[1];
+                   xyz[1] = ((swap_plarity_old & (1<<3)) != 0) ? (-temp) :temp;
+                }else{
+                   xyz[0] = ((swap_plarity_old & (1<<3)) != 0) ? (-xyz[0]) :xyz[0];
+                   xyz[1] = ((swap_plarity_old & (1<<2)) != 0) ? (-xyz[1]) :xyz[1];
+                }
+
+                xyz[2] = ((swap_plarity_old & (1<<1)) != 0) ? (-xyz[2]) :xyz[2];
+        }   
+    
+    result = NSA_once_calibrate(handle, coarse_step, fine_step, xyz);
+#endif /* !MIR3DA_AUTO_CALIBRATE */
+    return result;
+}
+
+int mir3da_calibrate(MIR_HANDLE handle, int z_dir)
+{
+    int     res = 0;	
+	
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+    int     xyz[3]={0};
+	
+    if( is_cali )
+        return -1;
+    is_cali = 1;
+
+    /* restore original direction if last calibration was done in a wrong direction */
+    mir3da_write_offset(handle, original_offset);
+	      
+    cycle_read_xyz(handle, &xyz[0], &xyz[1], &xyz[2], 20);	
+
+    res = mir3da_gsensor_drv.obj[gsensor_mod].calibrate(handle, z_dir); 
+    if (res != 0){
+          MI_ERR("Calibrate failed !");
+          mir3da_write_offset(handle, original_offset); 
+    }else
+          bLoad = FILE_EXIST;
+    
+    is_cali = 0;
+#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */
+    return res;
+}
+
+#if MIR3DA_AUTO_CALIBRATE
+#define STABLE_CHECK_SAMPLE_NUM     10
+#define STABLE_CHECK_THRESHOLD      50000
+#define AUTO_CALI_THRESHOLD_XY      200
+#define AUTO_CALI_THRESHOLD_Z       200
+
+static unsigned char    stable_sample_cnt = 0;
+static int              stable_sample_pow_sum[STABLE_CHECK_SAMPLE_NUM] = {0};
+static int              stable_sample_sum[3] = {0};
+
+static int mir3da_auto_cali_condition_confirm(int x, int y, int z, int ave_xyz[3])
+{
+    int    max = 0, min = 0;
+    int    i;
+    int    x_ok=0,y_ok=0,z_ok=0; 	
+    
+    stable_sample_pow_sum[stable_sample_cnt] = x*x + y*y + z*z;
+    stable_sample_sum[0] += x;
+    stable_sample_sum[1] += y;
+    stable_sample_sum[2] += z;
+    stable_sample_cnt++;
+    
+    MI_MSG("---stable_sample_cnt = %d", stable_sample_cnt);
+    
+    if( stable_sample_cnt < STABLE_CHECK_SAMPLE_NUM )
+        return -1;
+    stable_sample_cnt = 0;
+    
+    max = stable_sample_pow_sum[0];
+    min = stable_sample_pow_sum[0];
+    stable_sample_pow_sum[0] = 0;
+    for(i = 1; i < STABLE_CHECK_SAMPLE_NUM; i++){
+        if( stable_sample_pow_sum[i] > max )
+            max = stable_sample_pow_sum[i];
+        if( stable_sample_pow_sum[i] < min )
+            min = stable_sample_pow_sum[i];
+        stable_sample_pow_sum[i] = 0;
+    }
+    MI_MSG("---max = %d; min = %d", max, min);
+
+    ave_xyz[0] = stable_sample_sum[0]/STABLE_CHECK_SAMPLE_NUM;
+    stable_sample_sum[0] = 0;
+    ave_xyz[1] = stable_sample_sum[1]/STABLE_CHECK_SAMPLE_NUM;
+    stable_sample_sum[1] = 0;
+    ave_xyz[2] = stable_sample_sum[2]/STABLE_CHECK_SAMPLE_NUM;
+    stable_sample_sum[2] = 0;
+            
+        MI_MSG("ave_x = %d, ave_y = %d, ave_z = %d", ave_xyz[0], ave_xyz[1], ave_xyz[2]);
+        x_ok =  (abs(ave_xyz[0]) < AUTO_CALI_THRESHOLD_XY) ? 1:0;
+        y_ok =  (abs(ave_xyz[1]) < AUTO_CALI_THRESHOLD_XY) ? 1:0;
+        z_ok =  (abs(abs(ave_xyz[2])-1024) < AUTO_CALI_THRESHOLD_Z) ? 1:0;
+
+        if( (abs(max-min) > STABLE_CHECK_THRESHOLD) ||((x_ok + y_ok + z_ok) < 2) ) {
+            return -1;
+        }
+
+        return 0;
+}
+
+static int mir3da_auto_calibrate(MIR_HANDLE handle, int x, int y, int z)
+{
+    int     res = 0;
+    int     xyz[3] = {0};
+
+    if((gsensor_chip_info.mems== MEMS_RTO3)
+	||(gsensor_chip_info.reg_value == 0x4B)
+	||(gsensor_chip_info.reg_value == 0x8C)
+	||(gsensor_chip_info.reg_value == 0xCA)
+	||(gsensor_chip_info.mems == MEMS_GT2))
+    	return -1;
+
+    if( is_cali )
+        return -1;
+    is_cali = 1;
+   
+#if MIR3DA_SUPPORT_FAST_AUTO_CALI
+    if(mir3da_gsensor_drv.method->support_fast_auto_cali()){
+        cycle_read_xyz(handle,&xyz[0],&xyz[1],&xyz[2],5);
+    }
+    else{
+        if( mir3da_auto_cali_condition_confirm(x, y, z, xyz) ){
+            res = -1;
+            goto EXIT;
+        }   
+    }
+#else   
+    if( mir3da_auto_cali_condition_confirm(x, y, z, xyz) ){
+        res = -1;
+        goto EXIT;
+    }   
+#endif
+
+    mir3da_write_offset(handle, original_offset);
+
+    res = mir3da_gsensor_drv.obj[gsensor_mod].auto_calibrate(handle, xyz); 
+    if (res != 0){
+         MI_ERR("Calibrate failed !");
+         mir3da_write_offset(handle, original_offset);
+    }else
+            bLoad = FILE_EXIST;
+    
+EXIT:    
+    is_cali = 0;
+
+    return res;
+}
+#endif /* !MIR3DA_AUTO_CALIBRATE */
+
+static int NSA_interrupt_ops(MIR_HANDLE handle, mir_int_ops_t *ops)
+{   
+    switch(ops->type)
+    {
+        case INTERRUPT_OP_INIT:
+        
+            /* latch */
+            mir3da_register_mask_write(handle, NSA_REG_INT_LATCH, 0x0f, ops->data.init.latch);
+            /* active level & output mode */
+            mir3da_register_mask_write(handle, NSA_REG_INT_PIN_CONFIG, 0x0f, ops->data.init.level|(ops->data.init.pin_mod<<1)|(ops->data.init.level<<2)|(ops->data.init.pin_mod<<3));
+            
+            break;
+            
+        case INTERRUPT_OP_ENABLE:
+            switch( ops->data.int_src )
+            { 
+                case INTERRUPT_ACTIVITY:
+                    /* Enable active interrupt */
+                    mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_SETTINGS1, 0x07, 0x07);                    
+                    break;
+                case INTERRUPT_CLICK:
+                    /* Enable single and double tap detect */
+                    mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_SETTINGS1, 0x30, 0x30);                   
+                    break;
+            }
+            break;
+            
+        case INTERRUPT_OP_CONFIG:
+            
+                            
+            switch( ops->data.cfg.int_src )
+            {
+                case INTERRUPT_ACTIVITY:
+                         
+                    mir3da_register_write(handle, NSA_REG_ACTIVE_THRESHOLD, ops->data.cfg.int_cfg.act.threshold);
+                    mir3da_register_mask_write(handle, NSA_REG_ACTIVE_DURATION, 0x03, ops->data.cfg.int_cfg.act.duration);
+                    
+                    /* Int mapping */
+                    if(ops->data.cfg.pin == INTERRUPT_PIN1) {  
+                        mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1, (1<<2), (1<<2));
+                    }
+                    else if(ops->data.cfg.pin == INTERRUPT_PIN2) {
+                        mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING3, (1<<2), (1<<2));
+                    }
+                    break;
+                    
+                case INTERRUPT_CLICK:
+                    
+                    mir3da_register_mask_write(handle, NSA_REG_TAP_THRESHOLD, 0x1f, ops->data.cfg.int_cfg.clk.threshold);
+                    mir3da_register_mask_write(handle, NSA_REG_TAP_DURATION, (0x03<<5)|(0x07), (ops->data.cfg.int_cfg.clk.quiet_time<<7)|(ops->data.cfg.int_cfg.clk.click_time<<6)|(ops->data.cfg.int_cfg.clk.window));
+                    
+                    if(ops->data.cfg.pin == INTERRUPT_PIN1) {
+                        mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1, 0x30, 0x30);
+                    }
+                    else if(ops->data.cfg.pin == INTERRUPT_PIN2) {
+                        mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING3, 0x30, 0x30);
+                    }
+                    break;
+            }
+            break;
+            
+        case INTERRUPT_OP_DISABLE:
+            switch( ops->data.int_src )
+            {
+                case INTERRUPT_ACTIVITY:
+                    /* Enable active interrupt */
+                    mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_SETTINGS1, 0x07, 0x00);
+                    break;
+                    
+                case INTERRUPT_CLICK:
+                    /* Enable single and double tap detect */
+                    mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_SETTINGS1, 0x30, 0x00);
+                    break;
+            }
+            break;
+            
+        default:
+            MI_ERR("Unsupport operation !");
+    }
+    return 0;
+}
+
+int mir3da_interrupt_ops(MIR_HANDLE handle, mir_int_ops_t *ops)
+{
+    int res = 0;
+    
+    res = mir3da_gsensor_drv.obj[gsensor_mod].int_ops(handle, ops);
+    return res;
+}
+
+#if FILTER_AVERAGE_ENHANCE
+int mir3da_get_filter_param(struct mir3da_filter_param_s* param){
+    if (param == 0){
+        MI_ERR("Invalid param!");
+        return -1;
+    }
+
+    param->filter_param_h = core_ctx.tFac[0].filter_param_h;
+    param->filter_param_l = core_ctx.tFac[0].filter_param_l;
+    param->filter_threhold = core_ctx.tFac[0].filter_threhold;
+
+    MI_MSG("FILTER param is get: filter_param_h = %d, filter_param_l = %d, filter_threhold = %d", param->filter_param_h, param->filter_param_l, param->filter_threhold);
+    
+    return 0;
+}
+
+int mir3da_set_filter_param(struct mir3da_filter_param_s* param){
+
+    if (param == 0){
+        MI_ERR("Invalid param!");
+        return -1;
+    }
+
+    MI_MSG("FILTER param is set: filter_param_h = %d, filter_param_l = %d, filter_threhold = %d", param->filter_param_h, param->filter_param_l, param->filter_threhold);
+
+    core_ctx.tFac[1].filter_param_l = core_ctx.tFac[2].filter_param_l = core_ctx.tFac[0].filter_param_l = param->filter_param_l;
+    core_ctx.tFac[1].filter_param_h =core_ctx.tFac[2].filter_param_h = core_ctx.tFac[0].filter_param_h  = param->filter_param_h;
+    core_ctx.tFac[1].filter_threhold = core_ctx.tFac[2].filter_threhold =core_ctx.tFac[0].filter_threhold = param->filter_threhold;
+
+    return 0;
+}
+#endif //#if FILTER_AVERAGE_ENHANCE
+
+int mir3da_get_enable(MIR_HANDLE handle, char *enable)
+{
+    int             res = 0;
+    unsigned char   reg_data=0;
+
+    res = mir3da_register_read(handle, mir3da_gsensor_drv.obj[gsensor_mod].power.addr, &reg_data);
+    if(res != 0) {
+        return res;
+    }
+    
+     *enable = ( reg_data & mir3da_gsensor_drv.obj[gsensor_mod].power.mask ) ? 0 : 1;
+
+    return res;
+}
+
+int mir3da_set_enable(MIR_HANDLE handle, char enable)
+{
+    int             res = 0;
+    unsigned char   reg_data = 0;
+	
+    if(!enable) {
+		reg_data = mir3da_gsensor_drv.obj[gsensor_mod].power.value;
+    }
+    
+    res = mir3da_register_mask_write(handle, mir3da_gsensor_drv.obj[gsensor_mod].power.addr, mir3da_gsensor_drv.obj[gsensor_mod].power.mask, reg_data);
+
+    return res;
+}
+
+static int NSA_get_reg_data(MIR_HANDLE handle, char *buf)
+{
+    int                 count = 0;
+    int                 i;
+    unsigned char       val;
+        
+    count += mir3da_gsensor_drv.method->mysprintf(buf+count, "---------start---------");
+    for (i = 0; i <= 0xd2; i++){
+        if(i%16 == 0)
+            count += mir3da_gsensor_drv.method->mysprintf(buf+count, "\n%02x\t", i);
+        mir3da_register_read(handle, i, &val); 
+        count += mir3da_gsensor_drv.method->mysprintf(buf+count, "%02X ", val);
+    }
+
+    count += mir3da_gsensor_drv.method->mysprintf(buf+count, "\n--------end---------\n");    
+    return count;
+}
+
+int mir3da_get_reg_data(MIR_HANDLE handle, char *buf)
+{     
+    return mir3da_gsensor_drv.obj[gsensor_mod].get_reg_data(handle, buf);
+}
+
+int mir3da_set_odr(MIR_HANDLE handle, int delay)
+{
+    int     res = 0;
+    int     odr = 0;
+
+    if(delay <= 5)
+    {
+       odr = MIR3DA_ODR_200HZ;
+    }
+    else if(delay <= 10)
+    {
+       odr = MIR3DA_ODR_100HZ;
+    }
+    else
+    {
+       odr = MIR3DA_ODR_50HZ;
+    }       
+
+    res = mir3da_register_mask_write(handle, mir3da_gsensor_drv.obj[gsensor_mod].odr_sect[odr].addr, 
+            mir3da_gsensor_drv.obj[gsensor_mod].odr_sect[odr].mask,mir3da_gsensor_drv.obj[gsensor_mod].odr_sect[odr].value);
+    if(res != 0) {
+        return res;
+    } 
+
+    return res; 
+}
+
+static int mir3da_soft_reset(MIR_HANDLE handle)
+{
+    int             res = 0;
+    unsigned char   reg_data;
+
+    reg_data = mir3da_gsensor_drv.obj[gsensor_mod].soft_reset.value;
+    res = mir3da_register_mask_write(handle, mir3da_gsensor_drv.obj[gsensor_mod].soft_reset.addr, mir3da_gsensor_drv.obj[gsensor_mod].soft_reset.mask, reg_data);
+    mir3da_gsensor_drv.method->msdelay(5);
+    
+    return res;
+}
+
+int mir3da_module_detect(PLAT_HANDLE handle)
+{
+    int             i, res = 0;
+    unsigned char   cid, mid;
+    int             is_find = -1;
+
+    /* Probe gsensor module */  
+    for(i=0;i<sizeof(mir3da_gsensor)/sizeof(mir3da_gsensor[0]);i++) {
+        res = mir3da_register_read(handle, mir3da_gsensor[i].chip_id.addr, &cid);
+        if(res != 0) {
+            return res;
+        }
+        
+        cid &= mir3da_gsensor[i].chip_id.mask;
+        if(mir3da_gsensor[i].chip_id.value == cid) {
+            res = mir3da_register_read(handle, mir3da_gsensor[i].mod_id.addr, &mid);
+            if(res != 0) {
+                return res;
+            }
+
+            mid &= mir3da_gsensor[i].mod_id.mask;
+            if( mir3da_gsensor[i].mod_id.value == mid ){
+                MI_MSG("Found Gsensor MIR3DA !");
+                gsensor_mod = i;
+                is_find =0;
+                break;
+            }
+        }
+    }
+
+    return is_find;
+}
+
+int mir3da_parse_chip_info(PLAT_HANDLE handle){
+    unsigned char i=0,tmp=0;   
+    unsigned char reg_value = -1,reg_value1 = -1,reg_value2 = -1;
+    char res=-1;
+
+    if(-1 == gsensor_mod)
+        return res; 
+
+    res = mir3da_register_read(handle, NSA_REG_CHIP_INFO, &reg_value);
+    if(res != 0) {
+        return res;
+    }
+
+  gsensor_chip_info.reg_value    = reg_value;               
+
+    if(0 == (reg_value>>6)){  
+        return -1;
+    }
+
+    if(!(reg_value&0xc0)){
+        gsensor_chip_info.asic = ASIC_2511;
+        gsensor_chip_info.mems= MEMS_T9;
+        gsensor_chip_info.package= PACKAGE_NONE;
+        
+        for(i=0;i<sizeof(mir3da_chip_info_list)/sizeof(mir3da_chip_info_list[0]);i++){
+                if(reg_value == mir3da_chip_info_list[i].reg_value){
+                    gsensor_chip_info.package = mir3da_chip_info_list[i].package;
+                    gsensor_chip_info.asic= mir3da_chip_info_list[i].asic;                  
+                    gsensor_chip_info.mems= mir3da_chip_info_list[i].mems;              
+                    break;
+                }                   
+        }
+    }
+    else{
+        gsensor_chip_info.asic = ASIC_2512B;
+        gsensor_chip_info.mems= MEMS_T9;
+        gsensor_chip_info.package= PACKAGE_NONE;
+        
+        gsensor_chip_info.package = (package_type)((reg_value&0xc0)>>6);
+            
+        if((reg_value&0x38)>>3 == 0x01)
+            gsensor_chip_info.asic =ASIC_2512B;
+        else if((reg_value&0x38)>>3 == 0x02)
+            gsensor_chip_info.asic =ASIC_2513A;
+        else if((reg_value&0x38)>>3 == 0x03)
+            gsensor_chip_info.asic =ASIC_2516;
+
+        res = mir3da_register_read(handle, NSA_REG_CHIP_INFO_SECOND, &reg_value1);
+        if(res != 0) {
+            return res;
+        }	
+
+        if(gsensor_chip_info.asic == ASIC_2512B){
+            res = mir3da_register_read(handle, NSA_REG_MEMS_OPTION, &reg_value);
+            if(res != 0) {
+               return res;
+            }
+			tmp= ((reg_value&0x01)<<2) |((reg_value1&0xc0)>>6); 
+        }
+		else
+		{
+			tmp= (reg_value1&0xe0)>>5; 
+        }
+		
+		res = mir3da_register_read(handle, NSA_REG_MEMS_OPTION, &reg_value2);
+		if(res != 0) {
+		   return res;
+		}
+
+        if(tmp == 0x00){
+	      if(reg_value2&0x80)
+	        gsensor_chip_info.mems =MEMS_TV03;
+	      else
+	        gsensor_chip_info.mems =MEMS_T9;
+        }else if(tmp == 0x01){
+               gsensor_chip_info.mems =MEMS_RTO3;
+        }	
+        else if(tmp == 0x03){
+          gsensor_chip_info.mems =MEMS_GT2;
+		  if((gsensor_chip_info.reg_value!=0x5A)&&(gsensor_chip_info.asic==ASIC_2516))
+            gsensor_chip_info.mems =MEMS_GT3;
+        }		
+        else if(tmp == 0x04){
+          gsensor_chip_info.mems =MEMS_GT3;
+        }
+
+#if YZ_CROSS_TALK_ENABLE 
+        if(reg_value1&0x10)
+          yzcross = -(reg_value1&0x0f);
+        else
+          yzcross = (reg_value1&0x0f); 
+#endif 		
+	}
+
+    return 0;
+}
+
+
+int mir3da_install_general_ops(struct general_op_s *ops)
+{    
+    if(0 == ops){
+        return -1;
+    }
+    
+    mir3da_gsensor_drv.method = ops;
+    return 0;
+}
+
+MIR_HANDLE mir3da_core_init(PLAT_HANDLE handle)
+{
+    int             res = 0;
+
+#if FILTER_AVERAGE_ENHANCE 
+int i =0;
+#endif
+
+    mir3da_gsensor_drv.obj = mir3da_gsensor;
+
+    if(gsensor_mod < 0){
+        res = mir3da_module_detect(handle);
+        if(res) {
+         MI_ERR("Can't find Mir3da gsensor!!"); 
+            return 0;
+        }
+
+        /* No miramems gsensor instance found */
+        if(gsensor_mod < 0) {   
+            return 0;
+        }
+    }
+
+    MI_MSG("Probe gsensor module: %s", mir3da_gsensor[gsensor_mod].asic);
+
+#if FILTER_AVERAGE_ENHANCE 
+    /* configure default filter param */    
+    for (i = 0; i < 3;i++){     
+        core_ctx.tFac[i].filter_param_l = 2;
+        core_ctx.tFac[i].filter_param_h = 8;
+        core_ctx.tFac[i].filter_threhold = 60;
+
+        core_ctx.tFac[i].refN_l = 0;
+        core_ctx.tFac[i].refN_h = 0;
+    }    
+#endif
+
+    res = mir3da_chip_resume(handle);
+    if(res) {
+                MI_ERR("chip resume fail!!\n");
+                return 0;
+    }
+
+    return handle;
+}
+
+int mir3da_chip_resume(MIR_HANDLE handle)
+{
+    int     res = 0;
+    unsigned char      reg_data;
+    unsigned char      i = 0;
+    
+    res = mir3da_soft_reset(handle); 
+    if(res) {
+        MI_ERR("Do softreset failed !");
+        return res;
+    }
+    
+    for(i=0;i<MIR3DA_INIT_SECT_LEN;i++) {
+        if( mir3da_gsensor_drv.obj[gsensor_mod].init_sect[i].addr < 0 ) {
+            break;
+        }
+
+        reg_data = mir3da_gsensor_drv.obj[gsensor_mod].init_sect[i].value;
+        res = mir3da_register_mask_write(handle, mir3da_gsensor_drv.obj[gsensor_mod].init_sect[i].addr, mir3da_gsensor_drv.obj[gsensor_mod].init_sect[i].mask, reg_data);
+        if(res != 0) {
+            return res;
+        } 
+    }
+
+    mir3da_gsensor_drv.method->msdelay(10);             
+
+    if(gsensor_type<0){
+        gsensor_type=mir3da_parse_chip_info(handle);
+      
+		if(gsensor_type<0){
+			MI_ERR("Can't parse Mir3da gsensor chipinfo!!");	
+			return -1; 
+		}
+	}
+	
+	if(gsensor_chip_info.asic==ASIC_2513A){
+		
+		res = mir3da_register_read(handle, NSA_REG_CHIP_INFO, &reg_data);
+		if((reg_data == 0x55)||(reg_data == 0x50)){
+
+			mir3da_register_mask_write(handle, 0x40, 0xff, 0x96);
+			mir3da_register_read(handle, 0x41, &reg_data);
+			if(reg_data != 0xBB){
+				MI_ERR("error chip");
+				return -1;
+			}
+			
+			mir3da_register_mask_write(handle, NSA_REG_POWERMODE_BW, 0x36, 0x30);
+			mir3da_register_mask_write(handle, NSA_REG_INT_PIN_CONFIG, 0xff, 0x00);
+
+			mir3da_register_read(handle, NAS_REG_OSC_TRIM, &reg_data);
+			if(reg_data == 0x00)
+				mir3da_register_mask_write(handle, NAS_REG_OSC_TRIM, 0xff, 0x50);
+			
+			is_da217 = 1;
+			MI_MSG("Da217 found!!!");
+		}else{
+			MI_ERR("parse asic error");
+			return -1;
+		}
+	}
+
+    if(gsensor_chip_info.asic==ASIC_2512B){
+        
+        reg_data = mir3da_gsensor_drv.method->get_address(handle);
+
+
+        if(reg_data ==0x26 ||reg_data ==0x4c){
+
+            mir3da_register_mask_write(handle,NSA_REG_SENS_COMP,0xc0,0x00);
+        }
+    }
+
+    
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+    res = mir3da_read_offset(handle, original_offset);
+    if (res != 0){
+        MI_ERR("Read offset failed !");
+        return res;    
+    }
+    
+    bLoad = FILE_CHECKING;
+    readOffsetCnt = 0;    
+    readsubfileCnt =0;
+    manual_load_cali_file(handle);
+#endif
+
+	if(is_da217 == 1){
+		res = mir3da_irq_init(handle);
+		if(res){
+			MI_ERR("step count init fail!!\n");
+			return 0;
+		}
+	}
+
+    return res;
+}
+
+int mir3da_get_primary_offset(MIR_HANDLE handle,int *x,int *y,int *z){
+    int     res = 0;
+    unsigned char      reg_data;
+    unsigned char      i = 0;
+    unsigned char      offset[9]={0};
+
+    res = mir3da_read_offset(handle, offset);
+    if (res != 0){
+        MI_ERR("Read offset failed !");
+        return -1;    
+    }
+    
+    res = mir3da_soft_reset(handle); 
+    if(res) {
+        MI_ERR("Do softreset failed !");
+        return -1;
+    }
+    
+    for(i=0;i<MIR3DA_INIT_SECT_LEN;i++) {
+        if( mir3da_gsensor_drv.obj[gsensor_mod].init_sect[i].addr < 0 ) {
+            break;
+        }
+
+        reg_data = mir3da_gsensor_drv.obj[gsensor_mod].init_sect[i].value;
+        res = mir3da_register_mask_write(handle, mir3da_gsensor_drv.obj[gsensor_mod].init_sect[i].addr, mir3da_gsensor_drv.obj[gsensor_mod].init_sect[i].mask, reg_data);
+        if(res != 0) {
+            MI_ERR("Write register[0x%x] error!",mir3da_gsensor_drv.obj[gsensor_mod].init_sect[i].addr);
+            goto EXIT;
+        } 
+    }
+
+    mir3da_gsensor_drv.method->msdelay(100);        
+
+    res = cycle_read_xyz(handle, x, y, z, 20);
+    if (res){
+            MI_ERR("i2c block read failed\n");
+            goto EXIT;
+    }
+
+    mir3da_write_offset(handle, offset);
+
+	if((gsensor_chip_info.reg_value == 0x4B)
+		||(gsensor_chip_info.reg_value == 0x8C)
+   		||(gsensor_chip_info.reg_value == 0xCA)
+   		||(gsensor_chip_info.mems == MEMS_GT2))
+	{
+		*z = 0;
+	}
+	
+    return 0; 
+
+EXIT:
+    mir3da_write_offset(handle, offset);
+    return -1;
+}
+
+/* int1 */
+int mir3da_irq_init(MIR_HANDLE handle){
+	int res = 0;
+	// irq config
+	res |= mir3da_register_mask_write(handle, NSA_REG_INT_LATCH,		0x0F, 0x00);	//latch 0s
+
+	// step config
+	res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG1,	0xff, 0x01);
+	res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG2,	0xff, 0x62);
+	res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG3,	0xff, 0x46); 
+	res |= mir3da_register_mask_write(handle, NSA_REG_STEP_CONFIG4,	0xff, 0x32);
+	res |= mir3da_register_mask_write(handle, NSA_REG_STEP_FILTER,  0xff, 0x22);	//disable
+
+	//step count
+	res |= mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1, 0x02, 0x02);	/* map int1_step */
+	res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0,           0x01, 0x00);	//disable step int
+
+	//significont motion
+	res |= mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1, 0x80, 0x80);  /* map int1_sm */
+	res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0,           0x02, 0x00);	//disable sm int
+	res |= mir3da_register_mask_write(handle, NSA_REG_SM_THRESHOLD,       0x0A, 0x0A);	//step number
+
+	//tilt
+	res |= mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1, 0x08, 0x08);	/* map int1_tilt */
+	res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0,           0x10, 0x00);	//disable tilt int
+
+	//active
+	res |= mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_MAPPING1,	0x04, 0x04); /* map int1_active */
+	res |= mir3da_register_mask_write(handle, NSA_REG_INTERRUPT_SETTINGS1,	0xC7, 0x80); /* int source: filter data */
+	res |= mir3da_register_mask_write(handle, NSA_REG_ACTIVE_DURATION,		0xff, 0x01);
+	res |= mir3da_register_mask_write(handle, NSA_REG_ACTIVE_THRESHOLD,		0xff, 0x14);
+
+	if(res)
+		MI_ERR("irq init error");
+	
+	MI_MSG("irq init ok")
+	return res;
+} 
+
+int mir3da_get_step_enable(MIR_HANDLE handle, char *enable)
+{
+    int             res = 0;
+    unsigned char   reg_data = 0;
+
+	res = mir3da_register_read(handle, NSA_REG_STEP_FILTER, &reg_data);	//check irq
+	if(res != 0) {
+		return res;
+	}
+
+	*enable = ( reg_data & 0x80 ) ? 1 : 0;
+
+	return res;
+}
+
+int mir3da_set_step_enable(MIR_HANDLE handle, char enable)
+{
+    int             res = 0;
+
+	if(enable){
+		res |= mir3da_register_mask_write(handle, NSA_REG_STEP_FILTER, 0x80, 0x80);	//step count enable
+		res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0,    0x01, 0x01);	//step irq bit
+	}else{
+		res |= mir3da_register_mask_write(handle, NSA_REG_STEP_FILTER, 0x80, 0x00);
+		res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0,    0x01, 0x00);
+	}
+    
+    return res;
+}
+
+int mir3da_get_sm_enable(MIR_HANDLE handle, char *enable)
+{
+    int             res = 0;
+    unsigned char   reg_data = 0;
+
+	res = mir3da_register_read(handle, NSA_REG_STEP_FILTER, &reg_data);
+    if(res != 0) {
+        return res;
+    }
+    
+     *enable = ( reg_data & 0x80 ) ? 1 : 0;
+
+    return res;
+}
+
+int mir3da_set_sm_enable(MIR_HANDLE handle, char enable)
+{
+    int             res = 0;
+
+	if(enable){
+		res |= mir3da_register_mask_write(handle, NSA_REG_STEP_FILTER, 0x80, 0x80);
+		res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0,    0x02, 0x02);
+	}else{
+		res |= mir3da_register_mask_write(handle, NSA_REG_STEP_FILTER, 0x80, 0x00);
+		res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0,    0x02, 0x00);
+	}
+    
+    return res;
+}
+
+int mir3da_get_tilt_enable(MIR_HANDLE handle, char *enable)
+{
+    int             res = 0;
+    unsigned char   reg_data = 0;
+
+	res = mir3da_register_read(handle, NAS_REG_INT_SET0, &reg_data);
+    if(res != 0) {
+        return res;
+    }
+    
+     *enable = ( reg_data & 0x10 ) ? 1 : 0;
+
+    return res;
+}
+
+int mir3da_set_tilt_enable(MIR_HANDLE handle, char enable)
+{
+    int             res = 0;
+
+	if(enable){
+		res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0, 0x10, 0x10);
+	}else{
+		res |= mir3da_register_mask_write(handle, NAS_REG_INT_SET0, 0x10, 0x00);
+	}
+    
+    return res;
+}
+
+int mir3da_open_interrupt(MIR_HANDLE handle, int num){
+	int   res = 0;
+
+	res |= mir3da_register_mask_write(handle,NSA_REG_INTERRUPT_SETTINGS1,0xff,0x87);
+	res |= mir3da_register_mask_write(handle,NSA_REG_ACTIVE_DURATION,0x03,0x00 );
+	res |= mir3da_register_mask_write(handle,NSA_REG_ACTIVE_THRESHOLD,0xff,0x1B );
+			
+	switch(num){
+
+		case 1:
+			res |= mir3da_register_mask_write(handle,NSA_REG_INTERRUPT_MAPPING1,0x04,0x04 );
+			break;
+
+		case 2:
+			res |= mir3da_register_mask_write(handle,NSA_REG_INTERRUPT_MAPPING3,0x04,0x04 );
+			break;
+		default:
+			break;
+	}
+
+	return res;
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_core.h b/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_core.h
new file mode 100755
index 0000000..3b5e1d4
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_core.h
@@ -0,0 +1,319 @@
+/* Core header for MiraMEMS 3-Axis Accelerometer's driver. 
+ * 
+ * mir3da_core.h - Linux kernel modules for MiraMEMS 3-Axis Accelerometer
+ *
+ * Copyright (C) 2011-2013 MiraMEMS Sensing Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 __MIR3DA_CORE_H__
+#define __MIR3DA_CORE_H__
+
+#define CUST_VER                            ""                                          /* for Custom debug version */
+#define CORE_VER                            "4.0.0_2017-07-22-15:35:30_"CUST_VER
+ 
+#define MIR3DA_SUPPORT_CHIP_LIST            MIR_NSA_NTO
+ 
+#define MIR3DA_BUFSIZE                      256
+
+#define MIR3DA_STK_TEMP_SOLUTION            1
+#define MIR3DA_OFFSET_TEMP_SOLUTION         0
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+#define MIR3DA_AUTO_CALIBRATE               0
+#else
+#define MIR3DA_AUTO_CALIBRATE               0
+#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */
+#if MIR3DA_AUTO_CALIBRATE
+#define MIR3DA_SUPPORT_FAST_AUTO_CALI       0
+#else
+#define MIR3DA_SUPPORT_FAST_AUTO_CALI       0
+#endif 
+#define MIR3DA_SENS_TEMP_SOLUTION           0
+#define FILTER_AVERAGE_ENHANCE              0
+#define FILTER_AVERAGE_EX                   0
+#define MIR3DA_SUPPORT_MULTI_LAYOUT         0
+#define YZ_CROSS_TALK_ENABLE                0 
+
+#define MIR3DA_OFFSET_LEN                   9
+
+
+typedef void*   MIR_HANDLE;
+typedef void*   PLAT_HANDLE;
+
+
+struct serial_manage_if_s {
+    
+    int                         (*read)(PLAT_HANDLE handle, unsigned char addr, unsigned char *data);
+    int                         (*write)(PLAT_HANDLE handle, unsigned char addr, unsigned char data);
+    int                         (*read_block)(PLAT_HANDLE handle, unsigned char base_addr, unsigned char count, unsigned char *data);
+};
+
+struct general_op_s {
+
+    struct serial_manage_if_s   smi;
+    
+    int                         (*data_save)(unsigned char *data);
+    int                         (*data_get)(unsigned char *data);
+    int                         (*data_check)(void);
+    int                         (*get_address)(PLAT_HANDLE handle);		
+    int                         (*support_fast_auto_cali)(void);
+    
+    int                         (*myprintf)(const char *fmt, ...);
+    int                         (*mysprintf)(char *buf, const char *fmt, ...);
+    void                        (*msdelay)(int ms);                        
+};  
+
+#define MIR_GENERAL_OPS_DECLARE(OPS_HDL, SMI_RD, SMI_RDBL, SMI_WR, DAT_SAVE, DAT_GET,DAT_CHECK, GET_ADDRESS,SUPPORT_FAST_AUTO_CALI,MDELAY, MYPRINTF, MYSPRINTF)                                      \
+                                                                                                                                                        \
+                                struct general_op_s     OPS_HDL = { { SMI_RD, SMI_WR, SMI_RDBL }, DAT_SAVE, DAT_GET,DAT_CHECK,GET_ADDRESS, SUPPORT_FAST_AUTO_CALI,MYPRINTF, MYSPRINTF, MDELAY }
+                                        
+enum interrupt_src {
+
+    INTERRUPT_ACTIVITY     = 1,
+    INTERRUPT_CLICK,
+
+};
+
+typedef enum _int_op_type {
+
+    INTERRUPT_OP_INIT,
+    INTERRUPT_OP_ENABLE,
+    INTERRUPT_OP_CONFIG,
+    INTERRUPT_OP_DISABLE,
+ 
+} mir_int_op_type;
+
+enum interrupt_pin {
+
+    INTERRUPT_PIN1,
+    INTERRUPT_PIN2,
+};
+
+enum pin_output_mode {
+
+    OUTPUT_MOD_PULL_PUSH,
+    OUTPUT_MOD_OD,
+};
+
+struct int_act_cfg_s {
+
+    unsigned char           threshold;
+    unsigned char           duration;
+};
+
+struct int_clk_cfg_s {
+
+    unsigned char                   threshold;
+    unsigned char                   click_time;     /* click time */
+    unsigned char                   quiet_time;     /* quiet time after click */
+    unsigned char                   window;         /* for second click time window */
+};
+
+typedef union _int_src_configuration {
+    
+    struct int_act_cfg_s            act;
+    struct int_clk_cfg_s            clk;
+
+} mir_int_src_cfg_t;
+    
+typedef struct _int_configuration {
+
+    enum interrupt_pin              pin;
+    enum interrupt_src              int_src;
+    
+    mir_int_src_cfg_t               int_cfg;  
+    
+} mir_int_cfg_t;
+
+typedef struct _int_init_data {
+
+    enum pin_output_mode            pin_mod;
+
+    unsigned char                   level;      /* 1: high active, 0: low active */
+    unsigned char                   latch;          /* >0: latch time, 0: no latch */
+     
+} mir_int_init_t ;
+
+typedef union _int_op_data {
+
+    enum interrupt_src              int_src;
+ 
+    mir_int_init_t                  init;
+    mir_int_cfg_t                   cfg;
+    
+} mir_int_op_data;
+
+typedef struct _int_operations {
+
+    mir_int_op_type                 type;
+    mir_int_op_data                 data;
+    
+} mir_int_ops_t;                             
+                                                        
+/* Register define for NSA asic */
+#define NSA_REG_SPI_I2C                 0x00
+#define NSA_REG_WHO_AM_I                0x01
+#define NSA_REG_ACC_X_LSB               0x02
+#define NSA_REG_ACC_X_MSB               0x03
+#define NSA_REG_ACC_Y_LSB               0x04
+#define NSA_REG_ACC_Y_MSB               0x05
+#define NSA_REG_ACC_Z_LSB               0x06
+#define NSA_REG_ACC_Z_MSB               0x07 
+#define NSA_REG_MOTION_FLAG				0x09
+#define NSA_REG_ORIENT_STATUS			0x0C
+#define NSA_REG_STEPS_MSB				0x0D
+#define NSA_REG_STEPS_LSB				0x0E
+#define NSA_REG_G_RANGE                 0x0F
+#define NSA_REG_ODR_AXIS_DISABLE        0x10
+#define NSA_REG_POWERMODE_BW            0x11
+#define NSA_REG_SWAP_POLARITY           0x12
+#define NSA_REG_FIFO_CTRL               0x14
+#define NAS_REG_INT_SET0				0x15
+#define NSA_REG_INTERRUPT_SETTINGS1     0x16
+#define NSA_REG_INTERRUPT_SETTINGS2     0x17
+#define NSA_REG_INTERRUPT_MAPPING1      0x19
+#define NSA_REG_INTERRUPT_MAPPING2      0x1a
+#define NSA_REG_INTERRUPT_MAPPING3      0x1b
+#define NSA_REG_INT_PIN_CONFIG          0x20
+#define NSA_REG_INT_LATCH               0x21
+#define NSA_REG_ACTIVE_DURATION         0x27
+#define NSA_REG_ACTIVE_THRESHOLD        0x28
+#define NSA_REG_TAP_DURATION            0x2A
+#define NSA_REG_TAP_THRESHOLD           0x2B
+#define NSA_REG_RESET_STEP				0x2E
+#define NSA_REG_STEP_CONFIG1			0x2F
+#define NSA_REG_STEP_CONFIG2			0x30
+#define NSA_REG_STEP_CONFIG3			0x31
+#define NSA_REG_STEP_CONFIG4			0x32
+#define NSA_REG_STEP_FILTER				0x33
+#define NSA_REG_SM_THRESHOLD			0x34
+#define NSA_REG_CUSTOM_OFFSET_X         0x38
+#define NSA_REG_CUSTOM_OFFSET_Y         0x39
+#define NSA_REG_CUSTOM_OFFSET_Z         0x3a
+#define NSA_REG_ENGINEERING_MODE        0x7f
+#define NSA_REG_SENSITIVITY_TRIM_X      0x80
+#define NSA_REG_SENSITIVITY_TRIM_Y      0x81
+#define NSA_REG_SENSITIVITY_TRIM_Z      0x82
+#define NSA_REG_COARSE_OFFSET_TRIM_X    0x83
+#define NSA_REG_COARSE_OFFSET_TRIM_Y    0x84
+#define NSA_REG_COARSE_OFFSET_TRIM_Z    0x85
+#define NSA_REG_FINE_OFFSET_TRIM_X      0x86
+#define NSA_REG_FINE_OFFSET_TRIM_Y      0x87
+#define NSA_REG_FINE_OFFSET_TRIM_Z      0x88
+#define NSA_REG_SENS_COMP               0x8c
+#define NSA_REG_MEMS_OPTION             0x8f
+#define NSA_REG_CHIP_INFO               0xc0
+#define NSA_REG_CHIP_INFO_SECOND        0xc1
+#define NSA_REG_MEMS_OPTION_SECOND      0xc7
+#define NSA_REG_SENS_COARSE_TRIM        0xd1
+#define NAS_REG_OSC_TRIM				0x8e
+                                         
+#define MIR3DA_ODR_50HZ                  0
+#define MIR3DA_ODR_100HZ                 1
+#define MIR3DA_ODR_200HZ                 2
+
+#define MI_TAG                          "[MIR3DA] "
+enum{
+	DEBUG_ERR=1,
+	DEBUG_ASSERT=1<<1,	
+	DEBUG_MSG=1<<2,
+	DEBUG_FUNC=1<<3,
+	DEBUG_DATA=1<<4,
+};
+
+/* register operation */
+int mir3da_register_read(MIR_HANDLE handle, short reg, unsigned char *data);
+int mir3da_register_write(MIR_HANDLE handle, short reg, unsigned char data);
+int mir3da_register_read_continuously(MIR_HANDLE handle, short base_reg, unsigned char count, unsigned char *data);
+int mir3da_register_mask_write(MIR_HANDLE handle, short addr, unsigned char mask, unsigned char data);
+
+int mir3da_install_general_ops(struct general_op_s *ops);	
+/* chip init */
+int mir3da_module_detect(PLAT_HANDLE handle);
+MIR_HANDLE mir3da_core_init(PLAT_HANDLE handle);
+
+/* data polling */
+int mir3da_read_data(MIR_HANDLE handle, short *x, short *y, short *z);
+
+/* filter configure */
+#if FILTER_AVERAGE_ENHANCE
+struct mir3da_filter_param_s{
+    int filter_param_l;
+    int filter_param_h;
+    int filter_threhold;
+};
+
+int mir3da_get_filter_param(struct mir3da_filter_param_s* param);
+int mir3da_set_filter_param(struct mir3da_filter_param_s* param);
+#endif
+
+#if MIR3DA_STK_TEMP_SOLUTION
+extern char bxstk;
+extern char bystk;
+extern char bzstk;
+extern  int squareRoot(int val);
+#endif
+
+enum {
+    GSENSOR_MOD_NSA_NTO=0,
+};
+
+extern int  gsensor_mod;        /* Initial value */
+
+extern int	is_da217;
+
+/* CALI */
+int mir3da_calibrate(MIR_HANDLE handle, int z_dir);
+
+/* calibration */
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+enum file_check_statu {
+    FILE_NO_EXIST  ,
+    FILE_CHECKING  ,
+    FILE_EXIST,
+};
+extern char bLoad;
+void manual_load_cali_file(MIR_HANDLE handle);
+#endif
+
+/* Interrupt operations */
+int mir3da_interrupt_ops(MIR_HANDLE handle, mir_int_ops_t *ops);
+
+int cycle_read_xyz(MIR_HANDLE handle, int* x, int* y, int* z, int ncycle);
+
+int mir3da_read_offset(MIR_HANDLE handle, unsigned char* offst);
+int mir3da_write_offset(MIR_HANDLE handle, unsigned char* offset);
+
+int mir3da_set_enable(MIR_HANDLE handle, char bEnable);
+int mir3da_get_enable(MIR_HANDLE handle, char *bEnable);
+int mir3da_get_reg_data(MIR_HANDLE handle, char *buf);
+int mir3da_set_odr(MIR_HANDLE handle, int delay);
+int mir3da_direction_remap(short *x,short *y, short *z, int direction);
+
+int mir3da_chip_resume(MIR_HANDLE handle);
+int mir3da_get_primary_offset(MIR_HANDLE handle,int *x,int *y,int *z);
+
+int mir3da_step_count_init(MIR_HANDLE handle);
+int mir3da_get_step_enable(MIR_HANDLE handle, char *enable);
+int mir3da_set_step_enable(MIR_HANDLE handle, char enable);
+int mir3da_get_sm_enable(MIR_HANDLE handle, char *enable);
+int mir3da_set_sm_enable(MIR_HANDLE handle, char enable);
+int mir3da_get_tilt_enable(MIR_HANDLE handle, char *enable);
+int mir3da_set_tilt_enable(MIR_HANDLE handle, char enable);
+
+int mir3da_read_step_counter(MIR_HANDLE handle, unsigned int *cnt);
+int mir3da_reset_step_counter(MIR_HANDLE handle);
+int mir3da_read_step_status(MIR_HANDLE handle);
+
+#endif    /* __MIR3DA_CORE_H__ */
+
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_cust.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_cust.c
new file mode 100755
index 0000000..30e57e6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_cust.c
@@ -0,0 +1,1321 @@
+/* For standard android platform, also available for SPRD, Qualcomm, InfotMic
+ *
+ * mir3da.c - Linux kernel modules for 3-Axis Accelerometer
+ *
+ * Copyright (C) 2011-2013 MiraMEMS Sensing Technology Co., Ltd.
+ *
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/input-polldev.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#include "mir3da_core.h"
+#include "mir3da_cust.h"
+
+#define	MIR3DA_IRQ_MODE					1
+
+#define PLATFORM_QUACOMM                0
+#define PLATFORM_SPRD                   0
+#define PLATFORM_ELSE                   8
+#define TARGET_PLATFORM                 PLATFORM_ELSE                   //PLATFORM_QUACOMM//PLATFORM_SPRD
+
+#define DEVICE_CREATE_BYSELF            1                               // 1 means define device in this driver
+#define DEVICE_CREATE_BYPLATFORM        2                               // 2 means define device in system file
+#define DEVICE_CREATE_MODE              DEVICE_CREATE_BYSELF            //DEVICE_CREATE_BYSELF //DEVICE_CREATE_BYPLATFORM
+
+#if TARGET_PLATFORM == PLATFORM_QUACOMM
+    #define MIR3DA_INPUT_DEV_NAME       "acc"                           //this name should be compatible with the define in HAL
+#else
+    #define MIR3DA_INPUT_DEV_NAME       "accelerometer"                 //this name should be compatible with the define in HAL
+#endif
+#define MIR3DA_DRV_NAME                 "mir3da"
+#define MIR3DA_MISC_NAME                MIR3DA_DRV_NAME
+
+#define GRAVITY_EARTH                   9806550
+#define ABSMIN_2G                       (-GRAVITY_EARTH * 2)
+#define ABSMAX_2G                       (GRAVITY_EARTH * 2)
+
+#define DELAY_INTERVAL_MAX               500
+#define DELAY_INTERVAL                   50 
+
+static MIR_HANDLE                       mir_handle;
+extern int                              Log_level;
+#if MIR3DA_SUPPORT_FAST_AUTO_CALI
+extern int in_autotest(void);
+#else
+int in_autotest(void){return 0;}
+#endif
+
+#define MI_DATA(format, ...)            if(DEBUG_DATA&Log_level){printk(KERN_ERR MI_TAG format "\n", ## __VA_ARGS__);}
+#define MI_MSG(format, ...)             if(DEBUG_MSG&Log_level){printk(KERN_ERR MI_TAG format "\n", ## __VA_ARGS__);}
+#define MI_ERR(format, ...)             if(DEBUG_ERR&Log_level){printk(KERN_ERR MI_TAG format "\n", ## __VA_ARGS__);}
+#define MI_FUN                          if(DEBUG_FUNC&Log_level){printk(KERN_ERR MI_TAG "%s is called, line: %d\n", __FUNCTION__,__LINE__);}
+#define MI_ASSERT(expr)                 \
+	if (!(expr)) {\
+		printk(KERN_ERR "Assertion failed! %s,%d,%s,%s\n",\
+			__FILE__, __LINE__, __func__, #expr);\
+	}
+
+#if  DEVICE_CREATE_MODE == DEVICE_CREATE_BYSELF
+#define I2C_STATIC_BUS_NUM              (1) //define which I2C bus to connect
+static struct i2c_board_info            mir3da_i2c_boardinfo = { I2C_BOARD_INFO(MIR3DA_DRV_NAME, MIR3DA_I2C_ADDR) };
+#endif
+
+struct mir3da_data {
+	struct i2c_client *mir3da_i2c_client;
+	atomic_t delay;
+	atomic_t enable;
+	unsigned char mode;
+	struct input_dev *input;
+	struct mutex enable_mutex;
+	struct delayed_work work;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
+    struct miscdevice misc;
+};
+static int    direction_remap = 0;
+static struct mir3da_data *zx29_mir3da = NULL;
+static struct i2c_client  *mir3da_client = NULL;
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+#if TARGET_PLATFORM == PLATFORM_QUACOMM
+static char OffsetFolerName[] = "/persist/";
+static char OffsetFileName[] = "/persist/miraGSensorOffset.txt";
+#elif TARGET_PLATFORM == PLATFORM_SPRD
+static char OffsetFolerName[] = "/productinfo/";
+static char OffsetFileName[] = "/productinfo/miraGSensorOffset.txt";
+#else
+static char OffsetFolerName[] = "/data/misc/";
+static char OffsetFileName[] = "/data/misc/miraGSensorOffset.txt";
+#endif
+
+#define OFFSET_STRING_LEN               26
+struct work_info
+{
+    char        tst1[20];
+    char        tst2[20];
+    char        buffer[OFFSET_STRING_LEN];
+    struct      workqueue_struct *wq;
+    struct      delayed_work read_work;
+    struct      delayed_work write_work;
+    struct      completion completion;
+    int         len;
+    int         rst; // result of the operation
+};
+
+static struct work_info m_work_info = {{0}};
+
+static void sensor_write_work( struct work_struct *work )
+{
+    struct work_info*   pWorkInfo;
+    struct file         *filep;
+    mm_segment_t        orgfs;
+    int                 ret;   
+
+    orgfs = get_fs();
+    set_fs(KERNEL_DS);
+
+    pWorkInfo = container_of((struct delayed_work*)work, struct work_info, write_work);
+    if (pWorkInfo == NULL){            
+            MI_ERR("get pWorkInfo failed!");       
+            return;
+    }
+    
+    filep = filp_open(OffsetFileName, O_RDWR|O_CREAT, 0600);
+    if (IS_ERR(filep)){
+        MI_ERR("write, sys_open %s error!!.\n", OffsetFileName);
+        ret =  -1;
+    }
+    else
+    {   
+        filep->f_op->write(filep, pWorkInfo->buffer, pWorkInfo->len, &filep->f_pos);
+        filp_close(filep, NULL);
+        ret = 0;        
+    }
+    
+    set_fs(orgfs);   
+    pWorkInfo->rst = ret;
+    complete( &pWorkInfo->completion );
+}
+
+static void sensor_read_work( struct work_struct *work )
+{
+    mm_segment_t orgfs;
+    struct file *filep;
+    int ret; 
+    struct work_info* pWorkInfo;
+        
+    orgfs = get_fs();
+    set_fs(KERNEL_DS);
+    
+    pWorkInfo = container_of((struct delayed_work*)work, struct work_info, read_work);
+    if (pWorkInfo == NULL){            
+        MI_ERR("get pWorkInfo failed!");       
+        return;
+    }
+ 
+    filep = filp_open(OffsetFileName, O_RDONLY, 0600);
+    if (IS_ERR(filep)){
+        MI_ERR("read, sys_open %s error!!.\n",OffsetFileName);
+        set_fs(orgfs);
+        ret =  -1;
+    }
+    else{
+        filep->f_op->read(filep, pWorkInfo->buffer,  sizeof(pWorkInfo->buffer), &filep->f_pos);
+        filp_close(filep, NULL);    
+        set_fs(orgfs);
+        ret = 0;
+    }
+
+    pWorkInfo->rst = ret;
+    complete( &(pWorkInfo->completion) );
+}
+
+static int sensor_sync_read(u8* offset)
+{
+    int     err;
+    int     off[MIR3DA_OFFSET_LEN] = {0};
+    struct work_info* pWorkInfo = &m_work_info;
+     
+    init_completion( &pWorkInfo->completion );
+    queue_delayed_work( pWorkInfo->wq, &pWorkInfo->read_work, msecs_to_jiffies(0) );
+    err = wait_for_completion_timeout( &pWorkInfo->completion, msecs_to_jiffies( 2000 ) );
+    if ( err == 0 ){
+        MI_ERR("wait_for_completion_timeout TIMEOUT");
+        return -1;
+    }
+
+    if (pWorkInfo->rst != 0){
+        return pWorkInfo->rst;
+    }
+    
+    sscanf(m_work_info.buffer, "%x,%x,%x,%x,%x,%x,%x,%x,%x", &off[0], &off[1], &off[2], &off[3], &off[4], &off[5],&off[6], &off[7], &off[8]);
+
+    offset[0] = (u8)off[0];
+    offset[1] = (u8)off[1];
+    offset[2] = (u8)off[2];
+    offset[3] = (u8)off[3];
+    offset[4] = (u8)off[4];
+    offset[5] = (u8)off[5];
+    offset[6] = (u8)off[6];
+    offset[7] = (u8)off[7];
+    offset[8] = (u8)off[8];
+    
+    return 0;
+}
+
+static int sensor_sync_write(u8* off)
+{
+    int err = 0;
+    struct work_info* pWorkInfo = &m_work_info;
+       
+    init_completion( &pWorkInfo->completion );
+    
+    sprintf(m_work_info.buffer, "%x,%x,%x,%x,%x,%x,%x,%x,%x\n", off[0],off[1],off[2],off[3],off[4],off[5],off[6],off[7],off[8]);
+    
+    pWorkInfo->len = sizeof(m_work_info.buffer);
+        
+    queue_delayed_work( pWorkInfo->wq, &pWorkInfo->write_work, msecs_to_jiffies(0) );
+    err = wait_for_completion_timeout( &pWorkInfo->completion, msecs_to_jiffies( 2000 ) );
+    if ( err == 0 ){
+        MI_ERR("wait_for_completion_timeout TIMEOUT");
+        return -1;
+    }
+
+    if (pWorkInfo->rst != 0){
+        return pWorkInfo->rst;
+    }
+    
+    return 0;
+}
+
+static int check_califolder_exist(void)
+{
+    mm_segment_t     orgfs;
+    struct  file *filep;
+        
+    orgfs = get_fs();
+    set_fs(KERNEL_DS);
+
+    filep = filp_open(OffsetFolerName, O_RDONLY, 0600);
+    if (IS_ERR(filep)) {
+        MI_ERR("%s read, sys_open %s error!!.\n",__func__,OffsetFolerName);
+        set_fs(orgfs);
+        return 0;
+    }
+
+    filp_close(filep, NULL);    
+    set_fs(orgfs); 
+
+    return 1;
+}
+
+static int support_fast_auto_cali(void)
+{
+    return in_autotest()?1:0;
+}
+
+#endif
+
+static int get_address(PLAT_HANDLE handle)
+{
+    if(NULL == handle){
+        MI_ERR("chip init failed !\n");
+		    return -1;
+    }
+			
+	return ((struct i2c_client *)handle)->addr; 		
+}
+
+unsigned int ttt_cnt = 0;
+static void mir3da_work_func(struct work_struct *work)
+{
+    short x=0,y=0,z=0;
+	struct mir3da_data *mir3da = container_of((struct delayed_work *)work,struct mir3da_data, work);
+	int map_para = 1;
+
+#if 1 //zxp				
+  if (mir3da_read_data(mir3da->mir3da_i2c_client, &x,&y,&z) != 0) {
+	  MI_ERR("MIR3DA data read failed!\n");
+  }
+  else
+  {	
+    map_para = mir3da_direction_remap(&x,&y,&z, direction_remap);
+	
+    if(bzstk)
+      z = map_para*squareRoot(1024*1024 - (x)*(x) - (y)*(y));
+	
+    input_report_abs(mir3da->input, ABS_X, x);
+    input_report_abs(mir3da->input, ABS_Y, y);
+    input_report_abs(mir3da->input, ABS_Z, z);
+    input_sync(mir3da->input); 
+  }
+#else
+	x = ttt_cnt ;
+	y = ttt_cnt + 1;
+	z = ttt_cnt + 2;
+    input_report_abs(mir3da->input, ABS_X, x);
+    input_report_abs(mir3da->input, ABS_Y, y);
+    input_report_abs(mir3da->input, ABS_Z, z);
+    input_sync(mir3da->input); 
+	ttt_cnt += 3;
+#endif  
+    schedule_delayed_work(&mir3da->work,msecs_to_jiffies(atomic_read(&mir3da->delay)));	
+}
+
+static int mir3da_misc_open(struct inode *inode, struct file *file)
+{
+	file->private_data = (struct i2c_client *)mir_handle;
+
+	if(file->private_data == NULL)
+	{
+		MI_ERR("null pointer!!\n");
+		return -EINVAL;
+	}
+	return nonseekable_open(inode, file);
+}
+/*----------------------------------------------------------------------------*/
+static int mir3da_misc_release(struct inode *inode, struct file *file)
+{
+	file->private_data = NULL;
+	return 0;
+}
+
+/*
+ * ============================================
+ *      IOCTRL interface
+ * ============================================
+ */
+static long mir3da_misc_ioctl( struct file *file,unsigned int cmd, unsigned long arg)
+{
+    void __user     *argp = (void __user *)arg;
+    int             err = 0;
+    int             interval = 0;
+    char            bEnable = 0;
+    int             z_dir = 0;
+    short           xyz[3] = {0};
+    unsigned int  step_counter = 0;	
+    int  step_status;	
+
+	struct i2c_client *client = (struct i2c_client*)file->private_data;
+	struct mir3da_data *mir3da = (struct mir3da_data*)i2c_get_clientdata(client);	
+    
+    if(_IOC_DIR(cmd) & _IOC_READ)
+    {
+        err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
+    }
+    else if(_IOC_DIR(cmd) & _IOC_WRITE)
+    {
+        err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
+    }
+
+    if(err)
+    {
+        return -EFAULT;
+    }
+
+    switch (cmd)
+    {      
+        case MIR3DA_ACC_IOCTL_GET_DELAY:
+            interval = atomic_read(&mir3da->delay);
+            if (copy_to_user(argp, &interval, sizeof(interval)))
+                return -EFAULT;
+            break;
+
+        case MIR3DA_ACC_IOCTL_SET_DELAY:
+            if (copy_from_user(&interval, argp, sizeof(interval)))
+                return -EFAULT;
+            if (interval < 0 || interval > 1000)
+                return -EINVAL;
+            if((interval <=30)&&(interval > 10))
+            {
+                interval = 10;
+            }
+			  atomic_set(&mir3da->delay, (unsigned int) interval);
+            break;
+
+        case MIR3DA_ACC_IOCTL_SET_ENABLE:
+            if (copy_from_user(&bEnable, argp, sizeof(bEnable)))
+                return -EFAULT;
+			if(bEnable)
+				ttt_cnt = 0;
+
+#if 1 //zxp			
+            err = mir3da_set_enable(client, bEnable);
+            if (err < 0)
+                return EINVAL;
+#endif
+			pr_info("[ACC]ioctl set enable: (%d) \n", bEnable);	
+				
+		        if (bEnable) {
+				        schedule_delayed_work(&mir3da->work,msecs_to_jiffies(atomic_read(&mir3da->delay)));
+		        } else {
+				        cancel_delayed_work_sync(&mir3da->work);
+			      }                
+			atomic_set(&mir3da->enable, bEnable);	              
+            break;
+
+        case MIR3DA_ACC_IOCTL_GET_ENABLE:        
+            err = mir3da_get_enable(client, &bEnable);
+            if (err < 0){
+                return -EINVAL;
+            }
+
+            if (copy_to_user(argp, &bEnable, sizeof(bEnable)))
+                    return -EINVAL;            
+            break;
+
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+        case MIR3DA_ACC_IOCTL_CALIBRATION:
+            if(copy_from_user(&z_dir, argp, sizeof(z_dir)))
+                return -EFAULT;
+            
+            if(mir3da_calibrate(client, z_dir)) {
+                return -EFAULT;
+            } 
+
+            if(copy_to_user(argp, &z_dir, sizeof(z_dir)))
+                return -EFAULT;
+            break;        
+
+        case MIR3DA_ACC_IOCTL_UPDATE_OFFSET:
+            manual_load_cali_file(client);
+            break;
+#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */ 
+
+        case MIR3DA_ACC_IOCTL_GET_COOR_XYZ:
+
+            if(mir3da_read_data(client, &xyz[0],&xyz[1],&xyz[2]))
+                return -EFAULT;        
+
+            if(copy_to_user((void __user *)arg, xyz, sizeof(xyz)))
+                return -EFAULT;
+            break;
+
+        case MIR3DA_ACC_IOCTL_SET_STEP_ENABLE:
+
+			if (copy_from_user(&bEnable, argp, sizeof(bEnable)))
+                return -EFAULT;      
+
+            err = mir3da_set_step_enable(client, bEnable);
+            if (err < 0)
+                return -EINVAL;
+            break;
+
+        case MIR3DA_ACC_IOCTL_GET_STEP_ENABLE:
+			
+            err = mir3da_get_step_enable(client, &bEnable);
+            if (err < 0){
+                return -EINVAL;
+            }
+
+            if (copy_to_user(argp, &bEnable, sizeof(bEnable)))
+            	return -EFAULT;            
+            break;
+
+		/* get step counter */	
+        case MIR3DA_ACC_IOCTL_GET_STEP_COUNTER:
+
+            if(mir3da_read_step_counter(client, &step_counter))
+                return -EFAULT;
+			
+			mir3da_reset_step_counter(client);/*reset step counter*/
+
+            if(copy_to_user((void __user *)arg, &step_counter, sizeof(step_counter)))
+                return -EFAULT;
+            break;
+
+		/* get step status */	
+        case MIR3DA_ACC_IOCTL_GET_STEP_STATUS:
+
+            step_status = mir3da_read_step_status(client);
+			if(step_status < 0)
+                return -EFAULT;        
+
+            if(copy_to_user((void __user *)arg, step_status, sizeof(step_status)))
+                return -EFAULT;
+            break;
+
+        default:
+            return -EINVAL;
+    }
+
+    return 0;
+}
+
+/* Misc device interface*/
+static const struct file_operations mir3da_misc_fops = {
+        .owner = THIS_MODULE,
+		.open = mir3da_misc_open,
+		.release = mir3da_misc_release,					
+        .unlocked_ioctl = mir3da_misc_ioctl,
+};
+
+static struct miscdevice misc_mir3da = {
+        .minor = MISC_DYNAMIC_MINOR,
+        .name = MIR3DA_MISC_NAME,
+        .fops = &mir3da_misc_fops,
+};
+
+
+static ssize_t mir3da_enable_show(struct device *dev,
+                   struct device_attribute *attr, char *buf)
+{
+    int             ret;
+    char            bEnable;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct mir3da_data *mir3da = i2c_get_clientdata(client);
+    
+    ret = mir3da_get_enable(mir3da->mir3da_i2c_client, &bEnable);    
+    if (ret < 0){
+        ret = -EINVAL;
+    }
+    else{
+        ret = sprintf(buf, "%d\n", bEnable);
+    }
+
+    return ret;
+}
+
+static ssize_t mir3da_enable_store(struct device *dev,
+                    struct device_attribute *attr,
+                    const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct mir3da_data *mir3da = i2c_get_clientdata(client);
+    int pre_enable = atomic_read(&mir3da->enable);
+    int bEnable;
+
+    if (buf == NULL){
+        return -1;
+    }
+
+    bEnable = (simple_strtoul(buf, NULL, 10) > 0) ? 1 : 0;
+	MI_MSG("enable = %d\n",bEnable);	
+	mutex_lock(&mir3da->enable_mutex);
+/*	if(in_autotest()){
+	   if(mir3da_set_enable(mir3da->mir3da_i2c_client, 1) < 0)
+		  return -EINVAL;
+	
+	    schedule_delayed_work(&mir3da->work,msecs_to_jiffies(atomic_read(&mir3da->delay)));
+
+	}else*/{
+    if (bEnable != pre_enable) {
+
+		if(mir3da_set_enable(mir3da->mir3da_i2c_client, bEnable) < 0)
+			return -EINVAL;
+
+	    if (bEnable) {
+			  schedule_delayed_work(&mir3da->work,msecs_to_jiffies(atomic_read(&mir3da->delay)));
+	    } else {
+			cancel_delayed_work_sync(&mir3da->work);
+		}
+
+        atomic_set(&mir3da->enable, bEnable);			
+	}		
+	}
+
+	mutex_unlock(&mir3da->enable_mutex);
+
+    return count;
+}
+
+static ssize_t mir3da_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+    struct i2c_client *client = to_i2c_client(dev);
+    struct mir3da_data *mir3da = i2c_get_clientdata(client);
+		
+    return sprintf(buf, "%d\n", atomic_read(&mir3da->delay));
+}
+
+static ssize_t mir3da_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+    unsigned long data=0;
+    int error=0;
+    struct i2c_client *client = to_i2c_client(dev);
+    struct mir3da_data *mir3da = i2c_get_clientdata(client);
+
+    error = strict_strtoul(buf, 10, &data);
+    if (error)
+        return error;
+
+    atomic_set(&mir3da->delay, (unsigned int) data);
+
+    return count;		
+}
+
+static ssize_t mir3da_axis_data_show(struct device *dev,
+           struct device_attribute *attr, char *buf)
+{
+    int result;
+    short x,y,z;
+    int count = 0;
+    struct i2c_client *client = to_i2c_client(dev);
+    struct mir3da_data *mir3da = i2c_get_clientdata(client);
+		
+    result = mir3da_read_data(mir3da->mir3da_i2c_client, &x, &y, &z);
+    if (result == 0)
+        count += sprintf(buf+count, "x= %d;y=%d;z=%d\n", x,y,z);
+    else
+        count += sprintf(buf+count, "reading failed!");
+
+    return count;
+}
+#if 0
+static ssize_t mir3da_odr_show(struct device *dev,
+                   struct device_attribute *attr, char *buf)
+{
+    int ret;
+    int odr; 
+    
+    //ret = mir3da_get_odr(&odr);
+    if (ret < 0){
+        ret = -EINVAL;
+    }else{
+        ret = sprintf(buf, "%d\n", odr);
+    }
+    
+    return ret;
+}
+
+static ssize_t mir3da_odr_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
+{
+    int ret;
+    int odr;
+    
+    sscanf(buf, "%d\n", &odr);
+    
+    //ret = mir3da_set_odr(odr);
+    if (ret < 0){
+        ret = -EINVAL;
+    }else{
+        ret = count;
+    }
+    
+    return ret;
+}
+#endif
+static ssize_t mir3da_reg_data_store(struct device *dev,
+           struct device_attribute *attr, const char *buf, size_t count)
+{
+    unsigned int                 addr, data;
+    int                 result;
+    struct i2c_client *client = to_i2c_client(dev);
+    struct mir3da_data *mir3da = i2c_get_clientdata(client);
+		
+    sscanf(buf, "0x%x, 0x%x\n", &addr, &data);
+
+	printk("addr[0x%x] data[0x%x]\n",addr,data);
+    
+    result = mir3da_register_write(mir3da->mir3da_i2c_client, addr, data);
+    
+    MI_ASSERT(result==0);
+
+    return count;
+}
+
+static ssize_t mir3da_reg_data_show(struct device *dev,
+           struct device_attribute *attr, char *buf)
+{
+    struct i2c_client *client = to_i2c_client(dev);
+    struct mir3da_data *mir3da = i2c_get_clientdata(client);
+		
+    return mir3da_get_reg_data(mir3da->mir3da_i2c_client, buf);
+}
+
+static ssize_t mir3da_step_show(struct device *dev,
+                   struct device_attribute *attr, char *buf)
+{
+    int           ret = 0;
+    unsigned int  step_counter = 0;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct mir3da_data *mir3da = i2c_get_clientdata(client);
+    
+    ret = mir3da_read_step_counter(mir3da->mir3da_i2c_client, &step_counter);    
+    if (ret < 0){
+        ret = -EINVAL;
+    }
+    else{
+        ret = sprintf(buf, "%d\n", step_counter);
+    }
+
+    return ret;
+}
+
+static ssize_t mir3da_step_store(struct device *dev,
+                    struct device_attribute *attr,
+                    const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct mir3da_data *mir3da = i2c_get_clientdata(client);
+    int bEnable;
+
+    if (buf == NULL){
+        return -1;
+    }
+
+    bEnable = (simple_strtoul(buf, NULL, 10) > 0) ? 1 : 0;
+	MI_MSG("enable = %d\n",bEnable);
+
+	if(mir3da_set_step_enable(mir3da->mir3da_i2c_client, bEnable) < 0)
+		return -EINVAL;
+
+    return count;
+}
+
+
+#if FILTER_AVERAGE_ENHANCE
+static ssize_t mir3da_average_enhance_show(struct device *dev,
+                   struct device_attribute *attr, char *buf)
+{
+    int                             ret = 0;
+    struct mir3da_filter_param_s    param = {0};
+
+    ret = mir3da_get_filter_param(&param);
+    ret |= sprintf(buf, "%d %d %d\n", param.filter_param_l, param.filter_param_h, param.filter_threhold);
+
+    return ret;
+}
+
+static ssize_t mir3da_average_enhance_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
+{ 
+    int                             ret = 0;
+    struct mir3da_filter_param_s    param = {0};
+    
+    sscanf(buf, "%d %d %d\n", &param.filter_param_l, &param.filter_param_h, &param.filter_threhold);
+    
+    ret = mir3da_set_filter_param(&param);
+    
+    return count;
+}
+#endif //FILTER_AVERAGE_ENHANCE
+
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+static ssize_t mir3da_offset_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+    ssize_t count = 0;
+    
+    if(bLoad==FILE_EXIST)
+    	count += sprintf(buf,"%s",m_work_info.buffer);   
+    else
+    	count += sprintf(buf,"%s","Calibration file not exist!\n");
+
+    return count;
+}     
+
+int bCaliResult = -1;
+static ssize_t mir3da_calibrate_show(struct device *dev,struct device_attribute *attr,char *buf)
+{
+    int ret;       
+
+    ret = sprintf(buf, "%d\n", bCaliResult);   
+    return ret;
+}
+
+static ssize_t mir3da_calibrate_store(struct device *dev,
+                    struct device_attribute *attr,
+                    const char *buf, size_t count)
+{
+    s8              z_dir = 0;
+    struct i2c_client *client = to_i2c_client(dev);
+    struct mir3da_data *mir3da = i2c_get_clientdata(client);
+		
+    z_dir = simple_strtol(buf, NULL, 10);
+    bCaliResult = mir3da_calibrate(mir3da->mir3da_i2c_client, z_dir);
+    
+    return count;
+}
+#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */
+
+static ssize_t mir3da_log_level_show(struct device *dev,
+                   struct device_attribute *attr, char *buf)
+{
+    int ret;
+
+    ret = sprintf(buf, "%d\n", Log_level);
+
+    return ret;
+}
+
+static ssize_t mir3da_log_level_store(struct device *dev,
+                    struct device_attribute *attr,
+                    const char *buf, size_t count)
+{
+    Log_level = simple_strtoul(buf, NULL, 10);    
+
+    return count;
+}
+
+static ssize_t mir3da_direction_remap_show(struct device *dev,
+                   struct device_attribute *attr, char *buf)
+{
+    int ret;
+
+    ret = sprintf(buf, "%d\n", direction_remap);
+
+    return ret;
+}
+
+static ssize_t mir3da_direction_remap_store(struct device *dev,
+                    struct device_attribute *attr,
+                    const char *buf, size_t count)
+{
+    direction_remap = simple_strtoul(buf, NULL, 10);    
+
+    return count;
+}
+
+static ssize_t mir3da_primary_offset_show(struct device *dev,
+                   struct device_attribute *attr, char *buf){    
+    struct i2c_client *client = to_i2c_client(dev);
+    struct mir3da_data *mir3da = i2c_get_clientdata(client);
+    int x=0,y=0,z=0;
+   
+    mir3da_get_primary_offset(mir3da->mir3da_i2c_client,&x,&y,&z);
+
+	return sprintf(buf, "x=%d ,y=%d ,z=%d\n",x,y,z);
+
+}
+
+static ssize_t mir3da_version_show(struct device *dev,
+                   struct device_attribute *attr, char *buf){    
+
+	return sprintf(buf, "%s_%s\n", DRI_VER, CORE_VER);
+
+}
+
+static ssize_t mir3da_vendor_show(struct device *dev,
+                   struct device_attribute *attr, char *buf){
+	return sprintf(buf, "%s\n", "MiraMEMS");
+}
+
+static DEVICE_ATTR(enable,          S_IRUGO | S_IWUGO,  mir3da_enable_show,             mir3da_enable_store);
+static DEVICE_ATTR(poll_delay,      S_IRUGO | S_IWUGO,  mir3da_delay_show,              mir3da_delay_store);
+static DEVICE_ATTR(axis_data,       S_IRUGO,            mir3da_axis_data_show,          NULL);
+static DEVICE_ATTR(reg_data,        S_IWUGO | S_IRUGO,  mir3da_reg_data_show,           mir3da_reg_data_store);
+static DEVICE_ATTR(log_level,       S_IWUGO | S_IRUGO,  mir3da_log_level_show,          mir3da_log_level_store);
+static DEVICE_ATTR(direction_remap, S_IWUGO | S_IRUGO,  mir3da_direction_remap_show,    mir3da_direction_remap_store);
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+static DEVICE_ATTR(offset,          S_IWUGO | S_IRUGO,  mir3da_offset_show,             NULL);
+static DEVICE_ATTR(calibrate_miraGSensor,       S_IWUGO | S_IRUGO,  mir3da_calibrate_show,          mir3da_calibrate_store);
+#endif
+#if FILTER_AVERAGE_ENHANCE
+static DEVICE_ATTR(average_enhance, S_IWUGO | S_IRUGO,  mir3da_average_enhance_show,    mir3da_average_enhance_store);
+#endif /* ! FILTER_AVERAGE_ENHANCE */
+static DEVICE_ATTR(primary_offset,  S_IRUGO,            mir3da_primary_offset_show,     NULL);
+static DEVICE_ATTR(version,         S_IRUGO,            mir3da_version_show,            NULL);
+static DEVICE_ATTR(vendor,          S_IRUGO,            mir3da_vendor_show,             NULL); 
+static DEVICE_ATTR(step,          	S_IRUGO | S_IWUGO,  mir3da_step_show,             mir3da_step_store);
+
+static struct attribute *mir3da_attributes[] = { 
+    &dev_attr_enable.attr,
+    &dev_attr_poll_delay.attr,		/* delay work, unit is ms */
+    &dev_attr_axis_data.attr,
+    &dev_attr_reg_data.attr,
+    &dev_attr_log_level.attr,
+	&dev_attr_direction_remap.attr,	/* no use */
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+    &dev_attr_offset.attr,    
+    &dev_attr_calibrate_miraGSensor.attr,
+#endif
+#if FILTER_AVERAGE_ENHANCE
+    &dev_attr_average_enhance.attr,
+#endif /* ! FILTER_AVERAGE_ENHANCE */
+    &dev_attr_primary_offset.attr,	/* no use */
+    &dev_attr_version.attr,
+    &dev_attr_vendor.attr,
+    &dev_attr_step.attr,
+    NULL
+};
+
+/********************************************** MIR private start ****************************************/
+/* sys/devices/virtule/input/input1 */
+static const struct attribute_group mir3da_attr_group = {
+    //.name   = "mir3da",
+    .attrs  = mir3da_attributes,
+};
+
+int i2c_smbus_read(PLAT_HANDLE handle, u8 addr, u8 *data)
+{
+    int                 res = 0;
+    struct i2c_client   *client = (struct i2c_client*)handle;
+    
+    *data = i2c_smbus_read_byte_data(client, addr);
+    
+    return res;
+}
+
+int i2c_smbus_read_block(PLAT_HANDLE handle, u8 addr, u8 count, u8 *data)
+{
+    int                 res = 0;
+    struct i2c_client   *client = (struct i2c_client*)handle;
+    
+    res = i2c_smbus_read_i2c_block_data(client, addr, count, data);
+    
+    return res;
+}
+
+int i2c_smbus_write(PLAT_HANDLE handle, u8 addr, u8 data)
+{
+    int                 res = 0;
+    struct i2c_client   *client = (struct i2c_client*)handle;
+    
+    res = i2c_smbus_write_byte_data(client, addr, data);
+    
+    return res;
+}
+
+void msdelay(int ms)
+{
+    mdelay(ms);
+}
+
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+MIR_GENERAL_OPS_DECLARE(ops_handle, i2c_smbus_read, i2c_smbus_read_block, i2c_smbus_write, sensor_sync_write, sensor_sync_read, check_califolder_exist,get_address,support_fast_auto_cali,msdelay, printk, sprintf);
+#else
+MIR_GENERAL_OPS_DECLARE(ops_handle, i2c_smbus_read, i2c_smbus_read_block, i2c_smbus_write, NULL, NULL, NULL,get_address,NULL,msdelay, printk, sprintf);
+#endif
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void mir3da_early_suspend(struct early_suspend *h)
+{
+	struct mir3da_data *mir3da = container_of(h, struct mir3da_data, early_suspend);   
+    	int result;
+
+    MI_FUN;	
+
+   result = mir3da_set_enable(mir3da->mir3da_i2c_client, false);
+    if(result) {
+	        MI_ERR("%s: disable fail!!\n",__func__);	
+            return;
+     }    
+    cancel_delayed_work_sync(&mir3da->work);
+}
+
+static void mir3da_late_resume(struct early_suspend *h)
+{
+	struct mir3da_data *mir3da = container_of(h, struct mir3da_data, early_suspend);   
+	int pre_enable;
+    	int result;
+		
+    mir3da_chip_resume(mir3da->mir3da_i2c_client);
+  	
+	pre_enable = atomic_read(&mir3da->enable);
+    result = mir3da_set_enable(mir3da->mir3da_i2c_client, pre_enable);
+    if(result) {
+	        MI_ERR("%s: disable fail!!\n",__func__);	
+            return;
+     }    
+    if (pre_enable) {
+		schedule_delayed_work(&mir3da->work,msecs_to_jiffies(atomic_read(&mir3da->delay))); 
+	}
+}
+#endif
+
+
+/******************************************* MIR private end **************************************************/
+
+static int /*__devinit */mir3da_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+    int                 result = 0;
+    struct input_dev    *idev;
+    struct i2c_adapter  *adapter;
+	struct mir3da_data *mir3da;
+	unsigned char chip_id=0;
+	unsigned char i=0;
+
+	MI_FUN;
+
+    adapter = to_i2c_adapter(client->dev.parent);
+    result = i2c_check_functionality(adapter,
+                     I2C_FUNC_SMBUS_BYTE |
+                     I2C_FUNC_SMBUS_BYTE_DATA);
+    MI_ASSERT(result);  
+	
+	mir3da_install_general_ops(&ops_handle);
+
+	mir3da = kzalloc(sizeof(struct mir3da_data), GFP_KERNEL);
+	if (!mir3da) {
+		result = -ENOMEM;
+		goto err_detach_client;
+	}
+	zx29_mir3da = mir3da;
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+    m_work_info.wq = create_singlethread_workqueue( "oo" );
+    if(NULL==m_work_info.wq) {
+        MI_ERR("Failed to create workqueue !");
+        goto err_detach_client;
+    }
+    
+    INIT_DELAYED_WORK( &m_work_info.read_work, sensor_read_work );
+    INIT_DELAYED_WORK( &m_work_info.write_work, sensor_write_work );
+#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */
+
+#if 1 //zxp
+	i2c_smbus_read((PLAT_HANDLE) client, NSA_REG_WHO_AM_I, &chip_id);	
+	if(chip_id != 0x13){
+        for(i=0;i<5;i++){
+			mdelay(5); 
+		    i2c_smbus_read((PLAT_HANDLE) client, NSA_REG_WHO_AM_I, &chip_id);
+            if(chip_id == 0x13)
+                break;				
+		}
+		if(i == 5)
+	        client->addr = 0x27;
+	}		
+    
+    /* Initialize the MIR3DA chip */
+    mir_handle = mir3da_core_init((PLAT_HANDLE)client);
+    if(NULL == mir_handle){
+        MI_ERR("chip init failed !\n");
+        goto err_detach_client;        
+    }
+#else
+	mir_handle = (PLAT_HANDLE)client;
+#endif	
+  
+	direction_remap = MIR3DA_DIRECTION_NUM;
+	
+	i2c_set_clientdata(client, mir3da);
+	mir3da->mir3da_i2c_client = client;
+
+	mutex_init(&mir3da->enable_mutex);
+	atomic_set(&mir3da->enable, 0);
+	atomic_set(&mir3da->delay, DELAY_INTERVAL);
+
+    /* input poll device register */
+    idev = input_allocate_device();
+    if (!idev) {
+        MI_ERR("alloc poll device failed!\n");
+        result = -ENOMEM;
+        goto err_hwmon_device_unregister;
+    }
+
+    idev->name = MIR3DA_INPUT_DEV_NAME;   
+    idev->id.bustype = BUS_I2C;
+    idev->evbit[0] = BIT_MASK(EV_ABS);
+
+	input_set_abs_params(idev, ABS_X, -2048, 2048, 0, 0);
+	input_set_abs_params(idev, ABS_Y, -2048, 2048, 0, 0);
+	input_set_abs_params(idev, ABS_Z, -2048, 2048, 0, 0);  
+
+	input_set_drvdata(idev, mir3da);
+
+    result = input_register_device(idev);
+    if (result) {
+        MI_ERR("register poll device failed!\n");
+        goto err_free_device; 
+    }
+
+    mir3da->input= idev;
+
+	INIT_DELAYED_WORK(&mir3da->work, mir3da_work_func);
+    /* Sys Attribute Register */
+    result = sysfs_create_group(&mir3da->input->dev.kobj, &mir3da_attr_group);
+    if (result) {
+        MI_ERR("create device file failed!\n");
+        result = -EINVAL;
+        goto err_unregister_device;
+    }
+
+    /* Misc device interface Register */
+    result = misc_register(&misc_mir3da);
+    if (result) {
+        MI_ERR("%s: mir3da_dev register failed", __func__);
+        goto err_remove_sysfs_group;
+    }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	mir3da->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	mir3da->early_suspend.suspend = mir3da_early_suspend;
+	mir3da->early_suspend.resume = mir3da_late_resume;
+	register_early_suspend(&mir3da->early_suspend);
+#endif
+		
+    return result;
+
+err_remove_sysfs_group:
+    sysfs_remove_group(&mir3da->input->dev.kobj, &mir3da_attr_group);    
+err_unregister_device:
+    input_unregister_device(mir3da->input);
+err_free_device:
+    input_free_device(mir3da->input);
+err_hwmon_device_unregister:
+    //hwmon_device_unregister(&client->dev);    
+err_detach_client:
+    //i2c_unregister_device(client);
+    return result;
+}
+
+static int /*__devexit */ mir3da_remove(struct i2c_client *client)
+{
+    struct mir3da_data *mir3da = i2c_get_clientdata(client);
+    int result = 0;
+
+    MI_FUN;
+
+   result=  mir3da_set_enable(mir3da->mir3da_i2c_client, 0);
+    if(result) {
+	        MI_ERR("%s: disable fail!!\n",__func__);	
+            return result;
+     }
+	
+    misc_deregister(&misc_mir3da);
+    
+    sysfs_remove_group(&mir3da->input->dev.kobj, &mir3da_attr_group);
+    
+    input_unregister_device(mir3da->input);
+    
+    input_free_device(mir3da->input);
+    
+#if MIR3DA_OFFSET_TEMP_SOLUTION
+    cancel_delayed_work_sync(&mir3da->work);
+
+    flush_workqueue(m_work_info.wq);
+
+    destroy_workqueue(m_work_info.wq);
+#endif /* !MIR3DA_OFFSET_TEMP_SOLUTION */
+    //hwmon_device_unregister(hwmon_dev);
+
+    return 0;
+}
+
+static int mir3da_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+    int result = 0;
+    struct mir3da_data *mir3da = i2c_get_clientdata(client);
+
+    MI_FUN;	
+
+    result = mir3da_set_enable(mir3da->mir3da_i2c_client, false);
+    if(result) {
+	        MI_ERR("%s: disable fail!!\n",__func__);	
+            return result;
+     }
+     
+    cancel_delayed_work_sync(&mir3da->work);
+    return result;
+}
+
+static int mir3da_resume(struct i2c_client *client)
+{
+    int result = 0;
+    struct mir3da_data *mir3da = i2c_get_clientdata(client);
+	int pre_enable;
+
+    MI_FUN;			
+    
+    result = mir3da_chip_resume(mir3da->mir3da_i2c_client);
+    if(result) {
+		MI_ERR("chip resume fail!!\n");
+		return result;
+    }
+
+	pre_enable = atomic_read(&mir3da->enable);
+	
+    result = mir3da_set_enable(mir3da->mir3da_i2c_client, pre_enable);
+    if(result) {
+	     MI_ERR("%s: enable fail!!\n",__func__);		
+            return result;
+     }
+     
+     if (pre_enable) {
+		schedule_delayed_work(&mir3da->work,msecs_to_jiffies(atomic_read(&mir3da->delay))); 
+	 }
+		
+    return result;
+}
+
+static int mir3da_detect(struct i2c_client *new_client,
+		       struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = new_client->adapter;
+
+      MI_MSG("adapter->NR = %d\n", adapter->nr);
+      MI_MSG(">>> mir3da_detect, new_client->addr = 0x%x\n", new_client->addr);
+
+      if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+       MI_MSG("info.type 1 = %s\n", info->type);
+       strlcpy(info->type, "da311", I2C_NAME_SIZE);
+       //strlcpy(info->type, MIR3DA_DRV_NAME, I2C_NAME_SIZE);
+
+       MI_MSG("info.type 2 = %s\n", info->type);
+       return 0;
+}
+
+static const struct i2c_device_id mir3da_id[] = {
+    { MIR3DA_DRV_NAME, 0 },
+    { }
+};
+
+MODULE_DEVICE_TABLE(i2c, mir3da_id);
+
+static const unsigned short normal_i2c[] = { 0x27,  0x26,I2C_CLIENT_END };
+static const struct of_device_id mir3da_of_match[] = {
+       { .compatible = "da,da213", },
+        {}
+};
+
+static struct i2c_driver mir3da_driver = {
+    .driver = {
+        .name    = MIR3DA_DRV_NAME,
+        .owner    = THIS_MODULE,
+        .of_match_table = mir3da_of_match,
+    },
+
+    .probe    = mir3da_probe,
+    .remove    = /*__devexit_p*/(mir3da_remove),
+    .id_table = mir3da_id,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+    .suspend  = mir3da_suspend,
+    .resume = mir3da_resume,
+#endif
+    .detect		= mir3da_detect,
+    .address_list	= normal_i2c,
+};
+
+/* comment this if you register this in board info */
+#if  DEVICE_CREATE_MODE == DEVICE_CREATE_BYSELF
+static int i2c_static_add_device(struct i2c_board_info *info)
+{
+    struct i2c_adapter *adapter;
+    struct i2c_client  *client;
+    int    ret;
+
+    adapter = i2c_get_adapter(I2C_STATIC_BUS_NUM);
+    if (!adapter) {
+        MI_ERR("%s: can't get i2c adapter\n", __func__);
+        ret = -ENODEV;
+        goto i2c_err;
+    }
+
+    client = i2c_new_device(adapter, info);
+    if (!client) {
+        MI_ERR("%s:  can't add i2c device at 0x%x\n", __FUNCTION__, (unsigned int)info->addr);
+        ret = -ENODEV;
+        goto i2c_err;
+    }
+
+    i2c_put_adapter(adapter);
+	mir3da_client = client;
+    return 0;
+
+i2c_err:
+    return ret;
+}
+#endif /* MODULE */ 
+
+static int __init mir3da_init(void)
+{    
+    int res;
+
+#if  DEVICE_CREATE_MODE == DEVICE_CREATE_BYSELF
+    res = i2c_static_add_device(&mir3da_i2c_boardinfo);
+    if (res < 0) {
+        MI_ERR("%s: add i2c device error %d\n", __func__, res);
+        return (res);
+    }
+#endif 
+
+    res = i2c_add_driver(&mir3da_driver);
+    if (res < 0){
+        MI_ERR("add mir3da i2c driver failed\n");
+        return -ENODEV;
+    }
+    MI_MSG("add mir3da i2c driver\n");
+    return (res);
+}
+
+static void __exit mir3da_exit(void)
+{
+   MI_FUN;
+
+#if  DEVICE_CREATE_MODE == DEVICE_CREATE_BYSELF
+    MI_MSG("unregister i2c device.\n");
+
+	if (mir_handle != NULL){
+    i2c_unregister_device((struct i2c_client *)mir_handle);
+}
+#endif
+
+    MI_MSG("remove mir3da i2c driver.\n");
+    i2c_del_driver(&mir3da_driver);
+}
+
+
+MODULE_AUTHOR("MiraMEMS <lschen@miramems.com>");
+MODULE_DESCRIPTION("MIR3DA 3-Axis Accelerometer driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+
+module_init(mir3da_init);
+module_exit(mir3da_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_cust.h b/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_cust.h
new file mode 100755
index 0000000..0a9dafc
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/mir3da/mir3da_cust.h
@@ -0,0 +1,49 @@
+/* For PLATFORM STANDARD
+ *
+ * mir3da.h - Linux kernel modules for 3-Axis Accelerometer
+ *
+ * Copyright (C) 2011-2013 MiraMEMS Sensing Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 __MIR3DA_STANDARD_H__
+#define __MIR3DA_STANDARD_H__
+	 
+#include <linux/ioctl.h>
+
+/* driver version info*/
+#define DRI_VER                                 "1.0"
+
+#define MIR3DA_I2C_ADDR		                    0x26//0x26<-> SD0=GND;0x27<-> SD0=High
+#define MIR3DA_DIRECTION_NUM					0   //0 ~ 7
+
+#define MIR3DA_ACC_IOCTL_BASE                   88
+#define IOCTL_INDEX_BASE                        0x00
+
+#define MIR3DA_ACC_IOCTL_SET_DELAY              _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE, int)
+#define MIR3DA_ACC_IOCTL_GET_DELAY              _IOR(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+1, int)
+#define MIR3DA_ACC_IOCTL_SET_ENABLE             _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+2, int)
+#define MIR3DA_ACC_IOCTL_GET_ENABLE             _IOR(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+3, int)
+#define MIR3DA_ACC_IOCTL_SET_G_RANGE            _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+4, int)
+#define MIR3DA_ACC_IOCTL_GET_G_RANGE            _IOR(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+5, int)
+
+#define MIR3DA_ACC_IOCTL_GET_COOR_XYZ           _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+22, int)
+#define MIR3DA_ACC_IOCTL_CALIBRATION            _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+23, int)
+#define MIR3DA_ACC_IOCTL_UPDATE_OFFSET     	    _IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+24, int)
+
+#define MIR3DA_ACC_IOCTL_SET_STEP_ENABLE		_IOW(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+31, int)
+#define MIR3DA_ACC_IOCTL_GET_STEP_ENABLE		_IOR(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+32, int)
+#define MIR3DA_ACC_IOCTL_GET_STEP_COUNTER		_IOR(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+33, int)
+#define MIR3DA_ACC_IOCTL_GET_STEP_STATUS		_IOR(MIR3DA_ACC_IOCTL_BASE, IOCTL_INDEX_BASE+34, int)
+#endif /* !__MIR3DA_STANDARD_H__ */
+
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/mma8450.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/mma8450.c
new file mode 100644
index 0000000..873ebce
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/mma8450.c
@@ -0,0 +1,254 @@
+/*
+ *  Driver for Freescale's 3-Axis Accelerometer MMA8450
+ *
+ *  Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input-polldev.h>
+#include <linux/of_device.h>
+
+#define MMA8450_DRV_NAME	"mma8450"
+
+#define MODE_CHANGE_DELAY_MS	100
+#define POLL_INTERVAL		100
+#define POLL_INTERVAL_MAX	500
+
+/* register definitions */
+#define MMA8450_STATUS		0x00
+#define MMA8450_STATUS_ZXYDR	0x08
+
+#define MMA8450_OUT_X8		0x01
+#define MMA8450_OUT_Y8		0x02
+#define MMA8450_OUT_Z8		0x03
+
+#define MMA8450_OUT_X_LSB	0x05
+#define MMA8450_OUT_X_MSB	0x06
+#define MMA8450_OUT_Y_LSB	0x07
+#define MMA8450_OUT_Y_MSB	0x08
+#define MMA8450_OUT_Z_LSB	0x09
+#define MMA8450_OUT_Z_MSB	0x0a
+
+#define MMA8450_XYZ_DATA_CFG	0x16
+
+#define MMA8450_CTRL_REG1	0x38
+#define MMA8450_CTRL_REG2	0x39
+
+/* mma8450 status */
+struct mma8450 {
+	struct i2c_client	*client;
+	struct input_polled_dev	*idev;
+};
+
+static int mma8450_read(struct mma8450 *m, unsigned off)
+{
+	struct i2c_client *c = m->client;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(c, off);
+	if (ret < 0)
+		dev_err(&c->dev,
+			"failed to read register 0x%02x, error %d\n",
+			off, ret);
+
+	return ret;
+}
+
+static int mma8450_write(struct mma8450 *m, unsigned off, u8 v)
+{
+	struct i2c_client *c = m->client;
+	int error;
+
+	error = i2c_smbus_write_byte_data(c, off, v);
+	if (error < 0) {
+		dev_err(&c->dev,
+			"failed to write to register 0x%02x, error %d\n",
+			off, error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int mma8450_read_block(struct mma8450 *m, unsigned off,
+			      u8 *buf, size_t size)
+{
+	struct i2c_client *c = m->client;
+	int err;
+
+	err = i2c_smbus_read_i2c_block_data(c, off, size, buf);
+	if (err < 0) {
+		dev_err(&c->dev,
+			"failed to read block data at 0x%02x, error %d\n",
+			MMA8450_OUT_X_LSB, err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void mma8450_poll(struct input_polled_dev *dev)
+{
+	struct mma8450 *m = dev->private;
+	int x, y, z;
+	int ret;
+	u8 buf[6];
+
+	ret = mma8450_read(m, MMA8450_STATUS);
+	if (ret < 0)
+		return;
+
+	if (!(ret & MMA8450_STATUS_ZXYDR))
+		return;
+
+	ret = mma8450_read_block(m, MMA8450_OUT_X_LSB, buf, sizeof(buf));
+	if (ret < 0)
+		return;
+
+	x = ((buf[1] << 4) & 0xff0) | (buf[0] & 0xf);
+	y = ((buf[3] << 4) & 0xff0) | (buf[2] & 0xf);
+	z = ((buf[5] << 4) & 0xff0) | (buf[4] & 0xf);
+
+	input_report_abs(dev->input, ABS_X, x);
+	input_report_abs(dev->input, ABS_Y, y);
+	input_report_abs(dev->input, ABS_Z, z);
+	input_sync(dev->input);
+}
+
+/* Initialize the MMA8450 chip */
+static void mma8450_open(struct input_polled_dev *dev)
+{
+	struct mma8450 *m = dev->private;
+	int err;
+
+	/* enable all events from X/Y/Z, no FIFO */
+	err = mma8450_write(m, MMA8450_XYZ_DATA_CFG, 0x07);
+	if (err)
+		return;
+
+	/*
+	 * Sleep mode poll rate - 50Hz
+	 * System output data rate - 400Hz
+	 * Full scale selection - Active, +/- 2G
+	 */
+	err = mma8450_write(m, MMA8450_CTRL_REG1, 0x01);
+	if (err < 0)
+		return;
+
+	msleep(MODE_CHANGE_DELAY_MS);
+}
+
+static void mma8450_close(struct input_polled_dev *dev)
+{
+	struct mma8450 *m = dev->private;
+
+	mma8450_write(m, MMA8450_CTRL_REG1, 0x00);
+	mma8450_write(m, MMA8450_CTRL_REG2, 0x01);
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static int __devinit mma8450_probe(struct i2c_client *c,
+				   const struct i2c_device_id *id)
+{
+	struct input_polled_dev *idev;
+	struct mma8450 *m;
+	int err;
+
+	m = kzalloc(sizeof(struct mma8450), GFP_KERNEL);
+	idev = input_allocate_polled_device();
+	if (!m || !idev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	m->client = c;
+	m->idev = idev;
+
+	idev->private		= m;
+	idev->input->name	= MMA8450_DRV_NAME;
+	idev->input->id.bustype	= BUS_I2C;
+	idev->poll		= mma8450_poll;
+	idev->poll_interval	= POLL_INTERVAL;
+	idev->poll_interval_max	= POLL_INTERVAL_MAX;
+	idev->open		= mma8450_open;
+	idev->close		= mma8450_close;
+
+	__set_bit(EV_ABS, idev->input->evbit);
+	input_set_abs_params(idev->input, ABS_X, -2048, 2047, 32, 32);
+	input_set_abs_params(idev->input, ABS_Y, -2048, 2047, 32, 32);
+	input_set_abs_params(idev->input, ABS_Z, -2048, 2047, 32, 32);
+
+	err = input_register_polled_device(idev);
+	if (err) {
+		dev_err(&c->dev, "failed to register polled input device\n");
+		goto err_free_mem;
+	}
+
+	return 0;
+
+err_free_mem:
+	input_free_polled_device(idev);
+	kfree(m);
+	return err;
+}
+
+static int __devexit mma8450_remove(struct i2c_client *c)
+{
+	struct mma8450 *m = i2c_get_clientdata(c);
+	struct input_polled_dev *idev = m->idev;
+
+	input_unregister_polled_device(idev);
+	input_free_polled_device(idev);
+	kfree(m);
+
+	return 0;
+}
+
+static const struct i2c_device_id mma8450_id[] = {
+	{ MMA8450_DRV_NAME, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, mma8450_id);
+
+static const struct of_device_id mma8450_dt_ids[] = {
+	{ .compatible = "fsl,mma8450", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mma8450_dt_ids);
+
+static struct i2c_driver mma8450_driver = {
+	.driver = {
+		.name	= MMA8450_DRV_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = mma8450_dt_ids,
+	},
+	.probe		= mma8450_probe,
+	.remove		= __devexit_p(mma8450_remove),
+	.id_table	= mma8450_id,
+};
+
+module_i2c_driver(mma8450_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/mpu3050.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/mpu3050.c
new file mode 100644
index 0000000..5403c57
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/mpu3050.c
@@ -0,0 +1,482 @@
+/*
+ * MPU3050 Tri-axis gyroscope driver
+ *
+ * Copyright (C) 2011 Wistron Co.Ltd
+ * Joseph Lai <joseph_lai@wistron.com>
+ *
+ * Trimmed down by Alan Cox <alan@linux.intel.com> to produce this version
+ *
+ * This is a 'lite' version of the driver, while we consider the right way
+ * to present the other features to user space. In particular it requires the
+ * device has an IRQ, and it only provides an input interface, so is not much
+ * use for device orientation. A fuller version is available from the Meego
+ * tree.
+ *
+ * This program is based on bma023.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#define MPU3050_CHIP_ID		0x69
+
+#define MPU3050_AUTO_DELAY	1000
+
+#define MPU3050_MIN_VALUE	-32768
+#define MPU3050_MAX_VALUE	32767
+
+#define MPU3050_DEFAULT_POLL_INTERVAL	200
+#define MPU3050_DEFAULT_FS_RANGE	3
+
+/* Register map */
+#define MPU3050_CHIP_ID_REG	0x00
+#define MPU3050_SMPLRT_DIV	0x15
+#define MPU3050_DLPF_FS_SYNC	0x16
+#define MPU3050_INT_CFG		0x17
+#define MPU3050_XOUT_H		0x1D
+#define MPU3050_PWR_MGM		0x3E
+#define MPU3050_PWR_MGM_POS	6
+
+/* Register bits */
+
+/* DLPF_FS_SYNC */
+#define MPU3050_EXT_SYNC_NONE		0x00
+#define MPU3050_EXT_SYNC_TEMP		0x20
+#define MPU3050_EXT_SYNC_GYROX		0x40
+#define MPU3050_EXT_SYNC_GYROY		0x60
+#define MPU3050_EXT_SYNC_GYROZ		0x80
+#define MPU3050_EXT_SYNC_ACCELX	0xA0
+#define MPU3050_EXT_SYNC_ACCELY	0xC0
+#define MPU3050_EXT_SYNC_ACCELZ	0xE0
+#define MPU3050_EXT_SYNC_MASK		0xE0
+#define MPU3050_FS_250DPS		0x00
+#define MPU3050_FS_500DPS		0x08
+#define MPU3050_FS_1000DPS		0x10
+#define MPU3050_FS_2000DPS		0x18
+#define MPU3050_FS_MASK		0x18
+#define MPU3050_DLPF_CFG_256HZ_NOLPF2	0x00
+#define MPU3050_DLPF_CFG_188HZ		0x01
+#define MPU3050_DLPF_CFG_98HZ		0x02
+#define MPU3050_DLPF_CFG_42HZ		0x03
+#define MPU3050_DLPF_CFG_20HZ		0x04
+#define MPU3050_DLPF_CFG_10HZ		0x05
+#define MPU3050_DLPF_CFG_5HZ		0x06
+#define MPU3050_DLPF_CFG_2100HZ_NOLPF	0x07
+#define MPU3050_DLPF_CFG_MASK		0x07
+/* INT_CFG */
+#define MPU3050_RAW_RDY_EN		0x01
+#define MPU3050_MPU_RDY_EN		0x02
+#define MPU3050_LATCH_INT_EN		0x04
+/* PWR_MGM */
+#define MPU3050_PWR_MGM_PLL_X		0x01
+#define MPU3050_PWR_MGM_PLL_Y		0x02
+#define MPU3050_PWR_MGM_PLL_Z		0x03
+#define MPU3050_PWR_MGM_CLKSEL		0x07
+#define MPU3050_PWR_MGM_STBY_ZG	0x08
+#define MPU3050_PWR_MGM_STBY_YG	0x10
+#define MPU3050_PWR_MGM_STBY_XG	0x20
+#define MPU3050_PWR_MGM_SLEEP		0x40
+#define MPU3050_PWR_MGM_RESET		0x80
+#define MPU3050_PWR_MGM_MASK		0x40
+
+struct axis_data {
+	s16 x;
+	s16 y;
+	s16 z;
+};
+
+struct mpu3050_sensor {
+	struct i2c_client *client;
+	struct device *dev;
+	struct input_dev *idev;
+};
+
+/**
+ *	mpu3050_xyz_read_reg	-	read the axes values
+ *	@buffer: provide register addr and get register
+ *	@length: length of register
+ *
+ *	Reads the register values in one transaction or returns a negative
+ *	error code on failure.
+ */
+static int mpu3050_xyz_read_reg(struct i2c_client *client,
+			       u8 *buffer, int length)
+{
+	/*
+	 * Annoying we can't make this const because the i2c layer doesn't
+	 * declare input buffers const.
+	 */
+	char cmd = MPU3050_XOUT_H;
+	struct i2c_msg msg[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &cmd,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = buffer,
+		},
+	};
+
+	return i2c_transfer(client->adapter, msg, 2);
+}
+
+/**
+ *	mpu3050_read_xyz	-	get co-ordinates from device
+ *	@client: i2c address of sensor
+ *	@coords: co-ordinates to update
+ *
+ *	Return the converted X Y and Z co-ordinates from the sensor device
+ */
+static void mpu3050_read_xyz(struct i2c_client *client,
+			     struct axis_data *coords)
+{
+	u16 buffer[3];
+
+	mpu3050_xyz_read_reg(client, (u8 *)buffer, 6);
+	coords->x = be16_to_cpu(buffer[0]);
+	coords->y = be16_to_cpu(buffer[1]);
+	coords->z = be16_to_cpu(buffer[2]);
+	dev_dbg(&client->dev, "%s: x %d, y %d, z %d\n", __func__,
+					coords->x, coords->y, coords->z);
+}
+
+/**
+ *	mpu3050_set_power_mode	-	set the power mode
+ *	@client: i2c client for the sensor
+ *	@val: value to switch on/off of power, 1: normal power, 0: low power
+ *
+ *	Put device to normal-power mode or low-power mode.
+ */
+static void mpu3050_set_power_mode(struct i2c_client *client, u8 val)
+{
+	u8 value;
+
+	value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
+	value = (value & ~MPU3050_PWR_MGM_MASK) |
+		(((val << MPU3050_PWR_MGM_POS) & MPU3050_PWR_MGM_MASK) ^
+		 MPU3050_PWR_MGM_MASK);
+	i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM, value);
+}
+
+/**
+ *	mpu3050_input_open	-	called on input event open
+ *	@input: input dev of opened device
+ *
+ *	The input layer calls this function when input event is opened. The
+ *	function will push the device to resume. Then, the device is ready
+ *	to provide data.
+ */
+static int mpu3050_input_open(struct input_dev *input)
+{
+	struct mpu3050_sensor *sensor = input_get_drvdata(input);
+	int error;
+
+	pm_runtime_get(sensor->dev);
+
+	/* Enable interrupts */
+	error = i2c_smbus_write_byte_data(sensor->client, MPU3050_INT_CFG,
+					  MPU3050_LATCH_INT_EN |
+					  MPU3050_RAW_RDY_EN |
+					  MPU3050_MPU_RDY_EN);
+	if (error < 0) {
+		pm_runtime_put(sensor->dev);
+		return error;
+	}
+
+	return 0;
+}
+
+/**
+ *	mpu3050_input_close	-	called on input event close
+ *	@input: input dev of closed device
+ *
+ *	The input layer calls this function when input event is closed. The
+ *	function will push the device to suspend.
+ */
+static void mpu3050_input_close(struct input_dev *input)
+{
+	struct mpu3050_sensor *sensor = input_get_drvdata(input);
+
+	pm_runtime_put(sensor->dev);
+}
+
+/**
+ *	mpu3050_interrupt_thread	-	handle an IRQ
+ *	@irq: interrupt numner
+ *	@data: the sensor
+ *
+ *	Called by the kernel single threaded after an interrupt occurs. Read
+ *	the sensor data and generate an input event for it.
+ */
+static irqreturn_t mpu3050_interrupt_thread(int irq, void *data)
+{
+	struct mpu3050_sensor *sensor = data;
+	struct axis_data axis;
+
+	mpu3050_read_xyz(sensor->client, &axis);
+
+	input_report_abs(sensor->idev, ABS_X, axis.x);
+	input_report_abs(sensor->idev, ABS_Y, axis.y);
+	input_report_abs(sensor->idev, ABS_Z, axis.z);
+	input_sync(sensor->idev);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ *	mpu3050_hw_init	-	initialize hardware
+ *	@sensor: the sensor
+ *
+ *	Called during device probe; configures the sampling method.
+ */
+static int __devinit mpu3050_hw_init(struct mpu3050_sensor *sensor)
+{
+	struct i2c_client *client = sensor->client;
+	int ret;
+	u8 reg;
+
+	/* Reset */
+	ret = i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM,
+					MPU3050_PWR_MGM_RESET);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
+	if (ret < 0)
+		return ret;
+
+	ret &= ~MPU3050_PWR_MGM_CLKSEL;
+	ret |= MPU3050_PWR_MGM_PLL_Z;
+	ret = i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM, ret);
+	if (ret < 0)
+		return ret;
+
+	/* Output frequency divider. The poll interval */
+	ret = i2c_smbus_write_byte_data(client, MPU3050_SMPLRT_DIV,
+					MPU3050_DEFAULT_POLL_INTERVAL - 1);
+	if (ret < 0)
+		return ret;
+
+	/* Set low pass filter and full scale */
+	reg = MPU3050_DEFAULT_FS_RANGE;
+	reg |= MPU3050_DLPF_CFG_42HZ << 3;
+	reg |= MPU3050_EXT_SYNC_NONE << 5;
+	ret = i2c_smbus_write_byte_data(client, MPU3050_DLPF_FS_SYNC, reg);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/**
+ *	mpu3050_probe	-	device detection callback
+ *	@client: i2c client of found device
+ *	@id: id match information
+ *
+ *	The I2C layer calls us when it believes a sensor is present at this
+ *	address. Probe to see if this is correct and to validate the device.
+ *
+ *	If present install the relevant sysfs interfaces and input device.
+ */
+static int __devinit mpu3050_probe(struct i2c_client *client,
+				   const struct i2c_device_id *id)
+{
+	struct mpu3050_sensor *sensor;
+	struct input_dev *idev;
+	int ret;
+	int error;
+
+	sensor = kzalloc(sizeof(struct mpu3050_sensor), GFP_KERNEL);
+	idev = input_allocate_device();
+	if (!sensor || !idev) {
+		dev_err(&client->dev, "failed to allocate driver data\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	sensor->client = client;
+	sensor->dev = &client->dev;
+	sensor->idev = idev;
+
+	mpu3050_set_power_mode(client, 1);
+	msleep(10);
+
+	ret = i2c_smbus_read_byte_data(client, MPU3050_CHIP_ID_REG);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to detect device\n");
+		error = -ENXIO;
+		goto err_free_mem;
+	}
+
+	if (ret != MPU3050_CHIP_ID) {
+		dev_err(&client->dev, "unsupported chip id\n");
+		error = -ENXIO;
+		goto err_free_mem;
+	}
+
+	idev->name = "MPU3050";
+	idev->id.bustype = BUS_I2C;
+	idev->dev.parent = &client->dev;
+
+	idev->open = mpu3050_input_open;
+	idev->close = mpu3050_input_close;
+
+	__set_bit(EV_ABS, idev->evbit);
+	input_set_abs_params(idev, ABS_X,
+			     MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
+	input_set_abs_params(idev, ABS_Y,
+			     MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
+	input_set_abs_params(idev, ABS_Z,
+			     MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
+
+	input_set_drvdata(idev, sensor);
+
+	pm_runtime_set_active(&client->dev);
+
+	error = mpu3050_hw_init(sensor);
+	if (error)
+		goto err_pm_set_suspended;
+
+	error = request_threaded_irq(client->irq,
+				     NULL, mpu3050_interrupt_thread,
+				     IRQF_TRIGGER_RISING,
+				     "mpu3050", sensor);
+	if (error) {
+		dev_err(&client->dev,
+			"can't get IRQ %d, error %d\n", client->irq, error);
+		goto err_pm_set_suspended;
+	}
+
+	error = input_register_device(idev);
+	if (error) {
+		dev_err(&client->dev, "failed to register input device\n");
+		goto err_free_irq;
+	}
+
+	pm_runtime_enable(&client->dev);
+	pm_runtime_set_autosuspend_delay(&client->dev, MPU3050_AUTO_DELAY);
+
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, sensor);
+err_pm_set_suspended:
+	pm_runtime_set_suspended(&client->dev);
+err_free_mem:
+	input_free_device(idev);
+	kfree(sensor);
+	return error;
+}
+
+/**
+ *	mpu3050_remove	-	remove a sensor
+ *	@client: i2c client of sensor being removed
+ *
+ *	Our sensor is going away, clean up the resources.
+ */
+static int __devexit mpu3050_remove(struct i2c_client *client)
+{
+	struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+
+	free_irq(client->irq, sensor);
+	input_unregister_device(sensor->idev);
+	kfree(sensor);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ *	mpu3050_suspend		-	called on device suspend
+ *	@dev: device being suspended
+ *
+ *	Put the device into sleep mode before we suspend the machine.
+ */
+static int mpu3050_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	mpu3050_set_power_mode(client, 0);
+
+	return 0;
+}
+
+/**
+ *	mpu3050_resume		-	called on device resume
+ *	@dev: device being resumed
+ *
+ *	Put the device into powered mode on resume.
+ */
+static int mpu3050_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	mpu3050_set_power_mode(client, 1);
+	msleep(100);  /* wait for gyro chip resume */
+
+	return 0;
+}
+#endif
+
+static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL);
+
+static const struct i2c_device_id mpu3050_ids[] = {
+	{ "mpu3050", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mpu3050_ids);
+
+static const struct of_device_id mpu3050_of_match[] = {
+	{ .compatible = "invn,mpu3050", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, mpu3050_of_match);
+
+static struct i2c_driver mpu3050_i2c_driver = {
+	.driver	= {
+		.name	= "mpu3050",
+		.owner	= THIS_MODULE,
+		.pm	= &mpu3050_pm,
+		.of_match_table = mpu3050_of_match,
+	},
+	.probe		= mpu3050_probe,
+	.remove		= __devexit_p(mpu3050_remove),
+	.id_table	= mpu3050_ids,
+};
+
+module_i2c_driver(mpu3050_i2c_driver);
+
+MODULE_AUTHOR("Wistron Corp.");
+MODULE_DESCRIPTION("MPU3050 Tri-axis gyroscope driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/pcap_keys.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/pcap_keys.c
new file mode 100644
index 0000000..e09b4fe
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/pcap_keys.c
@@ -0,0 +1,133 @@
+/*
+ *  Input driver for PCAP events:
+ *   * Power key
+ *   * Headphone button
+ *
+ *  Copyright (c) 2008,2009 Ilya Petrov <ilya.muromec@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/mfd/ezx-pcap.h>
+#include <linux/slab.h>
+
+struct pcap_keys {
+	struct pcap_chip *pcap;
+	struct input_dev *input;
+};
+
+/* PCAP2 interrupts us on keypress */
+static irqreturn_t pcap_keys_handler(int irq, void *_pcap_keys)
+{
+	struct pcap_keys *pcap_keys = _pcap_keys;
+	int pirq = irq_to_pcap(pcap_keys->pcap, irq);
+	u32 pstat;
+
+	ezx_pcap_read(pcap_keys->pcap, PCAP_REG_PSTAT, &pstat);
+	pstat &= 1 << pirq;
+
+	switch (pirq) {
+	case PCAP_IRQ_ONOFF:
+		input_report_key(pcap_keys->input, KEY_POWER, !pstat);
+		break;
+	case PCAP_IRQ_MIC:
+		input_report_key(pcap_keys->input, KEY_HP, !pstat);
+		break;
+	}
+
+	input_sync(pcap_keys->input);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit pcap_keys_probe(struct platform_device *pdev)
+{
+	int err = -ENOMEM;
+	struct pcap_keys *pcap_keys;
+	struct input_dev *input_dev;
+
+	pcap_keys = kmalloc(sizeof(struct pcap_keys), GFP_KERNEL);
+	if (!pcap_keys)
+		return err;
+
+	pcap_keys->pcap = dev_get_drvdata(pdev->dev.parent);
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		goto fail;
+
+	pcap_keys->input = input_dev;
+
+	platform_set_drvdata(pdev, pcap_keys);
+	input_dev->name = pdev->name;
+	input_dev->phys = "pcap-keys/input0";
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->dev.parent = &pdev->dev;
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(KEY_POWER, input_dev->keybit);
+	__set_bit(KEY_HP, input_dev->keybit);
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto fail_allocate;
+
+	err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF),
+			pcap_keys_handler, 0, "Power key", pcap_keys);
+	if (err)
+		goto fail_register;
+
+	err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC),
+			pcap_keys_handler, 0, "Headphone button", pcap_keys);
+	if (err)
+		goto fail_pwrkey;
+
+	return 0;
+
+fail_pwrkey:
+	free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys);
+fail_register:
+	input_unregister_device(input_dev);
+	goto fail;
+fail_allocate:
+	input_free_device(input_dev);
+fail:
+	kfree(pcap_keys);
+	return err;
+}
+
+static int __devexit pcap_keys_remove(struct platform_device *pdev)
+{
+	struct pcap_keys *pcap_keys = platform_get_drvdata(pdev);
+
+	free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys);
+	free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), pcap_keys);
+
+	input_unregister_device(pcap_keys->input);
+	kfree(pcap_keys);
+
+	return 0;
+}
+
+static struct platform_driver pcap_keys_device_driver = {
+	.probe		= pcap_keys_probe,
+	.remove		= __devexit_p(pcap_keys_remove),
+	.driver		= {
+		.name	= "pcap-keys",
+		.owner	= THIS_MODULE,
+	}
+};
+module_platform_driver(pcap_keys_device_driver);
+
+MODULE_DESCRIPTION("Motorola PCAP2 input events driver");
+MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcap_keys");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/pcf50633-input.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/pcf50633-input.c
new file mode 100644
index 0000000..53891de
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/pcf50633-input.c
@@ -0,0 +1,121 @@
+/* NXP PCF50633 Input Driver
+ *
+ * (C) 2006-2008 by Openmoko, Inc.
+ * Author: Balaji Rao <balajirrao@openmoko.org>
+ * All rights reserved.
+ *
+ * Broken down from monstrous PCF50633 driver mainly by
+ * Harald Welte, Andy Green and Werner Almesberger
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/pcf50633/core.h>
+
+#define PCF50633_OOCSTAT_ONKEY	0x01
+#define PCF50633_REG_OOCSTAT	0x12
+#define PCF50633_REG_OOCMODE	0x10
+
+struct pcf50633_input {
+	struct pcf50633 *pcf;
+	struct input_dev *input_dev;
+};
+
+static void
+pcf50633_input_irq(int irq, void *data)
+{
+	struct pcf50633_input *input;
+	int onkey_released;
+
+	input = data;
+
+	/* We report only one event depending on the key press status */
+	onkey_released = pcf50633_reg_read(input->pcf, PCF50633_REG_OOCSTAT)
+						& PCF50633_OOCSTAT_ONKEY;
+
+	if (irq == PCF50633_IRQ_ONKEYF && !onkey_released)
+		input_report_key(input->input_dev, KEY_POWER, 1);
+	else if (irq == PCF50633_IRQ_ONKEYR && onkey_released)
+		input_report_key(input->input_dev, KEY_POWER, 0);
+
+	input_sync(input->input_dev);
+}
+
+static int __devinit pcf50633_input_probe(struct platform_device *pdev)
+{
+	struct pcf50633_input *input;
+	struct input_dev *input_dev;
+	int ret;
+
+
+	input = kzalloc(sizeof(*input), GFP_KERNEL);
+	if (!input)
+		return -ENOMEM;
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		kfree(input);
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, input);
+	input->pcf = dev_to_pcf50633(pdev->dev.parent);
+	input->input_dev = input_dev;
+
+	input_dev->name = "PCF50633 PMU events";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_PWR);
+	set_bit(KEY_POWER, input_dev->keybit);
+
+	ret = input_register_device(input_dev);
+	if (ret) {
+		input_free_device(input_dev);
+		kfree(input);
+		return ret;
+	}
+	pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYR,
+				pcf50633_input_irq, input);
+	pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYF,
+				pcf50633_input_irq, input);
+
+	return 0;
+}
+
+static int __devexit pcf50633_input_remove(struct platform_device *pdev)
+{
+	struct pcf50633_input *input  = platform_get_drvdata(pdev);
+
+	pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYR);
+	pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYF);
+
+	input_unregister_device(input->input_dev);
+	kfree(input);
+
+	return 0;
+}
+
+static struct platform_driver pcf50633_input_driver = {
+	.driver = {
+		.name = "pcf50633-input",
+	},
+	.probe = pcf50633_input_probe,
+	.remove = __devexit_p(pcf50633_input_remove),
+};
+module_platform_driver(pcf50633_input_driver);
+
+MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
+MODULE_DESCRIPTION("PCF50633 input driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcf50633-input");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/pcf8574_keypad.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/pcf8574_keypad.c
new file mode 100644
index 0000000..544c663
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/pcf8574_keypad.c
@@ -0,0 +1,223 @@
+/*
+ * Driver for a keypad w/16 buttons connected to a PCF8574 I2C I/O expander
+ *
+ * Copyright 2005-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#define DRV_NAME "pcf8574_keypad"
+
+static const unsigned char pcf8574_kp_btncode[] = {
+	[0] = KEY_RESERVED,
+	[1] = KEY_ENTER,
+	[2] = KEY_BACKSLASH,
+	[3] = KEY_0,
+	[4] = KEY_RIGHTBRACE,
+	[5] = KEY_C,
+	[6] = KEY_9,
+	[7] = KEY_8,
+	[8] = KEY_7,
+	[9] = KEY_B,
+	[10] = KEY_6,
+	[11] = KEY_5,
+	[12] = KEY_4,
+	[13] = KEY_A,
+	[14] = KEY_3,
+	[15] = KEY_2,
+	[16] = KEY_1
+};
+
+struct kp_data {
+	unsigned short btncode[ARRAY_SIZE(pcf8574_kp_btncode)];
+	struct input_dev *idev;
+	struct i2c_client *client;
+	char name[64];
+	char phys[32];
+	unsigned char laststate;
+};
+
+static short read_state(struct kp_data *lp)
+{
+	unsigned char x, y, a, b;
+
+	i2c_smbus_write_byte(lp->client, 240);
+	x = 0xF & (~(i2c_smbus_read_byte(lp->client) >> 4));
+
+	i2c_smbus_write_byte(lp->client, 15);
+	y = 0xF & (~i2c_smbus_read_byte(lp->client));
+
+	for (a = 0; x > 0; a++)
+		x = x >> 1;
+	for (b = 0; y > 0; b++)
+		y = y >> 1;
+
+	return ((a - 1) * 4) + b;
+}
+
+static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id)
+{
+	struct kp_data *lp = dev_id;
+	unsigned char nextstate = read_state(lp);
+
+	if (lp->laststate != nextstate) {
+		int key_down = nextstate < ARRAY_SIZE(lp->btncode);
+		unsigned short keycode = key_down ?
+			lp->btncode[nextstate] : lp->btncode[lp->laststate];
+
+		input_report_key(lp->idev, keycode, key_down);
+		input_sync(lp->idev);
+
+		lp->laststate = nextstate;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int i, ret;
+	struct input_dev *idev;
+	struct kp_data *lp;
+
+	if (i2c_smbus_write_byte(client, 240) < 0) {
+		dev_err(&client->dev, "probe: write fail\n");
+		return -ENODEV;
+	}
+
+	lp = kzalloc(sizeof(*lp), GFP_KERNEL);
+	if (!lp)
+		return -ENOMEM;
+
+	idev = input_allocate_device();
+	if (!idev) {
+		dev_err(&client->dev, "Can't allocate input device\n");
+		ret = -ENOMEM;
+		goto fail_allocate;
+	}
+
+	lp->idev = idev;
+	lp->client = client;
+
+	idev->evbit[0] = BIT_MASK(EV_KEY);
+	idev->keycode = lp->btncode;
+	idev->keycodesize = sizeof(lp->btncode[0]);
+	idev->keycodemax = ARRAY_SIZE(lp->btncode);
+
+	for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); i++) {
+		lp->btncode[i] = pcf8574_kp_btncode[i];
+		__set_bit(lp->btncode[i] & KEY_MAX, idev->keybit);
+	}
+
+	sprintf(lp->name, DRV_NAME);
+	sprintf(lp->phys, "kp_data/input0");
+
+	idev->name = lp->name;
+	idev->phys = lp->phys;
+	idev->id.bustype = BUS_I2C;
+	idev->id.vendor = 0x0001;
+	idev->id.product = 0x0001;
+	idev->id.version = 0x0100;
+
+	lp->laststate = read_state(lp);
+
+	ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler,
+				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				   DRV_NAME, lp);
+	if (ret) {
+		dev_err(&client->dev, "IRQ %d is not free\n", client->irq);
+		goto fail_free_device;
+	}
+
+	ret = input_register_device(idev);
+	if (ret) {
+		dev_err(&client->dev, "input_register_device() failed\n");
+		goto fail_free_irq;
+	}
+
+	i2c_set_clientdata(client, lp);
+	return 0;
+
+ fail_free_irq:
+	free_irq(client->irq, lp);
+ fail_free_device:
+	input_free_device(idev);
+ fail_allocate:
+	kfree(lp);
+
+	return ret;
+}
+
+static int __devexit pcf8574_kp_remove(struct i2c_client *client)
+{
+	struct kp_data *lp = i2c_get_clientdata(client);
+
+	free_irq(client->irq, lp);
+
+	input_unregister_device(lp->idev);
+	kfree(lp);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pcf8574_kp_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	enable_irq(client->irq);
+
+	return 0;
+}
+
+static int pcf8574_kp_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	disable_irq(client->irq);
+
+	return 0;
+}
+
+static const struct dev_pm_ops pcf8574_kp_pm_ops = {
+	.suspend	= pcf8574_kp_suspend,
+	.resume		= pcf8574_kp_resume,
+};
+
+#else
+# define pcf8574_kp_resume  NULL
+# define pcf8574_kp_suspend NULL
+#endif
+
+static const struct i2c_device_id pcf8574_kp_id[] = {
+	{ DRV_NAME, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id);
+
+static struct i2c_driver pcf8574_kp_driver = {
+	.driver = {
+		.name  = DRV_NAME,
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &pcf8574_kp_pm_ops,
+#endif
+	},
+	.probe    = pcf8574_kp_probe,
+	.remove   = __devexit_p(pcf8574_kp_remove),
+	.id_table = pcf8574_kp_id,
+};
+
+module_i2c_driver(pcf8574_kp_driver);
+
+MODULE_AUTHOR("Michael Hennerich");
+MODULE_DESCRIPTION("Keypad input driver for 16 keys connected to PCF8574");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/pcspkr.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/pcspkr.c
new file mode 100644
index 0000000..b2484aa
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/pcspkr.c
@@ -0,0 +1,138 @@
+/*
+ *  PC Speaker beeper driver for Linux
+ *
+ *  Copyright (c) 2002 Vojtech Pavlik
+ *  Copyright (c) 1992 Orest Zborowski
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i8253.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/timex.h>
+#include <asm/io.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("PC Speaker beeper driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcspkr");
+
+static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	unsigned int count = 0;
+	unsigned long flags;
+
+	if (type != EV_SND)
+		return -1;
+
+	switch (code) {
+		case SND_BELL: if (value) value = 1000;
+		case SND_TONE: break;
+		default: return -1;
+	}
+
+	if (value > 20 && value < 32767)
+		count = PIT_TICK_RATE / value;
+
+	raw_spin_lock_irqsave(&i8253_lock, flags);
+
+	if (count) {
+		/* set command for counter 2, 2 byte write */
+		outb_p(0xB6, 0x43);
+		/* select desired HZ */
+		outb_p(count & 0xff, 0x42);
+		outb((count >> 8) & 0xff, 0x42);
+		/* enable counter 2 */
+		outb_p(inb_p(0x61) | 3, 0x61);
+	} else {
+		/* disable counter 2 */
+		outb(inb_p(0x61) & 0xFC, 0x61);
+	}
+
+	raw_spin_unlock_irqrestore(&i8253_lock, flags);
+
+	return 0;
+}
+
+static int __devinit pcspkr_probe(struct platform_device *dev)
+{
+	struct input_dev *pcspkr_dev;
+	int err;
+
+	pcspkr_dev = input_allocate_device();
+	if (!pcspkr_dev)
+		return -ENOMEM;
+
+	pcspkr_dev->name = "PC Speaker";
+	pcspkr_dev->phys = "isa0061/input0";
+	pcspkr_dev->id.bustype = BUS_ISA;
+	pcspkr_dev->id.vendor = 0x001f;
+	pcspkr_dev->id.product = 0x0001;
+	pcspkr_dev->id.version = 0x0100;
+	pcspkr_dev->dev.parent = &dev->dev;
+
+	pcspkr_dev->evbit[0] = BIT_MASK(EV_SND);
+	pcspkr_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+	pcspkr_dev->event = pcspkr_event;
+
+	err = input_register_device(pcspkr_dev);
+	if (err) {
+		input_free_device(pcspkr_dev);
+		return err;
+	}
+
+	platform_set_drvdata(dev, pcspkr_dev);
+
+	return 0;
+}
+
+static int __devexit pcspkr_remove(struct platform_device *dev)
+{
+	struct input_dev *pcspkr_dev = platform_get_drvdata(dev);
+
+	input_unregister_device(pcspkr_dev);
+	platform_set_drvdata(dev, NULL);
+	/* turn off the speaker */
+	pcspkr_event(NULL, EV_SND, SND_BELL, 0);
+
+	return 0;
+}
+
+static int pcspkr_suspend(struct device *dev)
+{
+	pcspkr_event(NULL, EV_SND, SND_BELL, 0);
+
+	return 0;
+}
+
+static void pcspkr_shutdown(struct platform_device *dev)
+{
+	/* turn off the speaker */
+	pcspkr_event(NULL, EV_SND, SND_BELL, 0);
+}
+
+static const struct dev_pm_ops pcspkr_pm_ops = {
+	.suspend = pcspkr_suspend,
+};
+
+static struct platform_driver pcspkr_platform_driver = {
+	.driver		= {
+		.name	= "pcspkr",
+		.owner	= THIS_MODULE,
+		.pm	= &pcspkr_pm_ops,
+	},
+	.probe		= pcspkr_probe,
+	.remove		= __devexit_p(pcspkr_remove),
+	.shutdown	= pcspkr_shutdown,
+};
+module_platform_driver(pcspkr_platform_driver);
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/pm8xxx-vibrator.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/pm8xxx-vibrator.c
new file mode 100644
index 0000000..dfbfb46
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/pm8xxx-vibrator.c
@@ -0,0 +1,285 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/mfd/pm8xxx/core.h>
+
+#define VIB_DRV			0x4A
+
+#define VIB_DRV_SEL_MASK	0xf8
+#define VIB_DRV_SEL_SHIFT	0x03
+#define VIB_DRV_EN_MANUAL_MASK	0xfc
+
+#define VIB_MAX_LEVEL_mV	(3100)
+#define VIB_MIN_LEVEL_mV	(1200)
+#define VIB_MAX_LEVELS		(VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV)
+
+#define MAX_FF_SPEED		0xff
+
+/**
+ * struct pm8xxx_vib - structure to hold vibrator data
+ * @vib_input_dev: input device supporting force feedback
+ * @work: work structure to set the vibration parameters
+ * @dev: device supporting force feedback
+ * @speed: speed of vibration set from userland
+ * @active: state of vibrator
+ * @level: level of vibration to set in the chip
+ * @reg_vib_drv: VIB_DRV register value
+ */
+struct pm8xxx_vib {
+	struct input_dev *vib_input_dev;
+	struct work_struct work;
+	struct device *dev;
+	int speed;
+	int level;
+	bool active;
+	u8  reg_vib_drv;
+};
+
+/**
+ * pm8xxx_vib_read_u8 - helper to read a byte from pmic chip
+ * @vib: pointer to vibrator structure
+ * @data: placeholder for data to be read
+ * @reg: register address
+ */
+static int pm8xxx_vib_read_u8(struct pm8xxx_vib *vib,
+				 u8 *data, u16 reg)
+{
+	int rc;
+
+	rc = pm8xxx_readb(vib->dev->parent, reg, data);
+	if (rc < 0)
+		dev_warn(vib->dev, "Error reading pm8xxx reg 0x%x(0x%x)\n",
+				reg, rc);
+	return rc;
+}
+
+/**
+ * pm8xxx_vib_write_u8 - helper to write a byte to pmic chip
+ * @vib: pointer to vibrator structure
+ * @data: data to write
+ * @reg: register address
+ */
+static int pm8xxx_vib_write_u8(struct pm8xxx_vib *vib,
+				 u8 data, u16 reg)
+{
+	int rc;
+
+	rc = pm8xxx_writeb(vib->dev->parent, reg, data);
+	if (rc < 0)
+		dev_warn(vib->dev, "Error writing pm8xxx reg 0x%x(0x%x)\n",
+				reg, rc);
+	return rc;
+}
+
+/**
+ * pm8xxx_vib_set - handler to start/stop vibration
+ * @vib: pointer to vibrator structure
+ * @on: state to set
+ */
+static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)
+{
+	int rc;
+	u8 val = vib->reg_vib_drv;
+
+	if (on)
+		val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK);
+	else
+		val &= ~VIB_DRV_SEL_MASK;
+
+	rc = pm8xxx_vib_write_u8(vib, val, VIB_DRV);
+	if (rc < 0)
+		return rc;
+
+	vib->reg_vib_drv = val;
+	return 0;
+}
+
+/**
+ * pm8xxx_work_handler - worker to set vibration level
+ * @work: pointer to work_struct
+ */
+static void pm8xxx_work_handler(struct work_struct *work)
+{
+	struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work);
+	int rc;
+	u8 val;
+
+	rc = pm8xxx_vib_read_u8(vib, &val, VIB_DRV);
+	if (rc < 0)
+		return;
+
+	/*
+	 * pmic vibrator supports voltage ranges from 1.2 to 3.1V, so
+	 * scale the level to fit into these ranges.
+	 */
+	if (vib->speed) {
+		vib->active = true;
+		vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) +
+						VIB_MIN_LEVEL_mV;
+		vib->level /= 100;
+	} else {
+		vib->active = false;
+		vib->level = VIB_MIN_LEVEL_mV / 100;
+	}
+
+	pm8xxx_vib_set(vib, vib->active);
+}
+
+/**
+ * pm8xxx_vib_close - callback of input close callback
+ * @dev: input device pointer
+ *
+ * Turns off the vibrator.
+ */
+static void pm8xxx_vib_close(struct input_dev *dev)
+{
+	struct pm8xxx_vib *vib = input_get_drvdata(dev);
+
+	cancel_work_sync(&vib->work);
+	if (vib->active)
+		pm8xxx_vib_set(vib, false);
+}
+
+/**
+ * pm8xxx_vib_play_effect - function to handle vib effects.
+ * @dev: input device pointer
+ * @data: data of effect
+ * @effect: effect to play
+ *
+ * Currently this driver supports only rumble effects.
+ */
+static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,
+				  struct ff_effect *effect)
+{
+	struct pm8xxx_vib *vib = input_get_drvdata(dev);
+
+	vib->speed = effect->u.rumble.strong_magnitude >> 8;
+	if (!vib->speed)
+		vib->speed = effect->u.rumble.weak_magnitude >> 9;
+
+	schedule_work(&vib->work);
+
+	return 0;
+}
+
+static int __devinit pm8xxx_vib_probe(struct platform_device *pdev)
+
+{
+	struct pm8xxx_vib *vib;
+	struct input_dev *input_dev;
+	int error;
+	u8 val;
+
+	vib = kzalloc(sizeof(*vib), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!vib || !input_dev) {
+		dev_err(&pdev->dev, "couldn't allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	INIT_WORK(&vib->work, pm8xxx_work_handler);
+	vib->dev = &pdev->dev;
+	vib->vib_input_dev = input_dev;
+
+	/* operate in manual mode */
+	error = pm8xxx_vib_read_u8(vib, &val, VIB_DRV);
+	if (error < 0)
+		goto err_free_mem;
+	val &= ~VIB_DRV_EN_MANUAL_MASK;
+	error = pm8xxx_vib_write_u8(vib, val, VIB_DRV);
+	if (error < 0)
+		goto err_free_mem;
+
+	vib->reg_vib_drv = val;
+
+	input_dev->name = "pm8xxx_vib_ffmemless";
+	input_dev->id.version = 1;
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->close = pm8xxx_vib_close;
+	input_set_drvdata(input_dev, vib);
+	input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE);
+
+	error = input_ff_create_memless(input_dev, NULL,
+					pm8xxx_vib_play_effect);
+	if (error) {
+		dev_err(&pdev->dev,
+			"couldn't register vibrator as FF device\n");
+		goto err_free_mem;
+	}
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(&pdev->dev, "couldn't register input device\n");
+		goto err_destroy_memless;
+	}
+
+	platform_set_drvdata(pdev, vib);
+	return 0;
+
+err_destroy_memless:
+	input_ff_destroy(input_dev);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(vib);
+
+	return error;
+}
+
+static int __devexit pm8xxx_vib_remove(struct platform_device *pdev)
+{
+	struct pm8xxx_vib *vib = platform_get_drvdata(pdev);
+
+	input_unregister_device(vib->vib_input_dev);
+	kfree(vib);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pm8xxx_vib_suspend(struct device *dev)
+{
+	struct pm8xxx_vib *vib = dev_get_drvdata(dev);
+
+	/* Turn off the vibrator */
+	pm8xxx_vib_set(vib, false);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
+
+static struct platform_driver pm8xxx_vib_driver = {
+	.probe		= pm8xxx_vib_probe,
+	.remove		= __devexit_p(pm8xxx_vib_remove),
+	.driver		= {
+		.name	= "pm8xxx-vib",
+		.owner	= THIS_MODULE,
+		.pm	= &pm8xxx_vib_pm_ops,
+	},
+};
+module_platform_driver(pm8xxx_vib_driver);
+
+MODULE_ALIAS("platform:pm8xxx_vib");
+MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Amy Maloche <amaloche@codeaurora.org>");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/pmic8xxx-pwrkey.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/pmic8xxx-pwrkey.c
new file mode 100644
index 0000000..0f83d0f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -0,0 +1,221 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/log2.h>
+
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/input/pmic8xxx-pwrkey.h>
+
+#define PON_CNTL_1 0x1C
+#define PON_CNTL_PULL_UP BIT(7)
+#define PON_CNTL_TRIG_DELAY_MASK (0x7)
+
+/**
+ * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information
+ * @key_press_irq: key press irq number
+ */
+struct pmic8xxx_pwrkey {
+	struct input_dev *pwr;
+	int key_press_irq;
+};
+
+static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
+{
+	struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
+
+	input_report_key(pwrkey->pwr, KEY_POWER, 1);
+	input_sync(pwrkey->pwr);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey)
+{
+	struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
+
+	input_report_key(pwrkey->pwr, KEY_POWER, 0);
+	input_sync(pwrkey->pwr);
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pmic8xxx_pwrkey_suspend(struct device *dev)
+{
+	struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(pwrkey->key_press_irq);
+
+	return 0;
+}
+
+static int pmic8xxx_pwrkey_resume(struct device *dev)
+{
+	struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(pwrkey->key_press_irq);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
+		pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
+
+static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
+{
+	struct input_dev *pwr;
+	int key_release_irq = platform_get_irq(pdev, 0);
+	int key_press_irq = platform_get_irq(pdev, 1);
+	int err;
+	unsigned int delay;
+	u8 pon_cntl;
+	struct pmic8xxx_pwrkey *pwrkey;
+	const struct pm8xxx_pwrkey_platform_data *pdata =
+					dev_get_platdata(&pdev->dev);
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "power key platform data not supplied\n");
+		return -EINVAL;
+	}
+
+	if (pdata->kpd_trigger_delay_us > 62500) {
+		dev_err(&pdev->dev, "invalid power key trigger delay\n");
+		return -EINVAL;
+	}
+
+	pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
+	if (!pwrkey)
+		return -ENOMEM;
+
+	pwr = input_allocate_device();
+	if (!pwr) {
+		dev_dbg(&pdev->dev, "Can't allocate power button\n");
+		err = -ENOMEM;
+		goto free_pwrkey;
+	}
+
+	input_set_capability(pwr, EV_KEY, KEY_POWER);
+
+	pwr->name = "pmic8xxx_pwrkey";
+	pwr->phys = "pmic8xxx_pwrkey/input0";
+	pwr->dev.parent = &pdev->dev;
+
+	delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
+	delay = 1 + ilog2(delay);
+
+	err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
+		goto free_input_dev;
+	}
+
+	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
+	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
+	if (pdata->pull_up)
+		pon_cntl |= PON_CNTL_PULL_UP;
+	else
+		pon_cntl &= ~PON_CNTL_PULL_UP;
+
+	err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
+		goto free_input_dev;
+	}
+
+	err = input_register_device(pwr);
+	if (err) {
+		dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
+		goto free_input_dev;
+	}
+
+	pwrkey->key_press_irq = key_press_irq;
+	pwrkey->pwr = pwr;
+
+	platform_set_drvdata(pdev, pwrkey);
+
+	err = request_irq(key_press_irq, pwrkey_press_irq,
+		IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
+	if (err < 0) {
+		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
+				 key_press_irq, err);
+		goto unreg_input_dev;
+	}
+
+	err = request_irq(key_release_irq, pwrkey_release_irq,
+		 IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
+	if (err < 0) {
+		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
+				 key_release_irq, err);
+
+		goto free_press_irq;
+	}
+
+	device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+	return 0;
+
+free_press_irq:
+	free_irq(key_press_irq, NULL);
+unreg_input_dev:
+	platform_set_drvdata(pdev, NULL);
+	input_unregister_device(pwr);
+	pwr = NULL;
+free_input_dev:
+	input_free_device(pwr);
+free_pwrkey:
+	kfree(pwrkey);
+	return err;
+}
+
+static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev)
+{
+	struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev);
+	int key_release_irq = platform_get_irq(pdev, 0);
+	int key_press_irq = platform_get_irq(pdev, 1);
+
+	device_init_wakeup(&pdev->dev, 0);
+
+	free_irq(key_press_irq, pwrkey);
+	free_irq(key_release_irq, pwrkey);
+	input_unregister_device(pwrkey->pwr);
+	platform_set_drvdata(pdev, NULL);
+	kfree(pwrkey);
+
+	return 0;
+}
+
+static struct platform_driver pmic8xxx_pwrkey_driver = {
+	.probe		= pmic8xxx_pwrkey_probe,
+	.remove		= __devexit_p(pmic8xxx_pwrkey_remove),
+	.driver		= {
+		.name	= PM8XXX_PWRKEY_DEV_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &pm8xxx_pwr_key_pm_ops,
+	},
+};
+module_platform_driver(pmic8xxx_pwrkey_driver);
+
+MODULE_ALIAS("platform:pmic8xxx_pwrkey");
+MODULE_DESCRIPTION("PMIC8XXX Power Key driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/powermate.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/powermate.c
new file mode 100644
index 0000000..538f704
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/powermate.c
@@ -0,0 +1,448 @@
+/*
+ * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial.
+ *
+ * v1.1, (c)2002 William R Sowerbutts <will@sowerbutts.com>
+ *
+ * This device is a anodised aluminium knob which connects over USB. It can measure
+ * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with
+ * a spring for automatic release. The base contains a pair of LEDs which illuminate
+ * the translucent base. It rotates without limit and reports its relative rotation
+ * back to the host when polled by the USB controller.
+ *
+ * Testing with the knob I have has shown that it measures approximately 94 "clicks"
+ * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was
+ * a variable speed cordless electric drill) has shown that the device can measure
+ * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
+ * the host. If it counts more than 7 clicks before it is polled, it will wrap back
+ * to zero and start counting again. This was at quite high speed, however, almost
+ * certainly faster than the human hand could turn it. Griffin say that it loses a
+ * pulse or two on a direction change; the granularity is so fine that I never
+ * noticed this in practice.
+ *
+ * The device's microcontroller can be programmed to set the LED to either a constant
+ * intensity, or to a rhythmic pulsing. Several patterns and speeds are available.
+ *
+ * Griffin were very happy to provide documentation and free hardware for development.
+ *
+ * Some userspace tools are available on the web: http://sowerbutts.com/powermate/
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/usb/input.h>
+
+#define POWERMATE_VENDOR	0x077d	/* Griffin Technology, Inc. */
+#define POWERMATE_PRODUCT_NEW	0x0410	/* Griffin PowerMate */
+#define POWERMATE_PRODUCT_OLD	0x04AA	/* Griffin soundKnob */
+
+#define CONTOUR_VENDOR		0x05f3	/* Contour Design, Inc. */
+#define CONTOUR_JOG		0x0240	/* Jog and Shuttle */
+
+/* these are the command codes we send to the device */
+#define SET_STATIC_BRIGHTNESS  0x01
+#define SET_PULSE_ASLEEP       0x02
+#define SET_PULSE_AWAKE        0x03
+#define SET_PULSE_MODE         0x04
+
+/* these refer to bits in the powermate_device's requires_update field. */
+#define UPDATE_STATIC_BRIGHTNESS (1<<0)
+#define UPDATE_PULSE_ASLEEP      (1<<1)
+#define UPDATE_PULSE_AWAKE       (1<<2)
+#define UPDATE_PULSE_MODE        (1<<3)
+
+/* at least two versions of the hardware exist, with differing payload
+   sizes. the first three bytes always contain the "interesting" data in
+   the relevant format. */
+#define POWERMATE_PAYLOAD_SIZE_MAX 6
+#define POWERMATE_PAYLOAD_SIZE_MIN 3
+struct powermate_device {
+	signed char *data;
+	dma_addr_t data_dma;
+	struct urb *irq, *config;
+	struct usb_ctrlrequest *configcr;
+	struct usb_device *udev;
+	struct input_dev *input;
+	spinlock_t lock;
+	int static_brightness;
+	int pulse_speed;
+	int pulse_table;
+	int pulse_asleep;
+	int pulse_awake;
+	int requires_update; // physical settings which are out of sync
+	char phys[64];
+};
+
+static char pm_name_powermate[] = "Griffin PowerMate";
+static char pm_name_soundknob[] = "Griffin SoundKnob";
+
+static void powermate_config_complete(struct urb *urb);
+
+/* Callback for data arriving from the PowerMate over the USB interrupt pipe */
+static void powermate_irq(struct urb *urb)
+{
+	struct powermate_device *pm = urb->context;
+	int retval;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+		goto exit;
+	}
+
+	/* handle updates to device state */
+	input_report_key(pm->input, BTN_0, pm->data[0] & 0x01);
+	input_report_rel(pm->input, REL_DIAL, pm->data[1]);
+	input_sync(pm->input);
+
+exit:
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		err ("%s - usb_submit_urb failed with result %d",
+		     __func__, retval);
+}
+
+/* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
+static void powermate_sync_state(struct powermate_device *pm)
+{
+	if (pm->requires_update == 0)
+		return; /* no updates are required */
+	if (pm->config->status == -EINPROGRESS)
+		return; /* an update is already in progress; it'll issue this update when it completes */
+
+	if (pm->requires_update & UPDATE_PULSE_ASLEEP){
+		pm->configcr->wValue = cpu_to_le16( SET_PULSE_ASLEEP );
+		pm->configcr->wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 );
+		pm->requires_update &= ~UPDATE_PULSE_ASLEEP;
+	}else if (pm->requires_update & UPDATE_PULSE_AWAKE){
+		pm->configcr->wValue = cpu_to_le16( SET_PULSE_AWAKE );
+		pm->configcr->wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 );
+		pm->requires_update &= ~UPDATE_PULSE_AWAKE;
+	}else if (pm->requires_update & UPDATE_PULSE_MODE){
+		int op, arg;
+		/* the powermate takes an operation and an argument for its pulse algorithm.
+		   the operation can be:
+		   0: divide the speed
+		   1: pulse at normal speed
+		   2: multiply the speed
+		   the argument only has an effect for operations 0 and 2, and ranges between
+		   1 (least effect) to 255 (maximum effect).
+
+		   thus, several states are equivalent and are coalesced into one state.
+
+		   we map this onto a range from 0 to 510, with:
+		   0 -- 254    -- use divide (0 = slowest)
+		   255         -- use normal speed
+		   256 -- 510  -- use multiple (510 = fastest).
+
+		   Only values of 'arg' quite close to 255 are particularly useful/spectacular.
+		*/
+		if (pm->pulse_speed < 255) {
+			op = 0;                   // divide
+			arg = 255 - pm->pulse_speed;
+		} else if (pm->pulse_speed > 255) {
+			op = 2;                   // multiply
+			arg = pm->pulse_speed - 255;
+		} else {
+			op = 1;                   // normal speed
+			arg = 0;                  // can be any value
+		}
+		pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE );
+		pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op );
+		pm->requires_update &= ~UPDATE_PULSE_MODE;
+	} else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS) {
+		pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS );
+		pm->configcr->wIndex = cpu_to_le16( pm->static_brightness );
+		pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS;
+	} else {
+		printk(KERN_ERR "powermate: unknown update required");
+		pm->requires_update = 0; /* fudge the bug */
+		return;
+	}
+
+/*	printk("powermate: %04x %04x\n", pm->configcr->wValue, pm->configcr->wIndex); */
+
+	pm->configcr->bRequestType = 0x41; /* vendor request */
+	pm->configcr->bRequest = 0x01;
+	pm->configcr->wLength = 0;
+
+	usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0),
+			     (void *) pm->configcr, NULL, 0,
+			     powermate_config_complete, pm);
+
+	if (usb_submit_urb(pm->config, GFP_ATOMIC))
+		printk(KERN_ERR "powermate: usb_submit_urb(config) failed");
+}
+
+/* Called when our asynchronous control message completes. We may need to issue another immediately */
+static void powermate_config_complete(struct urb *urb)
+{
+	struct powermate_device *pm = urb->context;
+	unsigned long flags;
+
+	if (urb->status)
+		printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
+
+	spin_lock_irqsave(&pm->lock, flags);
+	powermate_sync_state(pm);
+	spin_unlock_irqrestore(&pm->lock, flags);
+}
+
+/* Set the LED up as described and begin the sync with the hardware if required */
+static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
+				int pulse_table, int pulse_asleep, int pulse_awake)
+{
+	unsigned long flags;
+
+	if (pulse_speed < 0)
+		pulse_speed = 0;
+	if (pulse_table < 0)
+		pulse_table = 0;
+	if (pulse_speed > 510)
+		pulse_speed = 510;
+	if (pulse_table > 2)
+		pulse_table = 2;
+
+	pulse_asleep = !!pulse_asleep;
+	pulse_awake = !!pulse_awake;
+
+
+	spin_lock_irqsave(&pm->lock, flags);
+
+	/* mark state updates which are required */
+	if (static_brightness != pm->static_brightness) {
+		pm->static_brightness = static_brightness;
+		pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;
+	}
+	if (pulse_asleep != pm->pulse_asleep) {
+		pm->pulse_asleep = pulse_asleep;
+		pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS);
+	}
+	if (pulse_awake != pm->pulse_awake) {
+		pm->pulse_awake = pulse_awake;
+		pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS);
+	}
+	if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table) {
+		pm->pulse_speed = pulse_speed;
+		pm->pulse_table = pulse_table;
+		pm->requires_update |= UPDATE_PULSE_MODE;
+	}
+
+	powermate_sync_state(pm);
+
+	spin_unlock_irqrestore(&pm->lock, flags);
+}
+
+/* Callback from the Input layer when an event arrives from userspace to configure the LED */
+static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value)
+{
+	unsigned int command = (unsigned int)_value;
+	struct powermate_device *pm = input_get_drvdata(dev);
+
+	if (type == EV_MSC && code == MSC_PULSELED){
+		/*
+		    bits  0- 7: 8 bits: LED brightness
+		    bits  8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
+		    bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
+		    bit     19: 1 bit : pulse whilst asleep?
+		    bit     20: 1 bit : pulse constantly?
+		*/
+		int static_brightness = command & 0xFF;   // bits 0-7
+		int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
+		int pulse_table = (command >> 17) & 0x3;  // bits 17-18
+		int pulse_asleep = (command >> 19) & 0x1; // bit 19
+		int pulse_awake  = (command >> 20) & 0x1; // bit 20
+
+		powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
+	}
+
+	return 0;
+}
+
+static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm)
+{
+	pm->data = usb_alloc_coherent(udev, POWERMATE_PAYLOAD_SIZE_MAX,
+				      GFP_ATOMIC, &pm->data_dma);
+	if (!pm->data)
+		return -1;
+
+	pm->configcr = kmalloc(sizeof(*(pm->configcr)), GFP_KERNEL);
+	if (!pm->configcr)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm)
+{
+	usb_free_coherent(udev, POWERMATE_PAYLOAD_SIZE_MAX,
+			  pm->data, pm->data_dma);
+	kfree(pm->configcr);
+}
+
+/* Called whenever a USB device matching one in our supported devices table is connected */
+static int powermate_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev (intf);
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct powermate_device *pm;
+	struct input_dev *input_dev;
+	int pipe, maxp;
+	int error = -ENOMEM;
+
+	interface = intf->cur_altsetting;
+	endpoint = &interface->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -EIO;
+
+	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+		0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+		0, interface->desc.bInterfaceNumber, NULL, 0,
+		USB_CTRL_SET_TIMEOUT);
+
+	pm = kzalloc(sizeof(struct powermate_device), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!pm || !input_dev)
+		goto fail1;
+
+	if (powermate_alloc_buffers(udev, pm))
+		goto fail2;
+
+	pm->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!pm->irq)
+		goto fail2;
+
+	pm->config = usb_alloc_urb(0, GFP_KERNEL);
+	if (!pm->config)
+		goto fail3;
+
+	pm->udev = udev;
+	pm->input = input_dev;
+
+	usb_make_path(udev, pm->phys, sizeof(pm->phys));
+	strlcat(pm->phys, "/input0", sizeof(pm->phys));
+
+	spin_lock_init(&pm->lock);
+
+	switch (le16_to_cpu(udev->descriptor.idProduct)) {
+	case POWERMATE_PRODUCT_NEW:
+		input_dev->name = pm_name_powermate;
+		break;
+	case POWERMATE_PRODUCT_OLD:
+		input_dev->name = pm_name_soundknob;
+		break;
+	default:
+		input_dev->name = pm_name_soundknob;
+		printk(KERN_WARNING "powermate: unknown product id %04x\n",
+		       le16_to_cpu(udev->descriptor.idProduct));
+	}
+
+	input_dev->phys = pm->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, pm);
+
+	input_dev->event = powermate_input_event;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) |
+		BIT_MASK(EV_MSC);
+	input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+	input_dev->relbit[BIT_WORD(REL_DIAL)] = BIT_MASK(REL_DIAL);
+	input_dev->mscbit[BIT_WORD(MSC_PULSELED)] = BIT_MASK(MSC_PULSELED);
+
+	/* get a handle to the interrupt data pipe */
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+	if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) {
+		printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n",
+			POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp);
+		maxp = POWERMATE_PAYLOAD_SIZE_MAX;
+	}
+
+	usb_fill_int_urb(pm->irq, udev, pipe, pm->data,
+			 maxp, powermate_irq,
+			 pm, endpoint->bInterval);
+	pm->irq->transfer_dma = pm->data_dma;
+	pm->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* register our interrupt URB with the USB system */
+	if (usb_submit_urb(pm->irq, GFP_KERNEL)) {
+		error = -EIO;
+		goto fail4;
+	}
+
+	error = input_register_device(pm->input);
+	if (error)
+		goto fail5;
+
+
+	/* force an update of everything */
+	pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
+	powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
+
+	usb_set_intfdata(intf, pm);
+	return 0;
+
+ fail5:	usb_kill_urb(pm->irq);
+ fail4:	usb_free_urb(pm->config);
+ fail3:	usb_free_urb(pm->irq);
+ fail2:	powermate_free_buffers(udev, pm);
+ fail1:	input_free_device(input_dev);
+	kfree(pm);
+	return error;
+}
+
+/* Called when a USB device we've accepted ownership of is removed */
+static void powermate_disconnect(struct usb_interface *intf)
+{
+	struct powermate_device *pm = usb_get_intfdata (intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (pm) {
+		pm->requires_update = 0;
+		usb_kill_urb(pm->irq);
+		input_unregister_device(pm->input);
+		usb_free_urb(pm->irq);
+		usb_free_urb(pm->config);
+		powermate_free_buffers(interface_to_usbdev(intf), pm);
+
+		kfree(pm);
+	}
+}
+
+static struct usb_device_id powermate_devices [] = {
+	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) },
+	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) },
+	{ USB_DEVICE(CONTOUR_VENDOR, CONTOUR_JOG) },
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, powermate_devices);
+
+static struct usb_driver powermate_driver = {
+        .name =         "powermate",
+        .probe =        powermate_probe,
+        .disconnect =   powermate_disconnect,
+        .id_table =     powermate_devices,
+};
+
+module_usb_driver(powermate_driver);
+
+MODULE_AUTHOR( "William R Sowerbutts" );
+MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" );
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/pwm-beeper.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/pwm-beeper.c
new file mode 100644
index 0000000..fc84c8a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/pwm-beeper.c
@@ -0,0 +1,188 @@
+/*
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  PWM beeper driver
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under  the terms of the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+struct pwm_beeper {
+	struct input_dev *input;
+	struct pwm_device *pwm;
+	unsigned long period;
+};
+
+#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
+
+static int pwm_beeper_event(struct input_dev *input,
+			    unsigned int type, unsigned int code, int value)
+{
+	int ret = 0;
+	struct pwm_beeper *beeper = input_get_drvdata(input);
+	unsigned long period;
+
+	if (type != EV_SND || value < 0)
+		return -EINVAL;
+
+	switch (code) {
+	case SND_BELL:
+		value = value ? 1000 : 0;
+		break;
+	case SND_TONE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (value == 0) {
+		pwm_config(beeper->pwm, 0, 0);
+		pwm_disable(beeper->pwm);
+	} else {
+		period = HZ_TO_NANOSECONDS(value);
+		ret = pwm_config(beeper->pwm, period / 2, period);
+		if (ret)
+			return ret;
+		ret = pwm_enable(beeper->pwm);
+		if (ret)
+			return ret;
+		beeper->period = period;
+	}
+
+	return 0;
+}
+
+static int __devinit pwm_beeper_probe(struct platform_device *pdev)
+{
+	unsigned long pwm_id = (unsigned long)pdev->dev.platform_data;
+	struct pwm_beeper *beeper;
+	int error;
+
+	beeper = kzalloc(sizeof(*beeper), GFP_KERNEL);
+	if (!beeper)
+		return -ENOMEM;
+
+	beeper->pwm = pwm_request(pwm_id, "pwm beeper");
+
+	if (IS_ERR(beeper->pwm)) {
+		error = PTR_ERR(beeper->pwm);
+		dev_err(&pdev->dev, "Failed to request pwm device: %d\n", error);
+		goto err_free;
+	}
+
+	beeper->input = input_allocate_device();
+	if (!beeper->input) {
+		dev_err(&pdev->dev, "Failed to allocate input device\n");
+		error = -ENOMEM;
+		goto err_pwm_free;
+	}
+	beeper->input->dev.parent = &pdev->dev;
+
+	beeper->input->name = "pwm-beeper";
+	beeper->input->phys = "pwm/input0";
+	beeper->input->id.bustype = BUS_HOST;
+	beeper->input->id.vendor = 0x001f;
+	beeper->input->id.product = 0x0001;
+	beeper->input->id.version = 0x0100;
+
+	beeper->input->evbit[0] = BIT(EV_SND);
+	beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL);
+
+	beeper->input->event = pwm_beeper_event;
+
+	input_set_drvdata(beeper->input, beeper);
+
+	error = input_register_device(beeper->input);
+	if (error) {
+		dev_err(&pdev->dev, "Failed to register input device: %d\n", error);
+		goto err_input_free;
+	}
+
+	platform_set_drvdata(pdev, beeper);
+
+	return 0;
+
+err_input_free:
+	input_free_device(beeper->input);
+err_pwm_free:
+	pwm_free(beeper->pwm);
+err_free:
+	kfree(beeper);
+
+	return error;
+}
+
+static int __devexit pwm_beeper_remove(struct platform_device *pdev)
+{
+	struct pwm_beeper *beeper = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	input_unregister_device(beeper->input);
+
+	pwm_disable(beeper->pwm);
+	pwm_free(beeper->pwm);
+
+	kfree(beeper);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pwm_beeper_suspend(struct device *dev)
+{
+	struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+	if (beeper->period)
+		pwm_disable(beeper->pwm);
+
+	return 0;
+}
+
+static int pwm_beeper_resume(struct device *dev)
+{
+	struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+	if (beeper->period) {
+		pwm_config(beeper->pwm, beeper->period / 2, beeper->period);
+		pwm_enable(beeper->pwm);
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
+			 pwm_beeper_suspend, pwm_beeper_resume);
+
+#define PWM_BEEPER_PM_OPS (&pwm_beeper_pm_ops)
+#else
+#define PWM_BEEPER_PM_OPS NULL
+#endif
+
+static struct platform_driver pwm_beeper_driver = {
+	.probe	= pwm_beeper_probe,
+	.remove = __devexit_p(pwm_beeper_remove),
+	.driver = {
+		.name	= "pwm-beeper",
+		.owner	= THIS_MODULE,
+		.pm	= PWM_BEEPER_PM_OPS,
+	},
+};
+module_platform_driver(pwm_beeper_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("PWM beeper driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pwm-beeper");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/rb532_button.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/rb532_button.c
new file mode 100644
index 0000000..aeb02bc
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/rb532_button.c
@@ -0,0 +1,108 @@
+/*
+ * Support for the S1 button on Routerboard 532
+ *
+ * Copyright (C) 2009  Phil Sutter <n0-1@freewrt.org>
+ */
+
+#include <linux/input-polldev.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-rc32434/gpio.h>
+#include <asm/mach-rc32434/rb.h>
+
+#define DRV_NAME "rb532-button"
+
+#define RB532_BTN_RATE 100 /* msec */
+#define RB532_BTN_KSYM BTN_0
+
+/* The S1 button state is provided by GPIO pin 1. But as this
+ * pin is also used for uart input as alternate function, the
+ * operational modes must be switched first:
+ * 1) disable uart using set_latch_u5()
+ * 2) turn off alternate function implicitly through
+ *    gpio_direction_input()
+ * 3) read the GPIO's current value
+ * 4) undo step 2 by enabling alternate function (in this
+ *    mode the GPIO direction is fixed, so no change needed)
+ * 5) turn on uart again
+ * The GPIO value occurs to be inverted, so pin high means
+ * button is not pressed.
+ */
+static bool rb532_button_pressed(void)
+{
+	int val;
+
+	set_latch_u5(0, LO_FOFF);
+	gpio_direction_input(GPIO_BTN_S1);
+
+	val = gpio_get_value(GPIO_BTN_S1);
+
+	rb532_gpio_set_func(GPIO_BTN_S1);
+	set_latch_u5(LO_FOFF, 0);
+
+	return !val;
+}
+
+static void rb532_button_poll(struct input_polled_dev *poll_dev)
+{
+	input_report_key(poll_dev->input, RB532_BTN_KSYM,
+			 rb532_button_pressed());
+	input_sync(poll_dev->input);
+}
+
+static int __devinit rb532_button_probe(struct platform_device *pdev)
+{
+	struct input_polled_dev *poll_dev;
+	int error;
+
+	poll_dev = input_allocate_polled_device();
+	if (!poll_dev)
+		return -ENOMEM;
+
+	poll_dev->poll = rb532_button_poll;
+	poll_dev->poll_interval = RB532_BTN_RATE;
+
+	poll_dev->input->name = "rb532 button";
+	poll_dev->input->phys = "rb532/button0";
+	poll_dev->input->id.bustype = BUS_HOST;
+	poll_dev->input->dev.parent = &pdev->dev;
+
+	dev_set_drvdata(&pdev->dev, poll_dev);
+
+	input_set_capability(poll_dev->input, EV_KEY, RB532_BTN_KSYM);
+
+	error = input_register_polled_device(poll_dev);
+	if (error) {
+		input_free_polled_device(poll_dev);
+		return error;
+	}
+
+	return 0;
+}
+
+static int __devexit rb532_button_remove(struct platform_device *pdev)
+{
+	struct input_polled_dev *poll_dev = dev_get_drvdata(&pdev->dev);
+
+	input_unregister_polled_device(poll_dev);
+	input_free_polled_device(poll_dev);
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver rb532_button_driver = {
+	.probe = rb532_button_probe,
+	.remove = __devexit_p(rb532_button_remove),
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+module_platform_driver(rb532_button_driver);
+
+MODULE_AUTHOR("Phil Sutter <n0-1@freewrt.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Support for S1 button on Routerboard 532");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/rotary_encoder.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/rotary_encoder.c
new file mode 100644
index 0000000..f07f784
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/rotary_encoder.c
@@ -0,0 +1,292 @@
+/*
+ * rotary_encoder.c
+ *
+ * (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 2011 Johan Hovold <jhovold@gmail.com>
+ *
+ * state machine code inspired by code from Tim Ruetz
+ *
+ * A generic driver for rotary encoders connected to GPIO lines.
+ * See file:Documentation/input/rotary-encoder.txt for more information
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/rotary_encoder.h>
+#include <linux/slab.h>
+
+#define DRV_NAME "rotary-encoder"
+
+struct rotary_encoder {
+	struct input_dev *input;
+	struct rotary_encoder_platform_data *pdata;
+
+	unsigned int axis;
+	unsigned int pos;
+
+	unsigned int irq_a;
+	unsigned int irq_b;
+
+	bool armed;
+	unsigned char dir;	/* 0 - clockwise, 1 - CCW */
+
+	char last_stable;
+};
+
+static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata)
+{
+	int a = !!gpio_get_value(pdata->gpio_a);
+	int b = !!gpio_get_value(pdata->gpio_b);
+
+	a ^= pdata->inverted_a;
+	b ^= pdata->inverted_b;
+
+	return ((a << 1) | b);
+}
+
+static void rotary_encoder_report_event(struct rotary_encoder *encoder)
+{
+	struct rotary_encoder_platform_data *pdata = encoder->pdata;
+
+	if (pdata->relative_axis) {
+		input_report_rel(encoder->input,
+				 pdata->axis, encoder->dir ? -1 : 1);
+	} else {
+		unsigned int pos = encoder->pos;
+
+		if (encoder->dir) {
+			/* turning counter-clockwise */
+			if (pdata->rollover)
+				pos += pdata->steps;
+			if (pos)
+				pos--;
+		} else {
+			/* turning clockwise */
+			if (pdata->rollover || pos < pdata->steps)
+				pos++;
+		}
+
+		if (pdata->rollover)
+			pos %= pdata->steps;
+
+		encoder->pos = pos;
+		input_report_abs(encoder->input, pdata->axis, encoder->pos);
+	}
+
+	input_sync(encoder->input);
+}
+
+static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
+{
+	struct rotary_encoder *encoder = dev_id;
+	int state;
+
+	state = rotary_encoder_get_state(encoder->pdata);
+
+	switch (state) {
+	case 0x0:
+		if (encoder->armed) {
+			rotary_encoder_report_event(encoder);
+			encoder->armed = false;
+		}
+		break;
+
+	case 0x1:
+	case 0x2:
+		if (encoder->armed)
+			encoder->dir = state - 1;
+		break;
+
+	case 0x3:
+		encoder->armed = true;
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
+{
+	struct rotary_encoder *encoder = dev_id;
+	int state;
+
+	state = rotary_encoder_get_state(encoder->pdata);
+
+	switch (state) {
+	case 0x00:
+	case 0x03:
+		if (state != encoder->last_stable) {
+			rotary_encoder_report_event(encoder);
+			encoder->last_stable = state;
+		}
+		break;
+
+	case 0x01:
+	case 0x02:
+		encoder->dir = (encoder->last_stable + state) & 0x01;
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit rotary_encoder_probe(struct platform_device *pdev)
+{
+	struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data;
+	struct rotary_encoder *encoder;
+	struct input_dev *input;
+	irq_handler_t handler;
+	int err;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "missing platform data\n");
+		return -ENOENT;
+	}
+
+	encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!encoder || !input) {
+		dev_err(&pdev->dev, "failed to allocate memory for device\n");
+		err = -ENOMEM;
+		goto exit_free_mem;
+	}
+
+	encoder->input = input;
+	encoder->pdata = pdata;
+	encoder->irq_a = gpio_to_irq(pdata->gpio_a);
+	encoder->irq_b = gpio_to_irq(pdata->gpio_b);
+
+	/* create and register the input driver */
+	input->name = pdev->name;
+	input->id.bustype = BUS_HOST;
+	input->dev.parent = &pdev->dev;
+
+	if (pdata->relative_axis) {
+		input->evbit[0] = BIT_MASK(EV_REL);
+		input->relbit[0] = BIT_MASK(pdata->axis);
+	} else {
+		input->evbit[0] = BIT_MASK(EV_ABS);
+		input_set_abs_params(encoder->input,
+				     pdata->axis, 0, pdata->steps, 0, 1);
+	}
+
+	err = input_register_device(input);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register input device\n");
+		goto exit_free_mem;
+	}
+
+	/* request the GPIOs */
+	err = gpio_request(pdata->gpio_a, DRV_NAME);
+	if (err) {
+		dev_err(&pdev->dev, "unable to request GPIO %d\n",
+			pdata->gpio_a);
+		goto exit_unregister_input;
+	}
+
+	err = gpio_direction_input(pdata->gpio_a);
+	if (err) {
+		dev_err(&pdev->dev, "unable to set GPIO %d for input\n",
+			pdata->gpio_a);
+		goto exit_unregister_input;
+	}
+
+	err = gpio_request(pdata->gpio_b, DRV_NAME);
+	if (err) {
+		dev_err(&pdev->dev, "unable to request GPIO %d\n",
+			pdata->gpio_b);
+		goto exit_free_gpio_a;
+	}
+
+	err = gpio_direction_input(pdata->gpio_b);
+	if (err) {
+		dev_err(&pdev->dev, "unable to set GPIO %d for input\n",
+			pdata->gpio_b);
+		goto exit_free_gpio_a;
+	}
+
+	/* request the IRQs */
+	if (pdata->half_period) {
+		handler = &rotary_encoder_half_period_irq;
+		encoder->last_stable = rotary_encoder_get_state(pdata);
+	} else {
+		handler = &rotary_encoder_irq;
+	}
+
+	err = request_irq(encoder->irq_a, handler,
+			  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			  DRV_NAME, encoder);
+	if (err) {
+		dev_err(&pdev->dev, "unable to request IRQ %d\n",
+			encoder->irq_a);
+		goto exit_free_gpio_b;
+	}
+
+	err = request_irq(encoder->irq_b, handler,
+			  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			  DRV_NAME, encoder);
+	if (err) {
+		dev_err(&pdev->dev, "unable to request IRQ %d\n",
+			encoder->irq_b);
+		goto exit_free_irq_a;
+	}
+
+	platform_set_drvdata(pdev, encoder);
+
+	return 0;
+
+exit_free_irq_a:
+	free_irq(encoder->irq_a, encoder);
+exit_free_gpio_b:
+	gpio_free(pdata->gpio_b);
+exit_free_gpio_a:
+	gpio_free(pdata->gpio_a);
+exit_unregister_input:
+	input_unregister_device(input);
+	input = NULL; /* so we don't try to free it */
+exit_free_mem:
+	input_free_device(input);
+	kfree(encoder);
+	return err;
+}
+
+static int __devexit rotary_encoder_remove(struct platform_device *pdev)
+{
+	struct rotary_encoder *encoder = platform_get_drvdata(pdev);
+	struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data;
+
+	free_irq(encoder->irq_a, encoder);
+	free_irq(encoder->irq_b, encoder);
+	gpio_free(pdata->gpio_a);
+	gpio_free(pdata->gpio_b);
+	input_unregister_device(encoder->input);
+	platform_set_drvdata(pdev, NULL);
+	kfree(encoder);
+
+	return 0;
+}
+
+static struct platform_driver rotary_encoder_driver = {
+	.probe		= rotary_encoder_probe,
+	.remove		= __devexit_p(rotary_encoder_remove),
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	}
+};
+module_platform_driver(rotary_encoder_driver);
+
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DESCRIPTION("GPIO rotary encoder driver");
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/sgi_btns.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/sgi_btns.c
new file mode 100644
index 0000000..5d9fd55
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/sgi_btns.c
@@ -0,0 +1,169 @@
+/*
+ *  SGI Volume Button interface driver
+ *
+ *  Copyright (C) 2008  Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_SGI_IP22
+#include <asm/sgi/ioc.h>
+
+static inline u8 button_status(void)
+{
+	u8 status;
+
+	status = readb(&sgioc->panel) ^ 0xa0;
+	return ((status & 0x80) >> 6) | ((status & 0x20) >> 5);
+}
+#endif
+
+#ifdef CONFIG_SGI_IP32
+#include <asm/ip32/mace.h>
+
+static inline u8 button_status(void)
+{
+	u64 status;
+
+	status = readq(&mace->perif.audio.control);
+	writeq(status & ~(3U << 23), &mace->perif.audio.control);
+
+	return (status >> 23) & 3;
+}
+#endif
+
+#define BUTTONS_POLL_INTERVAL	30	/* msec */
+#define BUTTONS_COUNT_THRESHOLD	3
+
+static const unsigned short sgi_map[] = {
+	KEY_VOLUMEDOWN,
+	KEY_VOLUMEUP
+};
+
+struct buttons_dev {
+	struct input_polled_dev *poll_dev;
+	unsigned short keymap[ARRAY_SIZE(sgi_map)];
+	int count[ARRAY_SIZE(sgi_map)];
+};
+
+static void handle_buttons(struct input_polled_dev *dev)
+{
+	struct buttons_dev *bdev = dev->private;
+	struct input_dev *input = dev->input;
+	u8 status;
+	int i;
+
+	status = button_status();
+
+	for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) {
+		if (status & (1U << i)) {
+			if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) {
+				input_event(input, EV_MSC, MSC_SCAN, i);
+				input_report_key(input, bdev->keymap[i], 1);
+				input_sync(input);
+			}
+		} else {
+			if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) {
+				input_event(input, EV_MSC, MSC_SCAN, i);
+				input_report_key(input, bdev->keymap[i], 0);
+				input_sync(input);
+			}
+			bdev->count[i] = 0;
+		}
+	}
+}
+
+static int __devinit sgi_buttons_probe(struct platform_device *pdev)
+{
+	struct buttons_dev *bdev;
+	struct input_polled_dev *poll_dev;
+	struct input_dev *input;
+	int error, i;
+
+	bdev = kzalloc(sizeof(struct buttons_dev), GFP_KERNEL);
+	poll_dev = input_allocate_polled_device();
+	if (!bdev || !poll_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	memcpy(bdev->keymap, sgi_map, sizeof(bdev->keymap));
+
+	poll_dev->private = bdev;
+	poll_dev->poll = handle_buttons;
+	poll_dev->poll_interval = BUTTONS_POLL_INTERVAL;
+
+	input = poll_dev->input;
+	input->name = "SGI buttons";
+	input->phys = "sgi/input0";
+	input->id.bustype = BUS_HOST;
+	input->dev.parent = &pdev->dev;
+
+	input->keycode = bdev->keymap;
+	input->keycodemax = ARRAY_SIZE(bdev->keymap);
+	input->keycodesize = sizeof(unsigned short);
+
+	input_set_capability(input, EV_MSC, MSC_SCAN);
+	__set_bit(EV_KEY, input->evbit);
+	for (i = 0; i < ARRAY_SIZE(sgi_map); i++)
+		__set_bit(bdev->keymap[i], input->keybit);
+	__clear_bit(KEY_RESERVED, input->keybit);
+
+	bdev->poll_dev = poll_dev;
+	dev_set_drvdata(&pdev->dev, bdev);
+
+	error = input_register_polled_device(poll_dev);
+	if (error)
+		goto err_free_mem;
+
+	return 0;
+
+ err_free_mem:
+	input_free_polled_device(poll_dev);
+	kfree(bdev);
+	dev_set_drvdata(&pdev->dev, NULL);
+	return error;
+}
+
+static int __devexit sgi_buttons_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct buttons_dev *bdev = dev_get_drvdata(dev);
+
+	input_unregister_polled_device(bdev->poll_dev);
+	input_free_polled_device(bdev->poll_dev);
+	kfree(bdev);
+	dev_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver sgi_buttons_driver = {
+	.probe	= sgi_buttons_probe,
+	.remove	= __devexit_p(sgi_buttons_remove),
+	.driver	= {
+		.name	= "sgibtns",
+		.owner	= THIS_MODULE,
+	},
+};
+module_platform_driver(sgi_buttons_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/sparcspkr.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/sparcspkr.c
new file mode 100644
index 0000000..0122f53
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/sparcspkr.c
@@ -0,0 +1,372 @@
+/*
+ *  Driver for PC-speaker like devices found on various Sparc systems.
+ *
+ *  Copyright (c) 2002 Vojtech Pavlik
+ *  Copyright (c) 2002, 2006, 2008 David S. Miller (davem@davemloft.net)
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("Sparc Speaker beeper driver");
+MODULE_LICENSE("GPL");
+
+struct grover_beep_info {
+	void __iomem	*freq_regs;
+	void __iomem	*enable_reg;
+};
+
+struct bbc_beep_info {
+	u32		clock_freq;
+	void __iomem	*regs;
+};
+
+struct sparcspkr_state {
+	const char		*name;
+	int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+	spinlock_t		lock;
+	struct input_dev	*input_dev;
+	union {
+		struct grover_beep_info grover;
+		struct bbc_beep_info bbc;
+	} u;
+};
+
+static u32 bbc_count_to_reg(struct bbc_beep_info *info, unsigned int count)
+{
+	u32 val, clock_freq = info->clock_freq;
+	int i;
+
+	if (!count)
+		return 0;
+
+	if (count <= clock_freq >> 20)
+		return 1 << 18;
+
+	if (count >= clock_freq >> 12)
+		return 1 << 10;
+
+	val = 1 << 18;
+	for (i = 19; i >= 11; i--) {
+		val >>= 1;
+		if (count <= clock_freq >> i)
+			break;
+	}
+
+	return val;
+}
+
+static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
+	struct bbc_beep_info *info = &state->u.bbc;
+	unsigned int count = 0;
+	unsigned long flags;
+
+	if (type != EV_SND)
+		return -1;
+
+	switch (code) {
+		case SND_BELL: if (value) value = 1000;
+		case SND_TONE: break;
+		default: return -1;
+	}
+
+	if (value > 20 && value < 32767)
+		count = 1193182 / value;
+
+	count = bbc_count_to_reg(info, count);
+
+	spin_lock_irqsave(&state->lock, flags);
+
+	if (count) {
+		outb(0x01,                 info->regs + 0);
+		outb(0x00,                 info->regs + 2);
+		outb((count >> 16) & 0xff, info->regs + 3);
+		outb((count >>  8) & 0xff, info->regs + 4);
+		outb(0x00,                 info->regs + 5);
+	} else {
+		outb(0x00,                 info->regs + 0);
+	}
+
+	spin_unlock_irqrestore(&state->lock, flags);
+
+	return 0;
+}
+
+static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
+	struct grover_beep_info *info = &state->u.grover;
+	unsigned int count = 0;
+	unsigned long flags;
+
+	if (type != EV_SND)
+		return -1;
+
+	switch (code) {
+		case SND_BELL: if (value) value = 1000;
+		case SND_TONE: break;
+		default: return -1;
+	}
+
+	if (value > 20 && value < 32767)
+		count = 1193182 / value;
+
+	spin_lock_irqsave(&state->lock, flags);
+
+	if (count) {
+		/* enable counter 2 */
+		outb(inb(info->enable_reg) | 3, info->enable_reg);
+		/* set command for counter 2, 2 byte write */
+		outb(0xB6, info->freq_regs + 1);
+		/* select desired HZ */
+		outb(count & 0xff, info->freq_regs + 0);
+		outb((count >> 8) & 0xff, info->freq_regs + 0);
+	} else {
+		/* disable counter 2 */
+		outb(inb_p(info->enable_reg) & 0xFC, info->enable_reg);
+	}
+
+	spin_unlock_irqrestore(&state->lock, flags);
+
+	return 0;
+}
+
+static int __devinit sparcspkr_probe(struct device *dev)
+{
+	struct sparcspkr_state *state = dev_get_drvdata(dev);
+	struct input_dev *input_dev;
+	int error;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	input_dev->name = state->name;
+	input_dev->phys = "sparc/input0";
+	input_dev->id.bustype = BUS_ISA;
+	input_dev->id.vendor = 0x001f;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_SND);
+	input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+
+	input_dev->event = state->event;
+
+	error = input_register_device(input_dev);
+	if (error) {
+		input_free_device(input_dev);
+		return error;
+	}
+
+	state->input_dev = input_dev;
+
+	return 0;
+}
+
+static void sparcspkr_shutdown(struct platform_device *dev)
+{
+	struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
+	struct input_dev *input_dev = state->input_dev;
+
+	/* turn off the speaker */
+	state->event(input_dev, EV_SND, SND_BELL, 0);
+}
+
+static int __devinit bbc_beep_probe(struct platform_device *op)
+{
+	struct sparcspkr_state *state;
+	struct bbc_beep_info *info;
+	struct device_node *dp;
+	int err = -ENOMEM;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		goto out_err;
+
+	state->name = "Sparc BBC Speaker";
+	state->event = bbc_spkr_event;
+	spin_lock_init(&state->lock);
+
+	dp = of_find_node_by_path("/");
+	err = -ENODEV;
+	if (!dp)
+		goto out_free;
+
+	info = &state->u.bbc;
+	info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0);
+	if (!info->clock_freq)
+		goto out_free;
+
+	info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep");
+	if (!info->regs)
+		goto out_free;
+
+	dev_set_drvdata(&op->dev, state);
+
+	err = sparcspkr_probe(&op->dev);
+	if (err)
+		goto out_clear_drvdata;
+
+	return 0;
+
+out_clear_drvdata:
+	dev_set_drvdata(&op->dev, NULL);
+	of_iounmap(&op->resource[0], info->regs, 6);
+
+out_free:
+	kfree(state);
+out_err:
+	return err;
+}
+
+static int __devexit bbc_remove(struct platform_device *op)
+{
+	struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
+	struct input_dev *input_dev = state->input_dev;
+	struct bbc_beep_info *info = &state->u.bbc;
+
+	/* turn off the speaker */
+	state->event(input_dev, EV_SND, SND_BELL, 0);
+
+	input_unregister_device(input_dev);
+
+	of_iounmap(&op->resource[0], info->regs, 6);
+
+	dev_set_drvdata(&op->dev, NULL);
+	kfree(state);
+
+	return 0;
+}
+
+static const struct of_device_id bbc_beep_match[] = {
+	{
+		.name = "beep",
+		.compatible = "SUNW,bbc-beep",
+	},
+	{},
+};
+
+static struct platform_driver bbc_beep_driver = {
+	.driver = {
+		.name = "bbcbeep",
+		.owner = THIS_MODULE,
+		.of_match_table = bbc_beep_match,
+	},
+	.probe		= bbc_beep_probe,
+	.remove		= __devexit_p(bbc_remove),
+	.shutdown	= sparcspkr_shutdown,
+};
+
+static int __devinit grover_beep_probe(struct platform_device *op)
+{
+	struct sparcspkr_state *state;
+	struct grover_beep_info *info;
+	int err = -ENOMEM;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		goto out_err;
+
+	state->name = "Sparc Grover Speaker";
+	state->event = grover_spkr_event;
+	spin_lock_init(&state->lock);
+
+	info = &state->u.grover;
+	info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq");
+	if (!info->freq_regs)
+		goto out_free;
+
+	info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable");
+	if (!info->enable_reg)
+		goto out_unmap_freq_regs;
+
+	dev_set_drvdata(&op->dev, state);
+
+	err = sparcspkr_probe(&op->dev);
+	if (err)
+		goto out_clear_drvdata;
+
+	return 0;
+
+out_clear_drvdata:
+	dev_set_drvdata(&op->dev, NULL);
+	of_iounmap(&op->resource[3], info->enable_reg, 1);
+
+out_unmap_freq_regs:
+	of_iounmap(&op->resource[2], info->freq_regs, 2);
+out_free:
+	kfree(state);
+out_err:
+	return err;
+}
+
+static int __devexit grover_remove(struct platform_device *op)
+{
+	struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
+	struct grover_beep_info *info = &state->u.grover;
+	struct input_dev *input_dev = state->input_dev;
+
+	/* turn off the speaker */
+	state->event(input_dev, EV_SND, SND_BELL, 0);
+
+	input_unregister_device(input_dev);
+
+	of_iounmap(&op->resource[3], info->enable_reg, 1);
+	of_iounmap(&op->resource[2], info->freq_regs, 2);
+
+	dev_set_drvdata(&op->dev, NULL);
+	kfree(state);
+
+	return 0;
+}
+
+static const struct of_device_id grover_beep_match[] = {
+	{
+		.name = "beep",
+		.compatible = "SUNW,smbus-beep",
+	},
+	{},
+};
+
+static struct platform_driver grover_beep_driver = {
+	.driver = {
+		.name = "groverbeep",
+		.owner = THIS_MODULE,
+		.of_match_table = grover_beep_match,
+	},
+	.probe		= grover_beep_probe,
+	.remove		= __devexit_p(grover_remove),
+	.shutdown	= sparcspkr_shutdown,
+};
+
+static int __init sparcspkr_init(void)
+{
+	int err = platform_driver_register(&bbc_beep_driver);
+
+	if (!err) {
+		err = platform_driver_register(&grover_beep_driver);
+		if (err)
+			platform_driver_unregister(&bbc_beep_driver);
+	}
+
+	return err;
+}
+
+static void __exit sparcspkr_exit(void)
+{
+	platform_driver_unregister(&bbc_beep_driver);
+	platform_driver_unregister(&grover_beep_driver);
+}
+
+module_init(sparcspkr_init);
+module_exit(sparcspkr_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/twl4030-pwrbutton.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/twl4030-pwrbutton.c
new file mode 100644
index 0000000..38e4b50
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/twl4030-pwrbutton.c
@@ -0,0 +1,135 @@
+/**
+ * twl4030-pwrbutton.c - TWL4030 Power Button Input Driver
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Peter De Schrijver <peter.de-schrijver@nokia.com>
+ * Several fixes by Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl.h>
+
+#define PWR_PWRON_IRQ (1 << 0)
+
+#define STS_HW_CONDITIONS 0xf
+
+static irqreturn_t powerbutton_irq(int irq, void *_pwr)
+{
+	struct input_dev *pwr = _pwr;
+	int err;
+	u8 value;
+
+	err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,
+				STS_HW_CONDITIONS);
+	if (!err)  {
+		input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ);
+		input_sync(pwr);
+	} else {
+		dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading"
+			" TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)
+{
+	struct input_dev *pwr;
+	int irq = platform_get_irq(pdev, 0);
+	int err;
+
+	pwr = input_allocate_device();
+	if (!pwr) {
+		dev_dbg(&pdev->dev, "Can't allocate power button\n");
+		return -ENOMEM;
+	}
+
+	pwr->evbit[0] = BIT_MASK(EV_KEY);
+	pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+	pwr->name = "twl4030_pwrbutton";
+	pwr->phys = "twl4030_pwrbutton/input0";
+	pwr->dev.parent = &pdev->dev;
+
+	err = request_threaded_irq(irq, NULL, powerbutton_irq,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+			"twl4030_pwrbutton", pwr);
+	if (err < 0) {
+		dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err);
+		goto free_input_dev;
+	}
+
+	err = input_register_device(pwr);
+	if (err) {
+		dev_dbg(&pdev->dev, "Can't register power button: %d\n", err);
+		goto free_irq;
+	}
+
+	platform_set_drvdata(pdev, pwr);
+
+	return 0;
+
+free_irq:
+	free_irq(irq, pwr);
+free_input_dev:
+	input_free_device(pwr);
+	return err;
+}
+
+static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev)
+{
+	struct input_dev *pwr = platform_get_drvdata(pdev);
+	int irq = platform_get_irq(pdev, 0);
+
+	free_irq(irq, pwr);
+	input_unregister_device(pwr);
+
+	return 0;
+}
+
+static struct platform_driver twl4030_pwrbutton_driver = {
+	.remove		= __exit_p(twl4030_pwrbutton_remove),
+	.driver		= {
+		.name	= "twl4030_pwrbutton",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init twl4030_pwrbutton_init(void)
+{
+	return platform_driver_probe(&twl4030_pwrbutton_driver,
+			twl4030_pwrbutton_probe);
+}
+module_init(twl4030_pwrbutton_init);
+
+static void __exit twl4030_pwrbutton_exit(void)
+{
+	platform_driver_unregister(&twl4030_pwrbutton_driver);
+}
+module_exit(twl4030_pwrbutton_exit);
+
+MODULE_ALIAS("platform:twl4030_pwrbutton");
+MODULE_DESCRIPTION("Triton2 Power Button");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter De Schrijver <peter.de-schrijver@nokia.com>");
+MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>");
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/twl4030-vibra.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/twl4030-vibra.c
new file mode 100644
index 0000000..fc0ed9b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/twl4030-vibra.c
@@ -0,0 +1,284 @@
+/*
+ * twl4030-vibra.c - TWL4030 Vibrator driver
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * Written by Henrik Saari <henrik.saari@nokia.com>
+ * Updates by Felipe Balbi <felipe.balbi@nokia.com>
+ * Input by Jari Vanhala <ext-jari.vanhala@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/i2c/twl.h>
+#include <linux/mfd/twl4030-audio.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+/* MODULE ID2 */
+#define LEDEN		0x00
+
+/* ForceFeedback */
+#define EFFECT_DIR_180_DEG	0x8000 /* range is 0 - 0xFFFF */
+
+struct vibra_info {
+	struct device		*dev;
+	struct input_dev	*input_dev;
+
+	struct workqueue_struct *workqueue;
+	struct work_struct	play_work;
+
+	bool			enabled;
+	int			speed;
+	int			direction;
+
+	bool			coexist;
+};
+
+static void vibra_disable_leds(void)
+{
+	u8 reg;
+
+	/* Disable LEDA & LEDB, cannot be used with vibra (PWM) */
+	twl_i2c_read_u8(TWL4030_MODULE_LED, &reg, LEDEN);
+	reg &= ~0x03;
+	twl_i2c_write_u8(TWL4030_MODULE_LED, LEDEN, reg);
+}
+
+/* Powers H-Bridge and enables audio clk */
+static void vibra_enable(struct vibra_info *info)
+{
+	u8 reg;
+
+	twl4030_audio_enable_resource(TWL4030_AUDIO_RES_POWER);
+
+	/* turn H-Bridge on */
+	twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
+			&reg, TWL4030_REG_VIBRA_CTL);
+	twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+			 (reg | TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
+
+	twl4030_audio_enable_resource(TWL4030_AUDIO_RES_APLL);
+
+	info->enabled = true;
+}
+
+static void vibra_disable(struct vibra_info *info)
+{
+	u8 reg;
+
+	/* Power down H-Bridge */
+	twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
+			&reg, TWL4030_REG_VIBRA_CTL);
+	twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+			 (reg & ~TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
+
+	twl4030_audio_disable_resource(TWL4030_AUDIO_RES_APLL);
+	twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER);
+
+	info->enabled = false;
+}
+
+static void vibra_play_work(struct work_struct *work)
+{
+	struct vibra_info *info = container_of(work,
+			struct vibra_info, play_work);
+	int dir;
+	int pwm;
+	u8 reg;
+
+	dir = info->direction;
+	pwm = info->speed;
+
+	twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
+			&reg, TWL4030_REG_VIBRA_CTL);
+	if (pwm && (!info->coexist || !(reg & TWL4030_VIBRA_SEL))) {
+
+		if (!info->enabled)
+			vibra_enable(info);
+
+		/* set vibra rotation direction */
+		twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
+				&reg, TWL4030_REG_VIBRA_CTL);
+		reg = (dir) ? (reg | TWL4030_VIBRA_DIR) :
+			(reg & ~TWL4030_VIBRA_DIR);
+		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+				 reg, TWL4030_REG_VIBRA_CTL);
+
+		/* set PWM, 1 = max, 255 = min */
+		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+				 256 - pwm, TWL4030_REG_VIBRA_SET);
+	} else {
+		if (info->enabled)
+			vibra_disable(info);
+	}
+}
+
+/*** Input/ForceFeedback ***/
+
+static int vibra_play(struct input_dev *input, void *data,
+		      struct ff_effect *effect)
+{
+	struct vibra_info *info = input_get_drvdata(input);
+
+	info->speed = effect->u.rumble.strong_magnitude >> 8;
+	if (!info->speed)
+		info->speed = effect->u.rumble.weak_magnitude >> 9;
+	info->direction = effect->direction < EFFECT_DIR_180_DEG ? 0 : 1;
+	queue_work(info->workqueue, &info->play_work);
+	return 0;
+}
+
+static int twl4030_vibra_open(struct input_dev *input)
+{
+	struct vibra_info *info = input_get_drvdata(input);
+
+	info->workqueue = create_singlethread_workqueue("vibra");
+	if (info->workqueue == NULL) {
+		dev_err(&input->dev, "couldn't create workqueue\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void twl4030_vibra_close(struct input_dev *input)
+{
+	struct vibra_info *info = input_get_drvdata(input);
+
+	cancel_work_sync(&info->play_work);
+	INIT_WORK(&info->play_work, vibra_play_work); /* cleanup */
+	destroy_workqueue(info->workqueue);
+	info->workqueue = NULL;
+
+	if (info->enabled)
+		vibra_disable(info);
+}
+
+/*** Module ***/
+#ifdef CONFIG_PM_SLEEP
+static int twl4030_vibra_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct vibra_info *info = platform_get_drvdata(pdev);
+
+	if (info->enabled)
+		vibra_disable(info);
+
+	return 0;
+}
+
+static int twl4030_vibra_resume(struct device *dev)
+{
+	vibra_disable_leds();
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
+			 twl4030_vibra_suspend, twl4030_vibra_resume);
+
+static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
+{
+	struct twl4030_vibra_data *pdata = pdev->dev.platform_data;
+	struct vibra_info *info;
+	int ret;
+
+	if (!pdata) {
+		dev_dbg(&pdev->dev, "platform_data not available\n");
+		return -EINVAL;
+	}
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->dev = &pdev->dev;
+	info->coexist = pdata->coexist;
+	INIT_WORK(&info->play_work, vibra_play_work);
+
+	info->input_dev = input_allocate_device();
+	if (info->input_dev == NULL) {
+		dev_err(&pdev->dev, "couldn't allocate input device\n");
+		ret = -ENOMEM;
+		goto err_kzalloc;
+	}
+
+	input_set_drvdata(info->input_dev, info);
+
+	info->input_dev->name = "twl4030:vibrator";
+	info->input_dev->id.version = 1;
+	info->input_dev->dev.parent = pdev->dev.parent;
+	info->input_dev->open = twl4030_vibra_open;
+	info->input_dev->close = twl4030_vibra_close;
+	__set_bit(FF_RUMBLE, info->input_dev->ffbit);
+
+	ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
+	if (ret < 0) {
+		dev_dbg(&pdev->dev, "couldn't register vibrator to FF\n");
+		goto err_ialloc;
+	}
+
+	ret = input_register_device(info->input_dev);
+	if (ret < 0) {
+		dev_dbg(&pdev->dev, "couldn't register input device\n");
+		goto err_iff;
+	}
+
+	vibra_disable_leds();
+
+	platform_set_drvdata(pdev, info);
+	return 0;
+
+err_iff:
+	input_ff_destroy(info->input_dev);
+err_ialloc:
+	input_free_device(info->input_dev);
+err_kzalloc:
+	kfree(info);
+	return ret;
+}
+
+static int __devexit twl4030_vibra_remove(struct platform_device *pdev)
+{
+	struct vibra_info *info = platform_get_drvdata(pdev);
+
+	/* this also free ff-memless and calls close if needed */
+	input_unregister_device(info->input_dev);
+	kfree(info);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver twl4030_vibra_driver = {
+	.probe		= twl4030_vibra_probe,
+	.remove		= __devexit_p(twl4030_vibra_remove),
+	.driver		= {
+		.name	= "twl4030-vibra",
+		.owner	= THIS_MODULE,
+		.pm	= &twl4030_vibra_pm_ops,
+	},
+};
+module_platform_driver(twl4030_vibra_driver);
+
+MODULE_ALIAS("platform:twl4030-vibra");
+MODULE_DESCRIPTION("TWL4030 Vibra driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nokia Corporation");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/twl6040-vibra.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/twl6040-vibra.c
new file mode 100644
index 0000000..14e94f5
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/twl6040-vibra.c
@@ -0,0 +1,419 @@
+/*
+ * twl6040-vibra.c - TWL6040 Vibrator driver
+ *
+ * Author:      Jorge Eduardo Candelaria <jorge.candelaria@ti.com>
+ * Author:      Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * Copyright:   (C) 2011 Texas Instruments, Inc.
+ *
+ * Based on twl4030-vibra.c by Henrik Saari <henrik.saari@nokia.com>
+ *				Felipe Balbi <felipe.balbi@nokia.com>
+ *				Jari Vanhala <ext-javi.vanhala@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+#include <linux/mfd/twl6040.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+
+#define EFFECT_DIR_180_DEG	0x8000
+
+/* Recommended modulation index 85% */
+#define TWL6040_VIBRA_MOD	85
+
+#define TWL6040_NUM_SUPPLIES 2
+
+struct vibra_info {
+	struct device *dev;
+	struct input_dev *input_dev;
+	struct workqueue_struct *workqueue;
+	struct work_struct play_work;
+	struct mutex mutex;
+	int irq;
+
+	bool enabled;
+	int weak_speed;
+	int strong_speed;
+	int direction;
+
+	unsigned int vibldrv_res;
+	unsigned int vibrdrv_res;
+	unsigned int viblmotor_res;
+	unsigned int vibrmotor_res;
+
+	struct regulator_bulk_data supplies[TWL6040_NUM_SUPPLIES];
+
+	struct twl6040 *twl6040;
+};
+
+static irqreturn_t twl6040_vib_irq_handler(int irq, void *data)
+{
+	struct vibra_info *info = data;
+	struct twl6040 *twl6040 = info->twl6040;
+	u8 status;
+
+	status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS);
+	if (status & TWL6040_VIBLOCDET) {
+		dev_warn(info->dev, "Left Vibrator overcurrent detected\n");
+		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
+				   TWL6040_VIBENA);
+	}
+	if (status & TWL6040_VIBROCDET) {
+		dev_warn(info->dev, "Right Vibrator overcurrent detected\n");
+		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
+				   TWL6040_VIBENA);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void twl6040_vibra_enable(struct vibra_info *info)
+{
+	struct twl6040 *twl6040 = info->twl6040;
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(info->supplies), info->supplies);
+	if (ret) {
+		dev_err(info->dev, "failed to enable regulators %d\n", ret);
+		return;
+	}
+
+	twl6040_power(info->twl6040, 1);
+	if (twl6040_get_revid(twl6040) <= TWL6040_REV_ES1_1) {
+		/*
+		 * ERRATA: Disable overcurrent protection for at least
+		 * 3ms when enabling vibrator drivers to avoid false
+		 * overcurrent detection
+		 */
+		twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
+				  TWL6040_VIBENA | TWL6040_VIBCTRL);
+		twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
+				  TWL6040_VIBENA | TWL6040_VIBCTRL);
+		usleep_range(3000, 3500);
+	}
+
+	twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
+			  TWL6040_VIBENA);
+	twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
+			  TWL6040_VIBENA);
+
+	info->enabled = true;
+}
+
+static void twl6040_vibra_disable(struct vibra_info *info)
+{
+	struct twl6040 *twl6040 = info->twl6040;
+
+	twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, 0x00);
+	twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, 0x00);
+	twl6040_power(info->twl6040, 0);
+
+	regulator_bulk_disable(ARRAY_SIZE(info->supplies), info->supplies);
+
+	info->enabled = false;
+}
+
+static u8 twl6040_vibra_code(int vddvib, int vibdrv_res, int motor_res,
+			     int speed, int direction)
+{
+	int vpk, max_code;
+	u8 vibdat;
+
+	/* output swing */
+	vpk = (vddvib * motor_res * TWL6040_VIBRA_MOD) /
+		(100 * (vibdrv_res + motor_res));
+
+	/* 50mV per VIBDAT code step */
+	max_code = vpk / 50;
+	if (max_code > TWL6040_VIBDAT_MAX)
+		max_code = TWL6040_VIBDAT_MAX;
+
+	/* scale speed to max allowed code */
+	vibdat = (u8)((speed * max_code) / USHRT_MAX);
+
+	/* 2's complement for direction > 180 degrees */
+	vibdat *= direction;
+
+	return vibdat;
+}
+
+static void twl6040_vibra_set_effect(struct vibra_info *info)
+{
+	struct twl6040 *twl6040 = info->twl6040;
+	u8 vibdatl, vibdatr;
+	int volt;
+
+	/* weak motor */
+	volt = regulator_get_voltage(info->supplies[0].consumer) / 1000;
+	vibdatl = twl6040_vibra_code(volt, info->vibldrv_res,
+				     info->viblmotor_res,
+				     info->weak_speed, info->direction);
+
+	/* strong motor */
+	volt = regulator_get_voltage(info->supplies[1].consumer) / 1000;
+	vibdatr = twl6040_vibra_code(volt, info->vibrdrv_res,
+				     info->vibrmotor_res,
+				     info->strong_speed, info->direction);
+
+	twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, vibdatl);
+	twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, vibdatr);
+}
+
+static void vibra_play_work(struct work_struct *work)
+{
+	struct vibra_info *info = container_of(work,
+				struct vibra_info, play_work);
+
+	mutex_lock(&info->mutex);
+
+	if (info->weak_speed || info->strong_speed) {
+		if (!info->enabled)
+			twl6040_vibra_enable(info);
+
+		twl6040_vibra_set_effect(info);
+	} else if (info->enabled)
+		twl6040_vibra_disable(info);
+
+	mutex_unlock(&info->mutex);
+}
+
+static int vibra_play(struct input_dev *input, void *data,
+		      struct ff_effect *effect)
+{
+	struct vibra_info *info = input_get_drvdata(input);
+	int ret;
+
+	/* Do not allow effect, while the routing is set to use audio */
+	ret = twl6040_get_vibralr_status(info->twl6040);
+	if (ret & TWL6040_VIBSEL) {
+		dev_info(&input->dev, "Vibra is configured for audio\n");
+		return -EBUSY;
+	}
+
+	info->weak_speed = effect->u.rumble.weak_magnitude;
+	info->strong_speed = effect->u.rumble.strong_magnitude;
+	info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1;
+
+	ret = queue_work(info->workqueue, &info->play_work);
+	if (!ret) {
+		dev_info(&input->dev, "work is already on queue\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void twl6040_vibra_close(struct input_dev *input)
+{
+	struct vibra_info *info = input_get_drvdata(input);
+
+	cancel_work_sync(&info->play_work);
+
+	mutex_lock(&info->mutex);
+
+	if (info->enabled)
+		twl6040_vibra_disable(info);
+
+	mutex_unlock(&info->mutex);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int twl6040_vibra_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct vibra_info *info = platform_get_drvdata(pdev);
+
+	mutex_lock(&info->mutex);
+
+	if (info->enabled)
+		twl6040_vibra_disable(info);
+
+	mutex_unlock(&info->mutex);
+
+	return 0;
+}
+
+#endif
+
+static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
+
+static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
+{
+	struct twl6040_vibra_data *pdata = pdev->dev.platform_data;
+	struct vibra_info *info;
+	int ret;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform_data not available\n");
+		return -EINVAL;
+	}
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		dev_err(&pdev->dev, "couldn't allocate memory\n");
+		return -ENOMEM;
+	}
+
+	info->dev = &pdev->dev;
+	info->twl6040 = dev_get_drvdata(pdev->dev.parent);
+	info->vibldrv_res = pdata->vibldrv_res;
+	info->vibrdrv_res = pdata->vibrdrv_res;
+	info->viblmotor_res = pdata->viblmotor_res;
+	info->vibrmotor_res = pdata->vibrmotor_res;
+	if ((!info->vibldrv_res && !info->viblmotor_res) ||
+	    (!info->vibrdrv_res && !info->vibrmotor_res)) {
+		dev_err(info->dev, "invalid vibra driver/motor resistance\n");
+		ret = -EINVAL;
+		goto err_kzalloc;
+	}
+
+	info->irq = platform_get_irq(pdev, 0);
+	if (info->irq < 0) {
+		dev_err(info->dev, "invalid irq\n");
+		ret = -EINVAL;
+		goto err_kzalloc;
+	}
+
+	mutex_init(&info->mutex);
+
+	info->input_dev = input_allocate_device();
+	if (info->input_dev == NULL) {
+		dev_err(info->dev, "couldn't allocate input device\n");
+		ret = -ENOMEM;
+		goto err_kzalloc;
+	}
+
+	input_set_drvdata(info->input_dev, info);
+
+	info->input_dev->name = "twl6040:vibrator";
+	info->input_dev->id.version = 1;
+	info->input_dev->dev.parent = pdev->dev.parent;
+	info->input_dev->close = twl6040_vibra_close;
+	__set_bit(FF_RUMBLE, info->input_dev->ffbit);
+
+	ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
+	if (ret < 0) {
+		dev_err(info->dev, "couldn't register vibrator to FF\n");
+		goto err_ialloc;
+	}
+
+	ret = input_register_device(info->input_dev);
+	if (ret < 0) {
+		dev_err(info->dev, "couldn't register input device\n");
+		goto err_iff;
+	}
+
+	platform_set_drvdata(pdev, info);
+
+	ret = request_threaded_irq(info->irq, NULL, twl6040_vib_irq_handler, 0,
+				   "twl6040_irq_vib", info);
+	if (ret) {
+		dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
+		goto err_irq;
+	}
+
+	info->supplies[0].supply = "vddvibl";
+	info->supplies[1].supply = "vddvibr";
+	ret = regulator_bulk_get(info->dev, ARRAY_SIZE(info->supplies),
+				 info->supplies);
+	if (ret) {
+		dev_err(info->dev, "couldn't get regulators %d\n", ret);
+		goto err_regulator;
+	}
+
+	if (pdata->vddvibl_uV) {
+		ret = regulator_set_voltage(info->supplies[0].consumer,
+					    pdata->vddvibl_uV,
+					    pdata->vddvibl_uV);
+		if (ret) {
+			dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
+				ret);
+			goto err_voltage;
+		}
+	}
+
+	if (pdata->vddvibr_uV) {
+		ret = regulator_set_voltage(info->supplies[1].consumer,
+					    pdata->vddvibr_uV,
+					    pdata->vddvibr_uV);
+		if (ret) {
+			dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
+				ret);
+			goto err_voltage;
+		}
+	}
+
+	info->workqueue = alloc_workqueue("twl6040-vibra", 0, 0);
+	if (info->workqueue == NULL) {
+		dev_err(info->dev, "couldn't create workqueue\n");
+		ret = -ENOMEM;
+		goto err_voltage;
+	}
+	INIT_WORK(&info->play_work, vibra_play_work);
+
+	return 0;
+
+err_voltage:
+	regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
+err_regulator:
+	free_irq(info->irq, info);
+err_irq:
+	input_unregister_device(info->input_dev);
+	info->input_dev = NULL;
+err_iff:
+	if (info->input_dev)
+		input_ff_destroy(info->input_dev);
+err_ialloc:
+	input_free_device(info->input_dev);
+err_kzalloc:
+	kfree(info);
+	return ret;
+}
+
+static int __devexit twl6040_vibra_remove(struct platform_device *pdev)
+{
+	struct vibra_info *info = platform_get_drvdata(pdev);
+
+	input_unregister_device(info->input_dev);
+	free_irq(info->irq, info);
+	regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
+	destroy_workqueue(info->workqueue);
+	kfree(info);
+
+	return 0;
+}
+
+static struct platform_driver twl6040_vibra_driver = {
+	.probe		= twl6040_vibra_probe,
+	.remove		= __devexit_p(twl6040_vibra_remove),
+	.driver		= {
+		.name	= "twl6040-vibra",
+		.owner	= THIS_MODULE,
+		.pm	= &twl6040_vibra_pm_ops,
+	},
+};
+module_platform_driver(twl6040_vibra_driver);
+
+MODULE_ALIAS("platform:twl6040-vibra");
+MODULE_DESCRIPTION("TWL6040 Vibra driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jorge Eduardo Candelaria <jorge.candelaria@ti.com>");
+MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/uinput.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/uinput.c
new file mode 100644
index 0000000..7360568
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/uinput.c
@@ -0,0 +1,834 @@
+/*
+ *  User level driver support for input subsystem
+ *
+ * Heavily based on evdev.c by Vojtech Pavlik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
+ *
+ * Changes/Revisions:
+ *	0.3	09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>)
+ *		- updated ff support for the changes in kernel interface
+ *		- added MODULE_VERSION
+ *	0.2	16/10/2004 (Micah Dowty <micah@navi.cx>)
+ *		- added force feedback support
+ *              - added UI_SET_PHYS
+ *	0.1	20/06/2002
+ *		- first public version
+ */
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uinput.h>
+#include <linux/input/mt.h>
+#include "../input-compat.h"
+
+static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct uinput_device	*udev = input_get_drvdata(dev);
+
+	udev->buff[udev->head].type = type;
+	udev->buff[udev->head].code = code;
+	udev->buff[udev->head].value = value;
+	do_gettimeofday(&udev->buff[udev->head].time);
+	udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
+
+	wake_up_interruptible(&udev->waitq);
+
+	return 0;
+}
+
+/* Atomically allocate an ID for the given request. Returns 0 on success. */
+static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request)
+{
+	int id;
+	int err = -1;
+
+	spin_lock(&udev->requests_lock);
+
+	for (id = 0; id < UINPUT_NUM_REQUESTS; id++) {
+		if (!udev->requests[id]) {
+			request->id = id;
+			udev->requests[id] = request;
+			err = 0;
+			break;
+		}
+	}
+
+	spin_unlock(&udev->requests_lock);
+	return err;
+}
+
+static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id)
+{
+	/* Find an input request, by ID. Returns NULL if the ID isn't valid. */
+	if (id >= UINPUT_NUM_REQUESTS || id < 0)
+		return NULL;
+
+	return udev->requests[id];
+}
+
+static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request)
+{
+	/* Allocate slot. If none are available right away, wait. */
+	return wait_event_interruptible(udev->requests_waitq,
+					!uinput_request_alloc_id(udev, request));
+}
+
+static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request)
+{
+	/* Mark slot as available */
+	udev->requests[request->id] = NULL;
+	wake_up(&udev->requests_waitq);
+
+	complete(&request->done);
+}
+
+static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request)
+{
+	int retval;
+
+	retval = uinput_request_reserve_slot(udev, request);
+	if (retval)
+		return retval;
+
+	retval = mutex_lock_interruptible(&udev->mutex);
+	if (retval)
+		return retval;
+
+	if (udev->state != UIST_CREATED) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	/* Tell our userspace app about this new request by queueing an input event */
+	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
+
+ out:
+	mutex_unlock(&udev->mutex);
+	return retval;
+}
+
+/*
+ * Fail all ouitstanding requests so handlers don't wait for the userspace
+ * to finish processing them.
+ */
+static void uinput_flush_requests(struct uinput_device *udev)
+{
+	struct uinput_request *request;
+	int i;
+
+	spin_lock(&udev->requests_lock);
+
+	for (i = 0; i < UINPUT_NUM_REQUESTS; i++) {
+		request = udev->requests[i];
+		if (request) {
+			request->retval = -ENODEV;
+			uinput_request_done(udev, request);
+		}
+	}
+
+	spin_unlock(&udev->requests_lock);
+}
+
+static void uinput_dev_set_gain(struct input_dev *dev, u16 gain)
+{
+	uinput_dev_event(dev, EV_FF, FF_GAIN, gain);
+}
+
+static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+	uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude);
+}
+
+static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value)
+{
+	return uinput_dev_event(dev, EV_FF, effect_id, value);
+}
+
+static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
+{
+	struct uinput_device *udev = input_get_drvdata(dev);
+	struct uinput_request request;
+	int retval;
+
+	/*
+	 * uinput driver does not currently support periodic effects with
+	 * custom waveform since it does not have a way to pass buffer of
+	 * samples (custom_data) to userspace. If ever there is a device
+	 * supporting custom waveforms we would need to define an additional
+	 * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out.
+	 */
+	if (effect->type == FF_PERIODIC &&
+			effect->u.periodic.waveform == FF_CUSTOM)
+		return -EINVAL;
+
+	request.id = -1;
+	init_completion(&request.done);
+	request.code = UI_FF_UPLOAD;
+	request.u.upload.effect = effect;
+	request.u.upload.old = old;
+
+	retval = uinput_request_submit(udev, &request);
+	if (!retval) {
+		wait_for_completion(&request.done);
+		retval = request.retval;
+	}
+
+	return retval;
+}
+
+static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
+{
+	struct uinput_device *udev = input_get_drvdata(dev);
+	struct uinput_request request;
+	int retval;
+
+	if (!test_bit(EV_FF, dev->evbit))
+		return -ENOSYS;
+
+	request.id = -1;
+	init_completion(&request.done);
+	request.code = UI_FF_ERASE;
+	request.u.effect_id = effect_id;
+
+	retval = uinput_request_submit(udev, &request);
+	if (!retval) {
+		wait_for_completion(&request.done);
+		retval = request.retval;
+	}
+
+	return retval;
+}
+
+static void uinput_destroy_device(struct uinput_device *udev)
+{
+	const char *name, *phys;
+	struct input_dev *dev = udev->dev;
+	enum uinput_state old_state = udev->state;
+
+	udev->state = UIST_NEW_DEVICE;
+
+	if (dev) {
+		name = dev->name;
+		phys = dev->phys;
+		if (old_state == UIST_CREATED) {
+			uinput_flush_requests(udev);
+			input_unregister_device(dev);
+		} else {
+			input_free_device(dev);
+		}
+		kfree(name);
+		kfree(phys);
+		udev->dev = NULL;
+	}
+}
+
+static int uinput_create_device(struct uinput_device *udev)
+{
+	struct input_dev *dev = udev->dev;
+	int error;
+
+	if (udev->state != UIST_SETUP_COMPLETE) {
+		printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
+		return -EINVAL;
+	}
+
+	if (udev->ff_effects_max) {
+		error = input_ff_create(dev, udev->ff_effects_max);
+		if (error)
+			goto fail1;
+
+		dev->ff->upload = uinput_dev_upload_effect;
+		dev->ff->erase = uinput_dev_erase_effect;
+		dev->ff->playback = uinput_dev_playback;
+		dev->ff->set_gain = uinput_dev_set_gain;
+		dev->ff->set_autocenter = uinput_dev_set_autocenter;
+	}
+
+	error = input_register_device(udev->dev);
+	if (error)
+		goto fail2;
+
+	udev->state = UIST_CREATED;
+
+	return 0;
+
+ fail2:	input_ff_destroy(dev);
+ fail1: uinput_destroy_device(udev);
+	return error;
+}
+
+static int uinput_open(struct inode *inode, struct file *file)
+{
+	struct uinput_device *newdev;
+
+	newdev = kzalloc(sizeof(struct uinput_device), GFP_KERNEL);
+	if (!newdev)
+		return -ENOMEM;
+
+	mutex_init(&newdev->mutex);
+	spin_lock_init(&newdev->requests_lock);
+	init_waitqueue_head(&newdev->requests_waitq);
+	init_waitqueue_head(&newdev->waitq);
+	newdev->state = UIST_NEW_DEVICE;
+
+	file->private_data = newdev;
+	nonseekable_open(inode, file);
+
+	return 0;
+}
+
+static int uinput_validate_absbits(struct input_dev *dev)
+{
+	unsigned int cnt;
+	int retval = 0;
+
+	for (cnt = 0; cnt < ABS_CNT; cnt++) {
+		int min, max;
+		if (!test_bit(cnt, dev->absbit))
+			continue;
+
+		min = input_abs_get_min(dev, cnt);
+		max = input_abs_get_max(dev, cnt);
+
+		if ((min != 0 || max != 0) && max <= min) {
+			printk(KERN_DEBUG
+				"%s: invalid abs[%02x] min:%d max:%d\n",
+				UINPUT_NAME, cnt,
+				input_abs_get_min(dev, cnt),
+				input_abs_get_max(dev, cnt));
+			retval = -EINVAL;
+			break;
+		}
+
+		if (input_abs_get_flat(dev, cnt) >
+		    input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) {
+			printk(KERN_DEBUG
+				"%s: abs_flat #%02x out of range: %d "
+				"(min:%d/max:%d)\n",
+				UINPUT_NAME, cnt,
+				input_abs_get_flat(dev, cnt),
+				input_abs_get_min(dev, cnt),
+				input_abs_get_max(dev, cnt));
+			retval = -EINVAL;
+			break;
+		}
+	}
+	return retval;
+}
+
+static int uinput_allocate_device(struct uinput_device *udev)
+{
+	udev->dev = input_allocate_device();
+	if (!udev->dev)
+		return -ENOMEM;
+
+	udev->dev->event = uinput_dev_event;
+	input_set_drvdata(udev->dev, udev);
+
+	return 0;
+}
+
+static int uinput_setup_device(struct uinput_device *udev, const char __user *buffer, size_t count)
+{
+	struct uinput_user_dev	*user_dev;
+	struct input_dev	*dev;
+	int			i;
+	int			retval;
+
+	if (count != sizeof(struct uinput_user_dev))
+		return -EINVAL;
+
+	if (!udev->dev) {
+		retval = uinput_allocate_device(udev);
+		if (retval)
+			return retval;
+	}
+
+	dev = udev->dev;
+
+	user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev));
+	if (IS_ERR(user_dev))
+		return PTR_ERR(user_dev);
+
+	udev->ff_effects_max = user_dev->ff_effects_max;
+
+	/* Ensure name is filled in */
+	if (!user_dev->name[0]) {
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	kfree(dev->name);
+	dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE,
+			     GFP_KERNEL);
+	if (!dev->name) {
+		retval = -ENOMEM;
+		goto exit;
+	}
+
+	dev->id.bustype	= user_dev->id.bustype;
+	dev->id.vendor	= user_dev->id.vendor;
+	dev->id.product	= user_dev->id.product;
+	dev->id.version	= user_dev->id.version;
+
+	for (i = 0; i < ABS_CNT; i++) {
+		input_abs_set_max(dev, i, user_dev->absmax[i]);
+		input_abs_set_min(dev, i, user_dev->absmin[i]);
+		input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]);
+		input_abs_set_flat(dev, i, user_dev->absflat[i]);
+	}
+
+	/* check if absmin/absmax/absfuzz/absflat are filled as
+	 * told in Documentation/input/input-programming.txt */
+	if (test_bit(EV_ABS, dev->evbit)) {
+		retval = uinput_validate_absbits(dev);
+		if (retval < 0)
+			goto exit;
+		if (test_bit(ABS_MT_SLOT, dev->absbit)) {
+			int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
+			input_mt_init_slots(dev, nslot);
+		} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
+			input_set_events_per_packet(dev, 60);
+		}
+	}
+
+	udev->state = UIST_SETUP_COMPLETE;
+	retval = count;
+
+ exit:
+	kfree(user_dev);
+	return retval;
+}
+
+static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char __user *buffer, size_t count)
+{
+	struct input_event ev;
+
+	if (count < input_event_size())
+		return -EINVAL;
+
+	if (input_event_from_user(buffer, &ev))
+		return -EFAULT;
+
+	input_event(udev->dev, ev.type, ev.code, ev.value);
+
+	return input_event_size();
+}
+
+static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+{
+	struct uinput_device *udev = file->private_data;
+	int retval;
+
+	retval = mutex_lock_interruptible(&udev->mutex);
+	if (retval)
+		return retval;
+
+	retval = udev->state == UIST_CREATED ?
+			uinput_inject_event(udev, buffer, count) :
+			uinput_setup_device(udev, buffer, count);
+
+	mutex_unlock(&udev->mutex);
+
+	return retval;
+}
+
+static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+	struct uinput_device *udev = file->private_data;
+	int retval = 0;
+
+	if (udev->state != UIST_CREATED)
+		return -ENODEV;
+
+	if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+
+	retval = wait_event_interruptible(udev->waitq,
+			udev->head != udev->tail || udev->state != UIST_CREATED);
+	if (retval)
+		return retval;
+
+	retval = mutex_lock_interruptible(&udev->mutex);
+	if (retval)
+		return retval;
+
+	if (udev->state != UIST_CREATED) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	while (udev->head != udev->tail && retval + input_event_size() <= count) {
+		if (input_event_to_user(buffer + retval, &udev->buff[udev->tail])) {
+			retval = -EFAULT;
+			goto out;
+		}
+		udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
+		retval += input_event_size();
+	}
+
+ out:
+	mutex_unlock(&udev->mutex);
+
+	return retval;
+}
+
+static unsigned int uinput_poll(struct file *file, poll_table *wait)
+{
+	struct uinput_device *udev = file->private_data;
+
+	poll_wait(file, &udev->waitq, wait);
+
+	if (udev->head != udev->tail)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+static int uinput_release(struct inode *inode, struct file *file)
+{
+	struct uinput_device *udev = file->private_data;
+
+	uinput_destroy_device(udev);
+	kfree(udev);
+
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+struct uinput_ff_upload_compat {
+	int			request_id;
+	int			retval;
+	struct ff_effect_compat	effect;
+	struct ff_effect_compat	old;
+};
+
+static int uinput_ff_upload_to_user(char __user *buffer,
+				    const struct uinput_ff_upload *ff_up)
+{
+	if (INPUT_COMPAT_TEST) {
+		struct uinput_ff_upload_compat ff_up_compat;
+
+		ff_up_compat.request_id = ff_up->request_id;
+		ff_up_compat.retval = ff_up->retval;
+		/*
+		 * It so happens that the pointer that gives us the trouble
+		 * is the last field in the structure. Since we don't support
+		 * custom waveforms in uinput anyway we can just copy the whole
+		 * thing (to the compat size) and ignore the pointer.
+		 */
+		memcpy(&ff_up_compat.effect, &ff_up->effect,
+			sizeof(struct ff_effect_compat));
+		memcpy(&ff_up_compat.old, &ff_up->old,
+			sizeof(struct ff_effect_compat));
+
+		if (copy_to_user(buffer, &ff_up_compat,
+				 sizeof(struct uinput_ff_upload_compat)))
+			return -EFAULT;
+	} else {
+		if (copy_to_user(buffer, ff_up,
+				 sizeof(struct uinput_ff_upload)))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int uinput_ff_upload_from_user(const char __user *buffer,
+				      struct uinput_ff_upload *ff_up)
+{
+	if (INPUT_COMPAT_TEST) {
+		struct uinput_ff_upload_compat ff_up_compat;
+
+		if (copy_from_user(&ff_up_compat, buffer,
+				   sizeof(struct uinput_ff_upload_compat)))
+			return -EFAULT;
+
+		ff_up->request_id = ff_up_compat.request_id;
+		ff_up->retval = ff_up_compat.retval;
+		memcpy(&ff_up->effect, &ff_up_compat.effect,
+			sizeof(struct ff_effect_compat));
+		memcpy(&ff_up->old, &ff_up_compat.old,
+			sizeof(struct ff_effect_compat));
+
+	} else {
+		if (copy_from_user(ff_up, buffer,
+				   sizeof(struct uinput_ff_upload)))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+#else
+
+static int uinput_ff_upload_to_user(char __user *buffer,
+				    const struct uinput_ff_upload *ff_up)
+{
+	if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int uinput_ff_upload_from_user(const char __user *buffer,
+				      struct uinput_ff_upload *ff_up)
+{
+	if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload)))
+		return -EFAULT;
+
+	return 0;
+}
+
+#endif
+
+#define uinput_set_bit(_arg, _bit, _max)		\
+({							\
+	int __ret = 0;					\
+	if (udev->state == UIST_CREATED)		\
+		__ret =  -EINVAL;			\
+	else if ((_arg) > (_max))			\
+		__ret = -EINVAL;			\
+	else set_bit((_arg), udev->dev->_bit);		\
+	__ret;						\
+})
+
+static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
+				 unsigned long arg, void __user *p)
+{
+	int			retval;
+	struct uinput_device	*udev = file->private_data;
+	struct uinput_ff_upload ff_up;
+	struct uinput_ff_erase  ff_erase;
+	struct uinput_request   *req;
+	char			*phys;
+
+	retval = mutex_lock_interruptible(&udev->mutex);
+	if (retval)
+		return retval;
+
+	if (!udev->dev) {
+		retval = uinput_allocate_device(udev);
+		if (retval)
+			goto out;
+	}
+
+	switch (cmd) {
+		case UI_DEV_CREATE:
+			retval = uinput_create_device(udev);
+			break;
+
+		case UI_DEV_DESTROY:
+			uinput_destroy_device(udev);
+			break;
+
+		case UI_SET_EVBIT:
+			retval = uinput_set_bit(arg, evbit, EV_MAX);
+			break;
+
+		case UI_SET_KEYBIT:
+			retval = uinput_set_bit(arg, keybit, KEY_MAX);
+			break;
+
+		case UI_SET_RELBIT:
+			retval = uinput_set_bit(arg, relbit, REL_MAX);
+			break;
+
+		case UI_SET_ABSBIT:
+			retval = uinput_set_bit(arg, absbit, ABS_MAX);
+			break;
+
+		case UI_SET_MSCBIT:
+			retval = uinput_set_bit(arg, mscbit, MSC_MAX);
+			break;
+
+		case UI_SET_LEDBIT:
+			retval = uinput_set_bit(arg, ledbit, LED_MAX);
+			break;
+
+		case UI_SET_SNDBIT:
+			retval = uinput_set_bit(arg, sndbit, SND_MAX);
+			break;
+
+		case UI_SET_FFBIT:
+			retval = uinput_set_bit(arg, ffbit, FF_MAX);
+			break;
+
+		case UI_SET_SWBIT:
+			retval = uinput_set_bit(arg, swbit, SW_MAX);
+			break;
+
+		case UI_SET_PROPBIT:
+			retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
+			break;
+
+		case UI_SET_PHYS:
+			if (udev->state == UIST_CREATED) {
+				retval = -EINVAL;
+				goto out;
+			}
+
+			phys = strndup_user(p, 1024);
+			if (IS_ERR(phys)) {
+				retval = PTR_ERR(phys);
+				goto out;
+			}
+
+			kfree(udev->dev->phys);
+			udev->dev->phys = phys;
+			break;
+
+		case UI_BEGIN_FF_UPLOAD:
+			retval = uinput_ff_upload_from_user(p, &ff_up);
+			if (retval)
+				break;
+
+			req = uinput_request_find(udev, ff_up.request_id);
+			if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) {
+				retval = -EINVAL;
+				break;
+			}
+
+			ff_up.retval = 0;
+			ff_up.effect = *req->u.upload.effect;
+			if (req->u.upload.old)
+				ff_up.old = *req->u.upload.old;
+			else
+				memset(&ff_up.old, 0, sizeof(struct ff_effect));
+
+			retval = uinput_ff_upload_to_user(p, &ff_up);
+			break;
+
+		case UI_BEGIN_FF_ERASE:
+			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
+				retval = -EFAULT;
+				break;
+			}
+
+			req = uinput_request_find(udev, ff_erase.request_id);
+			if (!req || req->code != UI_FF_ERASE) {
+				retval = -EINVAL;
+				break;
+			}
+
+			ff_erase.retval = 0;
+			ff_erase.effect_id = req->u.effect_id;
+			if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
+				retval = -EFAULT;
+				break;
+			}
+
+			break;
+
+		case UI_END_FF_UPLOAD:
+			retval = uinput_ff_upload_from_user(p, &ff_up);
+			if (retval)
+				break;
+
+			req = uinput_request_find(udev, ff_up.request_id);
+			if (!req || req->code != UI_FF_UPLOAD ||
+			    !req->u.upload.effect) {
+				retval = -EINVAL;
+				break;
+			}
+
+			req->retval = ff_up.retval;
+			uinput_request_done(udev, req);
+			break;
+
+		case UI_END_FF_ERASE:
+			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
+				retval = -EFAULT;
+				break;
+			}
+
+			req = uinput_request_find(udev, ff_erase.request_id);
+			if (!req || req->code != UI_FF_ERASE) {
+				retval = -EINVAL;
+				break;
+			}
+
+			req->retval = ff_erase.retval;
+			uinput_request_done(udev, req);
+			break;
+
+		default:
+			retval = -EINVAL;
+	}
+
+ out:
+	mutex_unlock(&udev->mutex);
+	return retval;
+}
+
+static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	return uinput_ioctl_handler(file, cmd, arg, (void __user *)arg);
+}
+
+#ifdef CONFIG_COMPAT
+static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg));
+}
+#endif
+
+static const struct file_operations uinput_fops = {
+	.owner		= THIS_MODULE,
+	.open		= uinput_open,
+	.release	= uinput_release,
+	.read		= uinput_read,
+	.write		= uinput_write,
+	.poll		= uinput_poll,
+	.unlocked_ioctl	= uinput_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= uinput_compat_ioctl,
+#endif
+	.llseek		= no_llseek,
+};
+
+static struct miscdevice uinput_misc = {
+	.fops		= &uinput_fops,
+	.minor		= UINPUT_MINOR,
+	.name		= UINPUT_NAME,
+};
+MODULE_ALIAS_MISCDEV(UINPUT_MINOR);
+MODULE_ALIAS("devname:" UINPUT_NAME);
+
+static int __init uinput_init(void)
+{
+	return misc_register(&uinput_misc);
+}
+
+static void __exit uinput_exit(void)
+{
+	misc_deregister(&uinput_misc);
+}
+
+MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
+MODULE_DESCRIPTION("User level driver support for input subsystem");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.3");
+
+module_init(uinput_init);
+module_exit(uinput_exit);
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/wistron_btns.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/wistron_btns.c
new file mode 100644
index 0000000..e2bdfd4
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/wistron_btns.c
@@ -0,0 +1,1389 @@
+/*
+ * Wistron laptop button driver
+ * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
+ * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
+ * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
+ *
+ * You can redistribute and/or modify this program under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/io.h>
+#include <linux/dmi.h>
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/mc146818rtc.h>
+#include <linux/module.h>
+#include <linux/preempt.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+/* How often we poll keys - msecs */
+#define POLL_INTERVAL_DEFAULT	500 /* when idle */
+#define POLL_INTERVAL_BURST	100 /* when a key was recently pressed */
+
+/* BIOS subsystem IDs */
+#define WIFI		0x35
+#define BLUETOOTH	0x34
+#define MAIL_LED	0x31
+
+MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>");
+MODULE_DESCRIPTION("Wistron laptop button driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.3");
+
+static bool force; /* = 0; */
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Load even if computer is not in database");
+
+static char *keymap_name; /* = NULL; */
+module_param_named(keymap, keymap_name, charp, 0);
+MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected [generic, 1557/MS2141]");
+
+static struct platform_device *wistron_device;
+
+ /* BIOS interface implementation */
+
+static void __iomem *bios_entry_point; /* BIOS routine entry point */
+static void __iomem *bios_code_map_base;
+static void __iomem *bios_data_map_base;
+
+static u8 cmos_address;
+
+struct regs {
+	u32 eax, ebx, ecx;
+};
+
+static void call_bios(struct regs *regs)
+{
+	unsigned long flags;
+
+	preempt_disable();
+	local_irq_save(flags);
+	asm volatile ("pushl %%ebp;"
+		      "movl %7, %%ebp;"
+		      "call *%6;"
+		      "popl %%ebp"
+		      : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx)
+		      : "0" (regs->eax), "1" (regs->ebx), "2" (regs->ecx),
+			"m" (bios_entry_point), "m" (bios_data_map_base)
+		      : "edx", "edi", "esi", "memory");
+	local_irq_restore(flags);
+	preempt_enable();
+}
+
+static ssize_t __init locate_wistron_bios(void __iomem *base)
+{
+	static unsigned char __initdata signature[] =
+		{ 0x42, 0x21, 0x55, 0x30 };
+	ssize_t offset;
+
+	for (offset = 0; offset < 0x10000; offset += 0x10) {
+		if (check_signature(base + offset, signature,
+				    sizeof(signature)) != 0)
+			return offset;
+	}
+	return -1;
+}
+
+static int __init map_bios(void)
+{
+	void __iomem *base;
+	ssize_t offset;
+	u32 entry_point;
+
+	base = ioremap(0xF0000, 0x10000); /* Can't fail */
+	offset = locate_wistron_bios(base);
+	if (offset < 0) {
+		printk(KERN_ERR "wistron_btns: BIOS entry point not found\n");
+		iounmap(base);
+		return -ENODEV;
+	}
+
+	entry_point = readl(base + offset + 5);
+	printk(KERN_DEBUG
+		"wistron_btns: BIOS signature found at %p, entry point %08X\n",
+		base + offset, entry_point);
+
+	if (entry_point >= 0xF0000) {
+		bios_code_map_base = base;
+		bios_entry_point = bios_code_map_base + (entry_point & 0xFFFF);
+	} else {
+		iounmap(base);
+		bios_code_map_base = ioremap(entry_point & ~0x3FFF, 0x4000);
+		if (bios_code_map_base == NULL) {
+			printk(KERN_ERR
+				"wistron_btns: Can't map BIOS code at %08X\n",
+				entry_point & ~0x3FFF);
+			goto err;
+		}
+		bios_entry_point = bios_code_map_base + (entry_point & 0x3FFF);
+	}
+	/* The Windows driver maps 0x10000 bytes, we keep only one page... */
+	bios_data_map_base = ioremap(0x400, 0xc00);
+	if (bios_data_map_base == NULL) {
+		printk(KERN_ERR "wistron_btns: Can't map BIOS data\n");
+		goto err_code;
+	}
+	return 0;
+
+err_code:
+	iounmap(bios_code_map_base);
+err:
+	return -ENOMEM;
+}
+
+static inline void unmap_bios(void)
+{
+	iounmap(bios_code_map_base);
+	iounmap(bios_data_map_base);
+}
+
+ /* BIOS calls */
+
+static u16 bios_pop_queue(void)
+{
+	struct regs regs;
+
+	memset(&regs, 0, sizeof (regs));
+	regs.eax = 0x9610;
+	regs.ebx = 0x061C;
+	regs.ecx = 0x0000;
+	call_bios(&regs);
+
+	return regs.eax;
+}
+
+static void __devinit bios_attach(void)
+{
+	struct regs regs;
+
+	memset(&regs, 0, sizeof (regs));
+	regs.eax = 0x9610;
+	regs.ebx = 0x012E;
+	call_bios(&regs);
+}
+
+static void bios_detach(void)
+{
+	struct regs regs;
+
+	memset(&regs, 0, sizeof (regs));
+	regs.eax = 0x9610;
+	regs.ebx = 0x002E;
+	call_bios(&regs);
+}
+
+static u8 __devinit bios_get_cmos_address(void)
+{
+	struct regs regs;
+
+	memset(&regs, 0, sizeof (regs));
+	regs.eax = 0x9610;
+	regs.ebx = 0x051C;
+	call_bios(&regs);
+
+	return regs.ecx;
+}
+
+static u16 __devinit bios_get_default_setting(u8 subsys)
+{
+	struct regs regs;
+
+	memset(&regs, 0, sizeof (regs));
+	regs.eax = 0x9610;
+	regs.ebx = 0x0200 | subsys;
+	call_bios(&regs);
+
+	return regs.eax;
+}
+
+static void bios_set_state(u8 subsys, int enable)
+{
+	struct regs regs;
+
+	memset(&regs, 0, sizeof (regs));
+	regs.eax = 0x9610;
+	regs.ebx = (enable ? 0x0100 : 0x0000) | subsys;
+	call_bios(&regs);
+}
+
+/* Hardware database */
+
+#define KE_WIFI		(KE_LAST + 1)
+#define KE_BLUETOOTH	(KE_LAST + 2)
+
+#define FE_MAIL_LED 0x01
+#define FE_WIFI_LED 0x02
+#define FE_UNTESTED 0x80
+
+static struct key_entry *keymap; /* = NULL; Current key map */
+static bool have_wifi;
+static bool have_bluetooth;
+static int leds_present;	/* bitmask of leds present */
+
+static int __init dmi_matched(const struct dmi_system_id *dmi)
+{
+	const struct key_entry *key;
+
+	keymap = dmi->driver_data;
+	for (key = keymap; key->type != KE_END; key++) {
+		if (key->type == KE_WIFI)
+			have_wifi = true;
+		else if (key->type == KE_BLUETOOTH)
+			have_bluetooth = true;
+	}
+	leds_present = key->code & (FE_MAIL_LED | FE_WIFI_LED);
+
+	return 1;
+}
+
+static struct key_entry keymap_empty[] __initdata = {
+	{ KE_END, 0 }
+};
+
+static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = {
+	{ KE_KEY,  0x01, {KEY_HELP} },
+	{ KE_KEY,  0x11, {KEY_PROG1} },
+	{ KE_KEY,  0x12, {KEY_PROG2} },
+	{ KE_WIFI, 0x30 },
+	{ KE_KEY,  0x31, {KEY_MAIL} },
+	{ KE_KEY,  0x36, {KEY_WWW} },
+	{ KE_END,  0 }
+};
+
+static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = {
+	{ KE_KEY,       0x01, {KEY_HELP} },          /* Fn+F1 */
+	{ KE_KEY,       0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */
+	{ KE_BLUETOOTH, 0x30 },                      /* Fn+F10 */
+	{ KE_KEY,       0x31, {KEY_MAIL} },          /* mail button */
+	{ KE_KEY,       0x36, {KEY_WWW} },           /* www button */
+	{ KE_WIFI,      0x78 },                      /* satellite dish button */
+	{ KE_END,       0 }
+};
+
+static struct key_entry keymap_fujitsu_n3510[] __initdata = {
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x71, {KEY_STOPCD} },
+	{ KE_KEY, 0x72, {KEY_PLAYPAUSE} },
+	{ KE_KEY, 0x74, {KEY_REWIND} },
+	{ KE_KEY, 0x78, {KEY_FORWARD} },
+	{ KE_END, 0 }
+};
+
+static struct key_entry keymap_wistron_ms2111[] __initdata = {
+	{ KE_KEY,  0x11, {KEY_PROG1} },
+	{ KE_KEY,  0x12, {KEY_PROG2} },
+	{ KE_KEY,  0x13, {KEY_PROG3} },
+	{ KE_KEY,  0x31, {KEY_MAIL} },
+	{ KE_KEY,  0x36, {KEY_WWW} },
+	{ KE_END, FE_MAIL_LED }
+};
+
+static struct key_entry keymap_wistron_md40100[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_wistron_ms2141[] __initdata = {
+	{ KE_KEY,  0x11, {KEY_PROG1} },
+	{ KE_KEY,  0x12, {KEY_PROG2} },
+	{ KE_WIFI, 0x30 },
+	{ KE_KEY,  0x22, {KEY_REWIND} },
+	{ KE_KEY,  0x23, {KEY_FORWARD} },
+	{ KE_KEY,  0x24, {KEY_PLAYPAUSE} },
+	{ KE_KEY,  0x25, {KEY_STOPCD} },
+	{ KE_KEY,  0x31, {KEY_MAIL} },
+	{ KE_KEY,  0x36, {KEY_WWW} },
+	{ KE_END,  0 }
+};
+
+static struct key_entry keymap_acer_aspire_1500[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_WIFI, 0x30 },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x49, {KEY_CONFIG} },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_aspire_1600[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x49, {KEY_CONFIG} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+/* 3020 has been tested */
+static struct key_entry keymap_acer_aspire_5020[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x6a, {KEY_CONFIG} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_2410[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x6d, {KEY_POWER} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x6a, {KEY_CONFIG} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_110[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
+	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
+	{ KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
+	{ KE_WIFI, 0x30 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_300[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
+	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_380[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_WIFI, 0x30 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+/* unusual map */
+static struct key_entry keymap_acer_travelmate_220[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_MAIL} },
+	{ KE_KEY, 0x12, {KEY_WWW} },
+	{ KE_KEY, 0x13, {KEY_PROG2} },
+	{ KE_KEY, 0x31, {KEY_PROG1} },
+	{ KE_END, FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_230[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_END, FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_240[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_WIFI, 0x30 },
+	{ KE_END, FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_350[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_MAIL} },
+	{ KE_KEY, 0x14, {KEY_PROG3} },
+	{ KE_KEY, 0x15, {KEY_WWW} },
+	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_360[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_MAIL} },
+	{ KE_KEY, 0x14, {KEY_PROG3} },
+	{ KE_KEY, 0x15, {KEY_WWW} },
+	{ KE_KEY, 0x40, {KEY_WLAN} },
+	{ KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */
+};
+
+/* Wifi subsystem only activates the led. Therefore we need to pass
+ * wifi event as a normal key, then userspace can really change the wifi state.
+ * TODO we need to export led state to userspace (wifi and mail) */
+static struct key_entry keymap_acer_travelmate_610[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_KEY, 0x14, {KEY_MAIL} },
+	{ KE_KEY, 0x15, {KEY_WWW} },
+	{ KE_KEY, 0x40, {KEY_WLAN} },
+	{ KE_END, FE_MAIL_LED | FE_WIFI_LED }
+};
+
+static struct key_entry keymap_acer_travelmate_630[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
+	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_WIFI, 0x30 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_aopen_1559as[] __initdata = {
+	{ KE_KEY,  0x01, {KEY_HELP} },
+	{ KE_KEY,  0x06, {KEY_PROG3} },
+	{ KE_KEY,  0x11, {KEY_PROG1} },
+	{ KE_KEY,  0x12, {KEY_PROG2} },
+	{ KE_WIFI, 0x30 },
+	{ KE_KEY,  0x31, {KEY_MAIL} },
+	{ KE_KEY,  0x36, {KEY_WWW} },
+	{ KE_END,  0 },
+};
+
+static struct key_entry keymap_fs_amilo_d88x0[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_wistron_md2900[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_WIFI, 0x30 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_wistron_md96500[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
+	{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
+	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+	{ KE_KEY, 0x22, {KEY_REWIND} },
+	{ KE_KEY, 0x23, {KEY_FORWARD} },
+	{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
+	{ KE_KEY, 0x25, {KEY_STOPCD} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_UNTESTED }
+};
+
+static struct key_entry keymap_wistron_generic[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
+	{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_KEY, 0x14, {KEY_MAIL} },
+	{ KE_KEY, 0x15, {KEY_WWW} },
+	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
+	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+	{ KE_KEY, 0x22, {KEY_REWIND} },
+	{ KE_KEY, 0x23, {KEY_FORWARD} },
+	{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
+	{ KE_KEY, 0x25, {KEY_STOPCD} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+	{ KE_KEY, 0x40, {KEY_WLAN} },
+	{ KE_KEY, 0x49, {KEY_CONFIG} },
+	{ KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
+	{ KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
+	{ KE_KEY, 0x6a, {KEY_CONFIG} },
+	{ KE_KEY, 0x6d, {KEY_POWER} },
+	{ KE_KEY, 0x71, {KEY_STOPCD} },
+	{ KE_KEY, 0x72, {KEY_PLAYPAUSE} },
+	{ KE_KEY, 0x74, {KEY_REWIND} },
+	{ KE_KEY, 0x78, {KEY_FORWARD} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, 0 }
+};
+
+static struct key_entry keymap_aopen_1557[] __initdata = {
+	{ KE_KEY,  0x01, {KEY_HELP} },
+	{ KE_KEY,  0x11, {KEY_PROG1} },
+	{ KE_KEY,  0x12, {KEY_PROG2} },
+	{ KE_WIFI, 0x30 },
+	{ KE_KEY,  0x22, {KEY_REWIND} },
+	{ KE_KEY,  0x23, {KEY_FORWARD} },
+	{ KE_KEY,  0x24, {KEY_PLAYPAUSE} },
+	{ KE_KEY,  0x25, {KEY_STOPCD} },
+	{ KE_KEY,  0x31, {KEY_MAIL} },
+	{ KE_KEY,  0x36, {KEY_WWW} },
+	{ KE_END,  0 }
+};
+
+static struct key_entry keymap_prestigio[] __initdata = {
+	{ KE_KEY,  0x11, {KEY_PROG1} },
+	{ KE_KEY,  0x12, {KEY_PROG2} },
+	{ KE_WIFI, 0x30 },
+	{ KE_KEY,  0x22, {KEY_REWIND} },
+	{ KE_KEY,  0x23, {KEY_FORWARD} },
+	{ KE_KEY,  0x24, {KEY_PLAYPAUSE} },
+	{ KE_KEY,  0x25, {KEY_STOPCD} },
+	{ KE_KEY,  0x31, {KEY_MAIL} },
+	{ KE_KEY,  0x36, {KEY_WWW} },
+	{ KE_END,  0 }
+};
+
+
+/*
+ * If your machine is not here (which is currently rather likely), please send
+ * a list of buttons and their key codes (reported when loading this module
+ * with force=1) and the output of dmidecode to $MODULE_AUTHOR.
+ */
+static const struct dmi_system_id __initconst dmi_ids[] = {
+	{
+		/* Fujitsu-Siemens Amilo Pro V2000 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"),
+		},
+		.driver_data = keymap_fs_amilo_pro_v2000
+	},
+	{
+		/* Fujitsu-Siemens Amilo Pro Edition V3505 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"),
+		},
+		.driver_data = keymap_fs_amilo_pro_v3505
+	},
+	{
+		/* Fujitsu-Siemens Amilo M7400 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M        "),
+		},
+		.driver_data = keymap_fs_amilo_pro_v2000
+	},
+	{
+		/* Maxdata Pro 7000 DX */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"),
+		},
+		.driver_data = keymap_fs_amilo_pro_v2000
+	},
+	{
+		/* Fujitsu N3510 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "N3510"),
+		},
+		.driver_data = keymap_fujitsu_n3510
+	},
+	{
+		/* Acer Aspire 1500 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"),
+		},
+		.driver_data = keymap_acer_aspire_1500
+	},
+	{
+		/* Acer Aspire 1600 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"),
+		},
+		.driver_data = keymap_acer_aspire_1600
+	},
+	{
+		/* Acer Aspire 3020 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
+		},
+		.driver_data = keymap_acer_aspire_5020
+	},
+	{
+		/* Acer Aspire 5020 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
+		},
+		.driver_data = keymap_acer_aspire_5020
+	},
+	{
+		/* Acer TravelMate 2100 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"),
+		},
+		.driver_data = keymap_acer_aspire_5020
+	},
+	{
+		/* Acer TravelMate 2410 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"),
+		},
+		.driver_data = keymap_acer_travelmate_2410
+	},
+	{
+		/* Acer TravelMate C300 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"),
+		},
+		.driver_data = keymap_acer_travelmate_300
+	},
+	{
+		/* Acer TravelMate C100 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"),
+		},
+		.driver_data = keymap_acer_travelmate_300
+	},
+	{
+		/* Acer TravelMate C110 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"),
+		},
+		.driver_data = keymap_acer_travelmate_110
+	},
+	{
+		/* Acer TravelMate 380 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"),
+		},
+		.driver_data = keymap_acer_travelmate_380
+	},
+	{
+		/* Acer TravelMate 370 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"),
+		},
+		.driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */
+	},
+	{
+		/* Acer TravelMate 220 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"),
+		},
+		.driver_data = keymap_acer_travelmate_220
+	},
+	{
+		/* Acer TravelMate 260 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"),
+		},
+		.driver_data = keymap_acer_travelmate_220
+	},
+	{
+		/* Acer TravelMate 230 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"),
+			/* acerhk looks for "TravelMate F4..." ?! */
+		},
+		.driver_data = keymap_acer_travelmate_230
+	},
+	{
+		/* Acer TravelMate 280 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"),
+		},
+		.driver_data = keymap_acer_travelmate_230
+	},
+	{
+		/* Acer TravelMate 240 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"),
+		},
+		.driver_data = keymap_acer_travelmate_240
+	},
+	{
+		/* Acer TravelMate 250 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"),
+		},
+		.driver_data = keymap_acer_travelmate_240
+	},
+	{
+		/* Acer TravelMate 2424NWXCi */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
+		},
+		.driver_data = keymap_acer_travelmate_240
+	},
+	{
+		/* Acer TravelMate 350 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"),
+		},
+		.driver_data = keymap_acer_travelmate_350
+	},
+	{
+		/* Acer TravelMate 360 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+		},
+		.driver_data = keymap_acer_travelmate_360
+	},
+	{
+		/* Acer TravelMate 610 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"),
+		},
+		.driver_data = keymap_acer_travelmate_610
+	},
+	{
+		/* Acer TravelMate 620 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"),
+		},
+		.driver_data = keymap_acer_travelmate_630
+	},
+	{
+		/* Acer TravelMate 630 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"),
+		},
+		.driver_data = keymap_acer_travelmate_630
+	},
+	{
+		/* AOpen 1559AS */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "E2U"),
+			DMI_MATCH(DMI_BOARD_NAME, "E2U"),
+		},
+		.driver_data = keymap_aopen_1559as
+	},
+	{
+		/* Medion MD 9783 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"),
+		},
+		.driver_data = keymap_wistron_ms2111
+	},
+	{
+		/* Medion MD 40100 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"),
+		},
+		.driver_data = keymap_wistron_md40100
+	},
+	{
+		/* Medion MD 2900 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"),
+		},
+		.driver_data = keymap_wistron_md2900
+	},
+	{
+		/* Medion MD 42200 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Medion"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"),
+		},
+		.driver_data = keymap_fs_amilo_pro_v2000
+	},
+	{
+		/* Medion MD 96500 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"),
+		},
+		.driver_data = keymap_wistron_md96500
+	},
+	{
+		/* Medion MD 95400 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"),
+		},
+		.driver_data = keymap_wistron_md96500
+	},
+	{
+		/* Fujitsu Siemens Amilo D7820 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */
+			DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"),
+		},
+		.driver_data = keymap_fs_amilo_d88x0
+	},
+	{
+		/* Fujitsu Siemens Amilo D88x0 */
+		.callback = dmi_matched,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"),
+		},
+		.driver_data = keymap_fs_amilo_d88x0
+	},
+	{ NULL, }
+};
+
+/* Copy the good keymap, as the original ones are free'd */
+static int __init copy_keymap(void)
+{
+	const struct key_entry *key;
+	struct key_entry *new_keymap;
+	unsigned int length = 1;
+
+	for (key = keymap; key->type != KE_END; key++)
+		length++;
+
+	new_keymap = kmemdup(keymap, length * sizeof(struct key_entry),
+			     GFP_KERNEL);
+	if (!new_keymap)
+		return -ENOMEM;
+
+	keymap = new_keymap;
+
+	return 0;
+}
+
+static int __init select_keymap(void)
+{
+	dmi_check_system(dmi_ids);
+	if (keymap_name != NULL) {
+		if (strcmp (keymap_name, "1557/MS2141") == 0)
+			keymap = keymap_wistron_ms2141;
+		else if (strcmp (keymap_name, "aopen1557") == 0)
+			keymap = keymap_aopen_1557;
+		else if (strcmp (keymap_name, "prestigio") == 0)
+			keymap = keymap_prestigio;
+		else if (strcmp (keymap_name, "generic") == 0)
+			keymap = keymap_wistron_generic;
+		else {
+			printk(KERN_ERR "wistron_btns: Keymap unknown\n");
+			return -EINVAL;
+		}
+	}
+	if (keymap == NULL) {
+		if (!force) {
+			printk(KERN_ERR "wistron_btns: System unknown\n");
+			return -ENODEV;
+		}
+		keymap = keymap_empty;
+	}
+
+	return copy_keymap();
+}
+
+ /* Input layer interface */
+
+static struct input_polled_dev *wistron_idev;
+static unsigned long jiffies_last_press;
+static bool wifi_enabled;
+static bool bluetooth_enabled;
+
+ /* led management */
+static void wistron_mail_led_set(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	bios_set_state(MAIL_LED, (value != LED_OFF) ? 1 : 0);
+}
+
+/* same as setting up wifi card, but for laptops on which the led is managed */
+static void wistron_wifi_led_set(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	bios_set_state(WIFI, (value != LED_OFF) ? 1 : 0);
+}
+
+static struct led_classdev wistron_mail_led = {
+	.name			= "wistron:green:mail",
+	.brightness_set		= wistron_mail_led_set,
+};
+
+static struct led_classdev wistron_wifi_led = {
+	.name			= "wistron:red:wifi",
+	.brightness_set		= wistron_wifi_led_set,
+};
+
+static void __devinit wistron_led_init(struct device *parent)
+{
+	if (leds_present & FE_WIFI_LED) {
+		u16 wifi = bios_get_default_setting(WIFI);
+		if (wifi & 1) {
+			wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF;
+			if (led_classdev_register(parent, &wistron_wifi_led))
+				leds_present &= ~FE_WIFI_LED;
+			else
+				bios_set_state(WIFI, wistron_wifi_led.brightness);
+
+		} else
+			leds_present &= ~FE_WIFI_LED;
+	}
+
+	if (leds_present & FE_MAIL_LED) {
+		/* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */
+		wistron_mail_led.brightness = LED_OFF;
+		if (led_classdev_register(parent, &wistron_mail_led))
+			leds_present &= ~FE_MAIL_LED;
+		else
+			bios_set_state(MAIL_LED, wistron_mail_led.brightness);
+	}
+}
+
+static void __devexit wistron_led_remove(void)
+{
+	if (leds_present & FE_MAIL_LED)
+		led_classdev_unregister(&wistron_mail_led);
+
+	if (leds_present & FE_WIFI_LED)
+		led_classdev_unregister(&wistron_wifi_led);
+}
+
+static inline void wistron_led_suspend(void)
+{
+	if (leds_present & FE_MAIL_LED)
+		led_classdev_suspend(&wistron_mail_led);
+
+	if (leds_present & FE_WIFI_LED)
+		led_classdev_suspend(&wistron_wifi_led);
+}
+
+static inline void wistron_led_resume(void)
+{
+	if (leds_present & FE_MAIL_LED)
+		led_classdev_resume(&wistron_mail_led);
+
+	if (leds_present & FE_WIFI_LED)
+		led_classdev_resume(&wistron_wifi_led);
+}
+
+static void handle_key(u8 code)
+{
+	const struct key_entry *key =
+		sparse_keymap_entry_from_scancode(wistron_idev->input, code);
+
+	if (key) {
+		switch (key->type) {
+		case KE_WIFI:
+			if (have_wifi) {
+				wifi_enabled = !wifi_enabled;
+				bios_set_state(WIFI, wifi_enabled);
+			}
+			break;
+
+		case KE_BLUETOOTH:
+			if (have_bluetooth) {
+				bluetooth_enabled = !bluetooth_enabled;
+				bios_set_state(BLUETOOTH, bluetooth_enabled);
+			}
+			break;
+
+		default:
+			sparse_keymap_report_entry(wistron_idev->input,
+						   key, 1, true);
+			break;
+		}
+		jiffies_last_press = jiffies;
+	} else
+		printk(KERN_NOTICE
+			"wistron_btns: Unknown key code %02X\n", code);
+}
+
+static void poll_bios(bool discard)
+{
+	u8 qlen;
+	u16 val;
+
+	for (;;) {
+		qlen = CMOS_READ(cmos_address);
+		if (qlen == 0)
+			break;
+		val = bios_pop_queue();
+		if (val != 0 && !discard)
+			handle_key((u8)val);
+	}
+}
+
+static void wistron_flush(struct input_polled_dev *dev)
+{
+	/* Flush stale event queue */
+	poll_bios(true);
+}
+
+static void wistron_poll(struct input_polled_dev *dev)
+{
+	poll_bios(false);
+
+	/* Increase poll frequency if user is currently pressing keys (< 2s ago) */
+	if (time_before(jiffies, jiffies_last_press + 2 * HZ))
+		dev->poll_interval = POLL_INTERVAL_BURST;
+	else
+		dev->poll_interval = POLL_INTERVAL_DEFAULT;
+}
+
+static int __devinit wistron_setup_keymap(struct input_dev *dev,
+					  struct key_entry *entry)
+{
+	switch (entry->type) {
+
+	/* if wifi or bluetooth are not available, create normal keys */
+	case KE_WIFI:
+		if (!have_wifi) {
+			entry->type = KE_KEY;
+			entry->keycode = KEY_WLAN;
+		}
+		break;
+
+	case KE_BLUETOOTH:
+		if (!have_bluetooth) {
+			entry->type = KE_KEY;
+			entry->keycode = KEY_BLUETOOTH;
+		}
+		break;
+
+	case KE_END:
+		if (entry->code & FE_UNTESTED)
+			printk(KERN_WARNING "Untested laptop multimedia keys, "
+				"please report success or failure to "
+				"eric.piel@tremplin-utc.net\n");
+		break;
+	}
+
+	return 0;
+}
+
+static int __devinit setup_input_dev(void)
+{
+	struct input_dev *input_dev;
+	int error;
+
+	wistron_idev = input_allocate_polled_device();
+	if (!wistron_idev)
+		return -ENOMEM;
+
+	wistron_idev->open = wistron_flush;
+	wistron_idev->poll = wistron_poll;
+	wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT;
+
+	input_dev = wistron_idev->input;
+	input_dev->name = "Wistron laptop buttons";
+	input_dev->phys = "wistron/input0";
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->dev.parent = &wistron_device->dev;
+
+	error = sparse_keymap_setup(input_dev, keymap, wistron_setup_keymap);
+	if (error)
+		goto err_free_dev;
+
+	error = input_register_polled_device(wistron_idev);
+	if (error)
+		goto err_free_keymap;
+
+	return 0;
+
+ err_free_keymap:
+	sparse_keymap_free(input_dev);
+ err_free_dev:
+	input_free_polled_device(wistron_idev);
+	return error;
+}
+
+/* Driver core */
+
+static int __devinit wistron_probe(struct platform_device *dev)
+{
+	int err;
+
+	bios_attach();
+	cmos_address = bios_get_cmos_address();
+
+	if (have_wifi) {
+		u16 wifi = bios_get_default_setting(WIFI);
+		if (wifi & 1)
+			wifi_enabled = wifi & 2;
+		else
+			have_wifi = 0;
+
+		if (have_wifi)
+			bios_set_state(WIFI, wifi_enabled);
+	}
+
+	if (have_bluetooth) {
+		u16 bt = bios_get_default_setting(BLUETOOTH);
+		if (bt & 1)
+			bluetooth_enabled = bt & 2;
+		else
+			have_bluetooth = false;
+
+		if (have_bluetooth)
+			bios_set_state(BLUETOOTH, bluetooth_enabled);
+	}
+
+	wistron_led_init(&dev->dev);
+
+	err = setup_input_dev();
+	if (err) {
+		bios_detach();
+		return err;
+	}
+
+	return 0;
+}
+
+static int __devexit wistron_remove(struct platform_device *dev)
+{
+	wistron_led_remove();
+	input_unregister_polled_device(wistron_idev);
+	sparse_keymap_free(wistron_idev->input);
+	input_free_polled_device(wistron_idev);
+	bios_detach();
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int wistron_suspend(struct device *dev)
+{
+	if (have_wifi)
+		bios_set_state(WIFI, 0);
+
+	if (have_bluetooth)
+		bios_set_state(BLUETOOTH, 0);
+
+	wistron_led_suspend();
+
+	return 0;
+}
+
+static int wistron_resume(struct device *dev)
+{
+	if (have_wifi)
+		bios_set_state(WIFI, wifi_enabled);
+
+	if (have_bluetooth)
+		bios_set_state(BLUETOOTH, bluetooth_enabled);
+
+	wistron_led_resume();
+
+	poll_bios(true);
+
+	return 0;
+}
+
+static const struct dev_pm_ops wistron_pm_ops = {
+	.suspend	= wistron_suspend,
+	.resume		= wistron_resume,
+	.poweroff	= wistron_suspend,
+	.restore	= wistron_resume,
+};
+#endif
+
+static struct platform_driver wistron_driver = {
+	.driver		= {
+		.name	= "wistron-bios",
+		.owner	= THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &wistron_pm_ops,
+#endif
+	},
+	.probe		= wistron_probe,
+	.remove		= __devexit_p(wistron_remove),
+};
+
+static int __init wb_module_init(void)
+{
+	int err;
+
+	err = select_keymap();
+	if (err)
+		return err;
+
+	err = map_bios();
+	if (err)
+		goto err_free_keymap;
+
+	err = platform_driver_register(&wistron_driver);
+	if (err)
+		goto err_unmap_bios;
+
+	wistron_device = platform_device_alloc("wistron-bios", -1);
+	if (!wistron_device) {
+		err = -ENOMEM;
+		goto err_unregister_driver;
+	}
+
+	err = platform_device_add(wistron_device);
+	if (err)
+		goto err_free_device;
+
+	return 0;
+
+ err_free_device:
+	platform_device_put(wistron_device);
+ err_unregister_driver:
+	platform_driver_unregister(&wistron_driver);
+ err_unmap_bios:
+	unmap_bios();
+ err_free_keymap:
+	kfree(keymap);
+
+	return err;
+}
+
+static void __exit wb_module_exit(void)
+{
+	platform_device_unregister(wistron_device);
+	platform_driver_unregister(&wistron_driver);
+	unmap_bios();
+	kfree(keymap);
+}
+
+module_init(wb_module_init);
+module_exit(wb_module_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/wm831x-on.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/wm831x-on.c
new file mode 100644
index 0000000..47f18d6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/wm831x-on.c
@@ -0,0 +1,154 @@
+/**
+ * wm831x-on.c - WM831X ON pin driver
+ *
+ * Copyright (C) 2009 Wolfson Microelectronics plc
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/mfd/wm831x/core.h>
+
+struct wm831x_on {
+	struct input_dev *dev;
+	struct delayed_work work;
+	struct wm831x *wm831x;
+};
+
+/*
+ * The chip gives us an interrupt when the ON pin is asserted but we
+ * then need to poll to see when the pin is deasserted.
+ */
+static void wm831x_poll_on(struct work_struct *work)
+{
+	struct wm831x_on *wm831x_on = container_of(work, struct wm831x_on,
+						   work.work);
+	struct wm831x *wm831x = wm831x_on->wm831x;
+	int poll, ret;
+
+	ret = wm831x_reg_read(wm831x, WM831X_ON_PIN_CONTROL);
+	if (ret >= 0) {
+		poll = !(ret & WM831X_ON_PIN_STS);
+
+		input_report_key(wm831x_on->dev, KEY_POWER, poll);
+		input_sync(wm831x_on->dev);
+	} else {
+		dev_err(wm831x->dev, "Failed to read ON status: %d\n", ret);
+		poll = 1;
+	}
+
+	if (poll)
+		schedule_delayed_work(&wm831x_on->work, 100);
+}
+
+static irqreturn_t wm831x_on_irq(int irq, void *data)
+{
+	struct wm831x_on *wm831x_on = data;
+
+	schedule_delayed_work(&wm831x_on->work, 0);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit wm831x_on_probe(struct platform_device *pdev)
+{
+	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+	struct wm831x_on *wm831x_on;
+	int irq = platform_get_irq(pdev, 0);
+	int ret;
+
+	wm831x_on = kzalloc(sizeof(struct wm831x_on), GFP_KERNEL);
+	if (!wm831x_on) {
+		dev_err(&pdev->dev, "Can't allocate data\n");
+		return -ENOMEM;
+	}
+
+	wm831x_on->wm831x = wm831x;
+	INIT_DELAYED_WORK(&wm831x_on->work, wm831x_poll_on);
+
+	wm831x_on->dev = input_allocate_device();
+	if (!wm831x_on->dev) {
+		dev_err(&pdev->dev, "Can't allocate input dev\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	wm831x_on->dev->evbit[0] = BIT_MASK(EV_KEY);
+	wm831x_on->dev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+	wm831x_on->dev->name = "wm831x_on";
+	wm831x_on->dev->phys = "wm831x_on/input0";
+	wm831x_on->dev->dev.parent = &pdev->dev;
+
+	ret = request_threaded_irq(irq, NULL, wm831x_on_irq,
+				   IRQF_TRIGGER_RISING, "wm831x_on",
+				   wm831x_on);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Unable to request IRQ: %d\n", ret);
+		goto err_input_dev;
+	}
+	ret = input_register_device(wm831x_on->dev);
+	if (ret) {
+		dev_dbg(&pdev->dev, "Can't register input device: %d\n", ret);
+		goto err_irq;
+	}
+
+	platform_set_drvdata(pdev, wm831x_on);
+
+	return 0;
+
+err_irq:
+	free_irq(irq, wm831x_on);
+err_input_dev:
+	input_free_device(wm831x_on->dev);
+err:
+	kfree(wm831x_on);
+	return ret;
+}
+
+static int __devexit wm831x_on_remove(struct platform_device *pdev)
+{
+	struct wm831x_on *wm831x_on = platform_get_drvdata(pdev);
+	int irq = platform_get_irq(pdev, 0);
+
+	free_irq(irq, wm831x_on);
+	cancel_delayed_work_sync(&wm831x_on->work);
+	input_unregister_device(wm831x_on->dev);
+	kfree(wm831x_on);
+
+	return 0;
+}
+
+static struct platform_driver wm831x_on_driver = {
+	.probe		= wm831x_on_probe,
+	.remove		= __devexit_p(wm831x_on_remove),
+	.driver		= {
+		.name	= "wm831x-on",
+		.owner	= THIS_MODULE,
+	},
+};
+module_platform_driver(wm831x_on_driver);
+
+MODULE_ALIAS("platform:wm831x-on");
+MODULE_DESCRIPTION("WM831x ON pin");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/xen-kbdfront.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/xen-kbdfront.c
new file mode 100644
index 0000000..02ca868
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/xen-kbdfront.c
@@ -0,0 +1,393 @@
+/*
+ * Xen para-virtual input device
+ *
+ * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
+ * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ *
+ *  Based on linux/drivers/input/mouse/sermouse.c
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include <asm/xen/hypervisor.h>
+
+#include <xen/xen.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/fbif.h>
+#include <xen/interface/io/kbdif.h>
+#include <xen/xenbus.h>
+
+struct xenkbd_info {
+	struct input_dev *kbd;
+	struct input_dev *ptr;
+	struct xenkbd_page *page;
+	int gref;
+	int irq;
+	struct xenbus_device *xbdev;
+	char phys[32];
+};
+
+static int xenkbd_remove(struct xenbus_device *);
+static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
+static void xenkbd_disconnect_backend(struct xenkbd_info *);
+
+/*
+ * Note: if you need to send out events, see xenfb_do_update() for how
+ * to do that.
+ */
+
+static irqreturn_t input_handler(int rq, void *dev_id)
+{
+	struct xenkbd_info *info = dev_id;
+	struct xenkbd_page *page = info->page;
+	__u32 cons, prod;
+
+	prod = page->in_prod;
+	if (prod == page->in_cons)
+		return IRQ_HANDLED;
+	rmb();			/* ensure we see ring contents up to prod */
+	for (cons = page->in_cons; cons != prod; cons++) {
+		union xenkbd_in_event *event;
+		struct input_dev *dev;
+		event = &XENKBD_IN_RING_REF(page, cons);
+
+		dev = info->ptr;
+		switch (event->type) {
+		case XENKBD_TYPE_MOTION:
+			input_report_rel(dev, REL_X, event->motion.rel_x);
+			input_report_rel(dev, REL_Y, event->motion.rel_y);
+			if (event->motion.rel_z)
+				input_report_rel(dev, REL_WHEEL,
+						 -event->motion.rel_z);
+			break;
+		case XENKBD_TYPE_KEY:
+			dev = NULL;
+			if (test_bit(event->key.keycode, info->kbd->keybit))
+				dev = info->kbd;
+			if (test_bit(event->key.keycode, info->ptr->keybit))
+				dev = info->ptr;
+			if (dev)
+				input_report_key(dev, event->key.keycode,
+						 event->key.pressed);
+			else
+				pr_warning("unhandled keycode 0x%x\n",
+					   event->key.keycode);
+			break;
+		case XENKBD_TYPE_POS:
+			input_report_abs(dev, ABS_X, event->pos.abs_x);
+			input_report_abs(dev, ABS_Y, event->pos.abs_y);
+			if (event->pos.rel_z)
+				input_report_rel(dev, REL_WHEEL,
+						 -event->pos.rel_z);
+			break;
+		}
+		if (dev)
+			input_sync(dev);
+	}
+	mb();			/* ensure we got ring contents */
+	page->in_cons = cons;
+	notify_remote_via_irq(info->irq);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit xenkbd_probe(struct xenbus_device *dev,
+				  const struct xenbus_device_id *id)
+{
+	int ret, i, abs;
+	struct xenkbd_info *info;
+	struct input_dev *kbd, *ptr;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+		return -ENOMEM;
+	}
+	dev_set_drvdata(&dev->dev, info);
+	info->xbdev = dev;
+	info->irq = -1;
+	info->gref = -1;
+	snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
+
+	info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+	if (!info->page)
+		goto error_nomem;
+
+	if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0)
+		abs = 0;
+	if (abs)
+		xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1");
+
+	/* keyboard */
+	kbd = input_allocate_device();
+	if (!kbd)
+		goto error_nomem;
+	kbd->name = "Xen Virtual Keyboard";
+	kbd->phys = info->phys;
+	kbd->id.bustype = BUS_PCI;
+	kbd->id.vendor = 0x5853;
+	kbd->id.product = 0xffff;
+
+	__set_bit(EV_KEY, kbd->evbit);
+	for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
+		__set_bit(i, kbd->keybit);
+	for (i = KEY_OK; i < KEY_MAX; i++)
+		__set_bit(i, kbd->keybit);
+
+	ret = input_register_device(kbd);
+	if (ret) {
+		input_free_device(kbd);
+		xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
+		goto error;
+	}
+	info->kbd = kbd;
+
+	/* pointing device */
+	ptr = input_allocate_device();
+	if (!ptr)
+		goto error_nomem;
+	ptr->name = "Xen Virtual Pointer";
+	ptr->phys = info->phys;
+	ptr->id.bustype = BUS_PCI;
+	ptr->id.vendor = 0x5853;
+	ptr->id.product = 0xfffe;
+
+	if (abs) {
+		__set_bit(EV_ABS, ptr->evbit);
+		input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0);
+		input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
+	} else {
+		input_set_capability(ptr, EV_REL, REL_X);
+		input_set_capability(ptr, EV_REL, REL_Y);
+	}
+	input_set_capability(ptr, EV_REL, REL_WHEEL);
+
+	__set_bit(EV_KEY, ptr->evbit);
+	for (i = BTN_LEFT; i <= BTN_TASK; i++)
+		__set_bit(i, ptr->keybit);
+
+	ret = input_register_device(ptr);
+	if (ret) {
+		input_free_device(ptr);
+		xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
+		goto error;
+	}
+	info->ptr = ptr;
+
+	ret = xenkbd_connect_backend(dev, info);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+ error_nomem:
+	ret = -ENOMEM;
+	xenbus_dev_fatal(dev, ret, "allocating device memory");
+ error:
+	xenkbd_remove(dev);
+	return ret;
+}
+
+static int xenkbd_resume(struct xenbus_device *dev)
+{
+	struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
+
+	xenkbd_disconnect_backend(info);
+	memset(info->page, 0, PAGE_SIZE);
+	return xenkbd_connect_backend(dev, info);
+}
+
+static int xenkbd_remove(struct xenbus_device *dev)
+{
+	struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
+
+	xenkbd_disconnect_backend(info);
+	if (info->kbd)
+		input_unregister_device(info->kbd);
+	if (info->ptr)
+		input_unregister_device(info->ptr);
+	free_page((unsigned long)info->page);
+	kfree(info);
+	return 0;
+}
+
+static int xenkbd_connect_backend(struct xenbus_device *dev,
+				  struct xenkbd_info *info)
+{
+	int ret, evtchn;
+	struct xenbus_transaction xbt;
+
+	ret = gnttab_grant_foreign_access(dev->otherend_id,
+	                                  virt_to_mfn(info->page), 0);
+	if (ret < 0)
+		return ret;
+	info->gref = ret;
+
+	ret = xenbus_alloc_evtchn(dev, &evtchn);
+	if (ret)
+		goto error_grant;
+	ret = bind_evtchn_to_irqhandler(evtchn, input_handler,
+					0, dev->devicetype, info);
+	if (ret < 0) {
+		xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
+		goto error_evtchan;
+	}
+	info->irq = ret;
+
+ again:
+	ret = xenbus_transaction_start(&xbt);
+	if (ret) {
+		xenbus_dev_fatal(dev, ret, "starting transaction");
+		goto error_irqh;
+	}
+	ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
+			    virt_to_mfn(info->page));
+	if (ret)
+		goto error_xenbus;
+	ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref);
+	if (ret)
+		goto error_xenbus;
+	ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+			    evtchn);
+	if (ret)
+		goto error_xenbus;
+	ret = xenbus_transaction_end(xbt, 0);
+	if (ret) {
+		if (ret == -EAGAIN)
+			goto again;
+		xenbus_dev_fatal(dev, ret, "completing transaction");
+		goto error_irqh;
+	}
+
+	xenbus_switch_state(dev, XenbusStateInitialised);
+	return 0;
+
+ error_xenbus:
+	xenbus_transaction_end(xbt, 1);
+	xenbus_dev_fatal(dev, ret, "writing xenstore");
+ error_irqh:
+	unbind_from_irqhandler(info->irq, info);
+	info->irq = -1;
+ error_evtchan:
+	xenbus_free_evtchn(dev, evtchn);
+ error_grant:
+	gnttab_end_foreign_access_ref(info->gref, 0);
+	info->gref = -1;
+	return ret;
+}
+
+static void xenkbd_disconnect_backend(struct xenkbd_info *info)
+{
+	if (info->irq >= 0)
+		unbind_from_irqhandler(info->irq, info);
+	info->irq = -1;
+	if (info->gref >= 0)
+		gnttab_end_foreign_access_ref(info->gref, 0);
+	info->gref = -1;
+}
+
+static void xenkbd_backend_changed(struct xenbus_device *dev,
+				   enum xenbus_state backend_state)
+{
+	struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
+	int ret, val;
+
+	switch (backend_state) {
+	case XenbusStateInitialising:
+	case XenbusStateInitialised:
+	case XenbusStateReconfiguring:
+	case XenbusStateReconfigured:
+	case XenbusStateUnknown:
+	case XenbusStateClosed:
+		break;
+
+	case XenbusStateInitWait:
+InitWait:
+		ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+				   "feature-abs-pointer", "%d", &val);
+		if (ret < 0)
+			val = 0;
+		if (val) {
+			ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
+					    "request-abs-pointer", "1");
+			if (ret)
+				pr_warning("xenkbd: can't request abs-pointer");
+		}
+
+		xenbus_switch_state(dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateConnected:
+		/*
+		 * Work around xenbus race condition: If backend goes
+		 * through InitWait to Connected fast enough, we can
+		 * get Connected twice here.
+		 */
+		if (dev->state != XenbusStateConnected)
+			goto InitWait; /* no InitWait seen yet, fudge it */
+
+		/* Set input abs params to match backend screen res */
+		if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+				 "width", "%d", &val) > 0)
+			input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0);
+
+		if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+				 "height", "%d", &val) > 0)
+			input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0);
+
+		break;
+
+	case XenbusStateClosing:
+		xenbus_frontend_closed(dev);
+		break;
+	}
+}
+
+static const struct xenbus_device_id xenkbd_ids[] = {
+	{ "vkbd" },
+	{ "" }
+};
+
+static DEFINE_XENBUS_DRIVER(xenkbd, ,
+	.probe = xenkbd_probe,
+	.remove = xenkbd_remove,
+	.resume = xenkbd_resume,
+	.otherend_changed = xenkbd_backend_changed,
+);
+
+static int __init xenkbd_init(void)
+{
+	if (!xen_domain())
+		return -ENODEV;
+
+	/* Nothing to do if running in dom0. */
+	if (xen_initial_domain())
+		return -ENODEV;
+
+	return xenbus_register_frontend(&xenkbd_driver);
+}
+
+static void __exit xenkbd_cleanup(void)
+{
+	xenbus_unregister_driver(&xenkbd_driver);
+}
+
+module_init(xenkbd_init);
+module_exit(xenkbd_cleanup);
+
+MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("xen:vkbd");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/yealink.c b/ap/os/linux/linux-3.4.x/drivers/input/misc/yealink.c
new file mode 100644
index 0000000..f4776e7
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/yealink.c
@@ -0,0 +1,997 @@
+/*
+ * drivers/usb/input/yealink.c
+ *
+ * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * Description:
+ *   Driver for the USB-P1K voip usb phone.
+ *   This device is produced by Yealink Network Technology Co Ltd
+ *   but may be branded under several names:
+ *	- Yealink usb-p1k
+ *	- Tiptel 115
+ *	- ...
+ *
+ * This driver is based on:
+ *   - the usbb2k-api	http://savannah.nongnu.org/projects/usbb2k-api/
+ *   - information from	http://memeteau.free.fr/usbb2k
+ *   - the xpad-driver	drivers/input/joystick/xpad.c
+ *
+ * Thanks to:
+ *   - Olivier Vandorpe, for providing the usbb2k-api.
+ *   - Martin Diehl, for spotting my memory allocation bug.
+ *
+ * History:
+ *   20050527 henk	First version, functional keyboard. Keyboard events
+ *			will pop-up on the ../input/eventX bus.
+ *   20050531 henk	Added led, LCD, dialtone and sysfs interface.
+ *   20050610 henk	Cleanups, make it ready for public consumption.
+ *   20050630 henk	Cleanups, fixes in response to comments.
+ *   20050701 henk	sysfs write serialisation, fix potential unload races
+ *   20050801 henk	Added ringtone, restructure USB
+ *   20050816 henk	Merge 2.6.13-rc6
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+#include <linux/usb/input.h>
+#include <linux/map_to_7segment.h>
+
+#include "yealink.h"
+
+#define DRIVER_VERSION "yld-20051230"
+#define DRIVER_AUTHOR "Henk Vergonet"
+#define DRIVER_DESC "Yealink phone driver"
+
+#define YEALINK_POLLING_FREQUENCY	10	/* in [Hz] */
+
+struct yld_status {
+	u8	lcd[24];
+	u8	led;
+	u8	dialtone;
+	u8	ringtone;
+	u8	keynum;
+} __attribute__ ((packed));
+
+/*
+ * Register the LCD segment and icon map
+ */
+#define _LOC(k,l)	{ .a = (k), .m = (l) }
+#define _SEG(t, a, am, b, bm, c, cm, d, dm, e, em, f, fm, g, gm)	\
+	{ .type	= (t),							\
+	  .u = { .s = {	_LOC(a, am), _LOC(b, bm), _LOC(c, cm),		\
+		        _LOC(d, dm), _LOC(e, em), _LOC(g, gm),		\
+			_LOC(f, fm) } } }
+#define _PIC(t, h, hm, n)						\
+	{ .type	= (t),							\
+ 	  .u = { .p = { .name = (n), .a = (h), .m = (hm) } } }
+
+static const struct lcd_segment_map {
+	char	type;
+	union {
+		struct pictogram_map {
+			u8	a,m;
+			char	name[10];
+		}	p;
+		struct segment_map {
+			u8	a,m;
+		} s[7];
+	} u;
+} lcdMap[] = {
+#include "yealink.h"
+};
+
+struct yealink_dev {
+	struct input_dev *idev;		/* input device */
+	struct usb_device *udev;	/* usb device */
+
+	/* irq input channel */
+	struct yld_ctl_packet	*irq_data;
+	dma_addr_t		irq_dma;
+	struct urb		*urb_irq;
+
+	/* control output channel */
+	struct yld_ctl_packet	*ctl_data;
+	dma_addr_t		ctl_dma;
+	struct usb_ctrlrequest	*ctl_req;
+	struct urb		*urb_ctl;
+
+	char phys[64];			/* physical device path */
+
+	u8 lcdMap[ARRAY_SIZE(lcdMap)];	/* state of LCD, LED ... */
+	int key_code;			/* last reported key	 */
+
+	unsigned int shutdown:1;
+
+	int	stat_ix;
+	union {
+		struct yld_status s;
+		u8		  b[sizeof(struct yld_status)];
+	} master, copy;
+};
+
+
+/*******************************************************************************
+ * Yealink lcd interface
+ ******************************************************************************/
+
+/*
+ * Register a default 7 segment character set
+ */
+static SEG7_DEFAULT_MAP(map_seg7);
+
+ /* Display a char,
+  * char '\9' and '\n' are placeholders and do not overwrite the original text.
+  * A space will always hide an icon.
+  */
+static int setChar(struct yealink_dev *yld, int el, int chr)
+{
+	int i, a, m, val;
+
+	if (el >= ARRAY_SIZE(lcdMap))
+		return -EINVAL;
+
+	if (chr == '\t' || chr == '\n')
+	    return 0;
+
+	yld->lcdMap[el] = chr;
+
+	if (lcdMap[el].type == '.') {
+		a = lcdMap[el].u.p.a;
+		m = lcdMap[el].u.p.m;
+		if (chr != ' ')
+			yld->master.b[a] |= m;
+		else
+			yld->master.b[a] &= ~m;
+		return 0;
+	}
+
+	val = map_to_seg7(&map_seg7, chr);
+	for (i = 0; i < ARRAY_SIZE(lcdMap[0].u.s); i++) {
+		m = lcdMap[el].u.s[i].m;
+
+		if (m == 0)
+			continue;
+
+		a = lcdMap[el].u.s[i].a;
+		if (val & 1)
+			yld->master.b[a] |= m;
+		else
+			yld->master.b[a] &= ~m;
+		val = val >> 1;
+	}
+	return 0;
+};
+
+/*******************************************************************************
+ * Yealink key interface
+ ******************************************************************************/
+
+/* Map device buttons to internal key events.
+ *
+ * USB-P1K button layout:
+ *
+ *             up
+ *       IN           OUT
+ *            down
+ *
+ *     pickup   C    hangup
+ *       1      2      3
+ *       4      5      6
+ *       7      8      9
+ *       *      0      #
+ *
+ * The "up" and "down" keys, are symbolised by arrows on the button.
+ * The "pickup" and "hangup" keys are symbolised by a green and red phone
+ * on the button.
+ */
+static int map_p1k_to_key(int scancode)
+{
+	switch(scancode) {		/* phone key:	*/
+	case 0x23: return KEY_LEFT;	/*   IN		*/
+	case 0x33: return KEY_UP;	/*   up		*/
+	case 0x04: return KEY_RIGHT;	/*   OUT	*/
+	case 0x24: return KEY_DOWN;	/*   down	*/
+	case 0x03: return KEY_ENTER;	/*   pickup	*/
+	case 0x14: return KEY_BACKSPACE; /*  C		*/
+	case 0x13: return KEY_ESC;	/*   hangup	*/
+	case 0x00: return KEY_1;	/*   1		*/
+	case 0x01: return KEY_2;	/*   2 		*/
+	case 0x02: return KEY_3;	/*   3		*/
+	case 0x10: return KEY_4;	/*   4		*/
+	case 0x11: return KEY_5;	/*   5		*/
+	case 0x12: return KEY_6;	/*   6		*/
+	case 0x20: return KEY_7;	/*   7		*/
+	case 0x21: return KEY_8;	/*   8		*/
+	case 0x22: return KEY_9;	/*   9		*/
+	case 0x30: return KEY_KPASTERISK; /* *		*/
+	case 0x31: return KEY_0;	/*   0		*/
+	case 0x32: return KEY_LEFTSHIFT |
+			  KEY_3 << 8;	/*   #		*/
+	}
+	return -EINVAL;
+}
+
+/* Completes a request by converting the data into events for the
+ * input subsystem.
+ *
+ * The key parameter can be cascaded: key2 << 8 | key1
+ */
+static void report_key(struct yealink_dev *yld, int key)
+{
+	struct input_dev *idev = yld->idev;
+
+	if (yld->key_code >= 0) {
+		/* old key up */
+		input_report_key(idev, yld->key_code & 0xff, 0);
+		if (yld->key_code >> 8)
+			input_report_key(idev, yld->key_code >> 8, 0);
+	}
+
+	yld->key_code = key;
+	if (key >= 0) {
+		/* new valid key */
+		input_report_key(idev, key & 0xff, 1);
+		if (key >> 8)
+			input_report_key(idev, key >> 8, 1);
+	}
+	input_sync(idev);
+}
+
+/*******************************************************************************
+ * Yealink usb communication interface
+ ******************************************************************************/
+
+static int yealink_cmd(struct yealink_dev *yld, struct yld_ctl_packet *p)
+{
+	u8	*buf = (u8 *)p;
+	int	i;
+	u8	sum = 0;
+
+	for(i=0; i<USB_PKT_LEN-1; i++)
+		sum -= buf[i];
+	p->sum = sum;
+	return usb_control_msg(yld->udev,
+			usb_sndctrlpipe(yld->udev, 0),
+			USB_REQ_SET_CONFIGURATION,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+			0x200, 3,
+			p, sizeof(*p),
+			USB_CTRL_SET_TIMEOUT);
+}
+
+static u8 default_ringtone[] = {
+	0xEF,			/* volume [0-255] */
+	0xFB, 0x1E, 0x00, 0x0C,	/* 1250 [hz], 12/100 [s] */
+	0xFC, 0x18, 0x00, 0x0C,	/* 1000 [hz], 12/100 [s] */
+	0xFB, 0x1E, 0x00, 0x0C,
+	0xFC, 0x18, 0x00, 0x0C,
+	0xFB, 0x1E, 0x00, 0x0C,
+	0xFC, 0x18, 0x00, 0x0C,
+	0xFB, 0x1E, 0x00, 0x0C,
+	0xFC, 0x18, 0x00, 0x0C,
+	0xFF, 0xFF, 0x01, 0x90,	/* silent, 400/100 [s] */
+	0x00, 0x00		/* end of sequence */
+};
+
+static int yealink_set_ringtone(struct yealink_dev *yld, u8 *buf, size_t size)
+{
+	struct yld_ctl_packet *p = yld->ctl_data;
+	int	ix, len;
+
+	if (size <= 0)
+		return -EINVAL;
+
+	/* Set the ringtone volume */
+	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+	yld->ctl_data->cmd	= CMD_RING_VOLUME;
+	yld->ctl_data->size	= 1;
+	yld->ctl_data->data[0]	= buf[0];
+	yealink_cmd(yld, p);
+
+	buf++;
+	size--;
+
+	p->cmd = CMD_RING_NOTE;
+	ix = 0;
+	while (size != ix) {
+		len = size - ix;
+		if (len > sizeof(p->data))
+			len = sizeof(p->data);
+		p->size	  = len;
+		p->offset = cpu_to_be16(ix);
+		memcpy(p->data, &buf[ix], len);
+		yealink_cmd(yld, p);
+		ix += len;
+	}
+	return 0;
+}
+
+/* keep stat_master & stat_copy in sync.
+ */
+static int yealink_do_idle_tasks(struct yealink_dev *yld)
+{
+	u8 val;
+	int i, ix, len;
+
+	ix = yld->stat_ix;
+
+	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+	yld->ctl_data->cmd  = CMD_KEYPRESS;
+	yld->ctl_data->size = 1;
+	yld->ctl_data->sum  = 0xff - CMD_KEYPRESS;
+
+	/* If state update pointer wraps do a KEYPRESS first. */
+	if (ix >= sizeof(yld->master)) {
+		yld->stat_ix = 0;
+		return 0;
+	}
+
+	/* find update candidates: copy != master */
+	do {
+		val = yld->master.b[ix];
+		if (val != yld->copy.b[ix])
+			goto send_update;
+	} while (++ix < sizeof(yld->master));
+
+	/* nothing todo, wait a bit and poll for a KEYPRESS */
+	yld->stat_ix = 0;
+	/* TODO how can we wait abit. ??
+	 * msleep_interruptible(1000 / YEALINK_POLLING_FREQUENCY);
+	 */
+	return 0;
+
+send_update:
+
+	/* Setup an appropriate update request */
+	yld->copy.b[ix] = val;
+	yld->ctl_data->data[0] = val;
+
+	switch(ix) {
+	case offsetof(struct yld_status, led):
+		yld->ctl_data->cmd	= CMD_LED;
+		yld->ctl_data->sum	= -1 - CMD_LED - val;
+		break;
+	case offsetof(struct yld_status, dialtone):
+		yld->ctl_data->cmd	= CMD_DIALTONE;
+		yld->ctl_data->sum	= -1 - CMD_DIALTONE - val;
+		break;
+	case offsetof(struct yld_status, ringtone):
+		yld->ctl_data->cmd	= CMD_RINGTONE;
+		yld->ctl_data->sum	= -1 - CMD_RINGTONE - val;
+		break;
+	case offsetof(struct yld_status, keynum):
+		val--;
+		val &= 0x1f;
+		yld->ctl_data->cmd	= CMD_SCANCODE;
+		yld->ctl_data->offset	= cpu_to_be16(val);
+		yld->ctl_data->data[0]	= 0;
+		yld->ctl_data->sum	= -1 - CMD_SCANCODE - val;
+		break;
+	default:
+		len = sizeof(yld->master.s.lcd) - ix;
+		if (len > sizeof(yld->ctl_data->data))
+			len = sizeof(yld->ctl_data->data);
+
+		/* Combine up to <len> consecutive LCD bytes in a singe request
+		 */
+		yld->ctl_data->cmd	= CMD_LCD;
+		yld->ctl_data->offset	= cpu_to_be16(ix);
+		yld->ctl_data->size	= len;
+		yld->ctl_data->sum	= -CMD_LCD - ix - val - len;
+		for(i=1; i<len; i++) {
+			ix++;
+			val = yld->master.b[ix];
+			yld->copy.b[ix]		= val;
+			yld->ctl_data->data[i]	= val;
+			yld->ctl_data->sum     -= val;
+		}
+	}
+	yld->stat_ix = ix + 1;
+	return 1;
+}
+
+/* Decide on how to handle responses
+ *
+ * The state transition diagram is somethhing like:
+ *
+ *          syncState<--+
+ *               |      |
+ *               |    idle
+ *              \|/     |
+ * init --ok--> waitForKey --ok--> getKey
+ *  ^               ^                |
+ *  |               +-------ok-------+
+ * error,start
+ *
+ */
+static void urb_irq_callback(struct urb *urb)
+{
+	struct yealink_dev *yld = urb->context;
+	int ret, status = urb->status;
+
+	if (status)
+		err("%s - urb status %d", __func__, status);
+
+	switch (yld->irq_data->cmd) {
+	case CMD_KEYPRESS:
+
+		yld->master.s.keynum = yld->irq_data->data[0];
+		break;
+
+	case CMD_SCANCODE:
+		dbg("get scancode %x", yld->irq_data->data[0]);
+
+		report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
+		break;
+
+	default:
+		err("unexpected response %x", yld->irq_data->cmd);
+	}
+
+	yealink_do_idle_tasks(yld);
+
+	if (!yld->shutdown) {
+		ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
+		if (ret && ret != -EPERM)
+			err("%s - usb_submit_urb failed %d", __func__, ret);
+	}
+}
+
+static void urb_ctl_callback(struct urb *urb)
+{
+	struct yealink_dev *yld = urb->context;
+	int ret = 0, status = urb->status;
+
+	if (status)
+		err("%s - urb status %d", __func__, status);
+
+	switch (yld->ctl_data->cmd) {
+	case CMD_KEYPRESS:
+	case CMD_SCANCODE:
+		/* ask for a response */
+		if (!yld->shutdown)
+			ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
+		break;
+	default:
+		/* send new command */
+		yealink_do_idle_tasks(yld);
+		if (!yld->shutdown)
+			ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
+		break;
+	}
+
+	if (ret && ret != -EPERM)
+		err("%s - usb_submit_urb failed %d", __func__, ret);
+}
+
+/*******************************************************************************
+ * input event interface
+ ******************************************************************************/
+
+/* TODO should we issue a ringtone on a SND_BELL event?
+static int input_ev(struct input_dev *dev, unsigned int type,
+		unsigned int code, int value)
+{
+
+	if (type != EV_SND)
+		return -EINVAL;
+
+	switch (code) {
+	case SND_BELL:
+	case SND_TONE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+*/
+
+static int input_open(struct input_dev *dev)
+{
+	struct yealink_dev *yld = input_get_drvdata(dev);
+	int i, ret;
+
+	dbg("%s", __func__);
+
+	/* force updates to device */
+	for (i = 0; i<sizeof(yld->master); i++)
+		yld->copy.b[i] = ~yld->master.b[i];
+	yld->key_code = -1;	/* no keys pressed */
+
+        yealink_set_ringtone(yld, default_ringtone, sizeof(default_ringtone));
+
+	/* issue INIT */
+	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+	yld->ctl_data->cmd	= CMD_INIT;
+	yld->ctl_data->size	= 10;
+	yld->ctl_data->sum	= 0x100-CMD_INIT-10;
+	if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) {
+		dbg("%s - usb_submit_urb failed with result %d",
+		     __func__, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static void input_close(struct input_dev *dev)
+{
+	struct yealink_dev *yld = input_get_drvdata(dev);
+
+	yld->shutdown = 1;
+	/*
+	 * Make sure the flag is seen by other CPUs before we start
+	 * killing URBs so new URBs won't be submitted
+	 */
+	smp_wmb();
+
+	usb_kill_urb(yld->urb_ctl);
+	usb_kill_urb(yld->urb_irq);
+
+	yld->shutdown = 0;
+	smp_wmb();
+}
+
+/*******************************************************************************
+ * sysfs interface
+ ******************************************************************************/
+
+static DECLARE_RWSEM(sysfs_rwsema);
+
+/* Interface to the 7-segments translation table aka. char set.
+ */
+static ssize_t show_map(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	memcpy(buf, &map_seg7, sizeof(map_seg7));
+	return sizeof(map_seg7);
+}
+
+static ssize_t store_map(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t cnt)
+{
+	if (cnt != sizeof(map_seg7))
+		return -EINVAL;
+	memcpy(&map_seg7, buf, sizeof(map_seg7));
+	return sizeof(map_seg7);
+}
+
+/* Interface to the LCD.
+ */
+
+/* Reading /sys/../lineX will return the format string with its settings:
+ *
+ * Example:
+ * cat ./line3
+ * 888888888888
+ * Linux Rocks!
+ */
+static ssize_t show_line(struct device *dev, char *buf, int a, int b)
+{
+	struct yealink_dev *yld;
+	int i;
+
+	down_read(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_read(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	for (i = a; i < b; i++)
+		*buf++ = lcdMap[i].type;
+	*buf++ = '\n';
+	for (i = a; i < b; i++)
+		*buf++ = yld->lcdMap[i];
+	*buf++ = '\n';
+	*buf = 0;
+
+	up_read(&sysfs_rwsema);
+	return 3 + ((b - a) << 1);
+}
+
+static ssize_t show_line1(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	return show_line(dev, buf, LCD_LINE1_OFFSET, LCD_LINE2_OFFSET);
+}
+
+static ssize_t show_line2(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	return show_line(dev, buf, LCD_LINE2_OFFSET, LCD_LINE3_OFFSET);
+}
+
+static ssize_t show_line3(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	return show_line(dev, buf, LCD_LINE3_OFFSET, LCD_LINE4_OFFSET);
+}
+
+/* Writing to /sys/../lineX will set the coresponding LCD line.
+ * - Excess characters are ignored.
+ * - If less characters are written than allowed, the remaining digits are
+ *   unchanged.
+ * - The '\n' or '\t' char is a placeholder, it does not overwrite the
+ *   original content.
+ */
+static ssize_t store_line(struct device *dev, const char *buf, size_t count,
+		int el, size_t len)
+{
+	struct yealink_dev *yld;
+	int i;
+
+	down_write(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_write(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	if (len > count)
+		len = count;
+	for (i = 0; i < len; i++)
+		setChar(yld, el++, buf[i]);
+
+	up_write(&sysfs_rwsema);
+	return count;
+}
+
+static ssize_t store_line1(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return store_line(dev, buf, count, LCD_LINE1_OFFSET, LCD_LINE1_SIZE);
+}
+
+static ssize_t store_line2(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return store_line(dev, buf, count, LCD_LINE2_OFFSET, LCD_LINE2_SIZE);
+}
+
+static ssize_t store_line3(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return store_line(dev, buf, count, LCD_LINE3_OFFSET, LCD_LINE3_SIZE);
+}
+
+/* Interface to visible and audible "icons", these include:
+ * pictures on the LCD, the LED, and the dialtone signal.
+ */
+
+/* Get a list of "switchable elements" with their current state. */
+static ssize_t get_icons(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct yealink_dev *yld;
+	int i, ret = 1;
+
+	down_read(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_read(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
+		if (lcdMap[i].type != '.')
+			continue;
+		ret += sprintf(&buf[ret], "%s %s\n",
+				yld->lcdMap[i] == ' ' ? "  " : "on",
+				lcdMap[i].u.p.name);
+	}
+	up_read(&sysfs_rwsema);
+	return ret;
+}
+
+/* Change the visibility of a particular element. */
+static ssize_t set_icon(struct device *dev, const char *buf, size_t count,
+			int chr)
+{
+	struct yealink_dev *yld;
+	int i;
+
+	down_write(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_write(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
+		if (lcdMap[i].type != '.')
+			continue;
+		if (strncmp(buf, lcdMap[i].u.p.name, count) == 0) {
+			setChar(yld, i, chr);
+			break;
+		}
+	}
+
+	up_write(&sysfs_rwsema);
+	return count;
+}
+
+static ssize_t show_icon(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	return set_icon(dev, buf, count, buf[0]);
+}
+
+static ssize_t hide_icon(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	return set_icon(dev, buf, count, ' ');
+}
+
+/* Upload a ringtone to the device.
+ */
+
+/* Stores raw ringtone data in the phone */
+static ssize_t store_ringtone(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct yealink_dev *yld;
+
+	down_write(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_write(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	/* TODO locking with async usb control interface??? */
+	yealink_set_ringtone(yld, (char *)buf, count);
+	up_write(&sysfs_rwsema);
+	return count;
+}
+
+#define _M444	S_IRUGO
+#define _M664	S_IRUGO|S_IWUSR|S_IWGRP
+#define _M220	S_IWUSR|S_IWGRP
+
+static DEVICE_ATTR(map_seg7	, _M664, show_map	, store_map	);
+static DEVICE_ATTR(line1	, _M664, show_line1	, store_line1	);
+static DEVICE_ATTR(line2	, _M664, show_line2	, store_line2	);
+static DEVICE_ATTR(line3	, _M664, show_line3	, store_line3	);
+static DEVICE_ATTR(get_icons	, _M444, get_icons	, NULL		);
+static DEVICE_ATTR(show_icon	, _M220, NULL		, show_icon	);
+static DEVICE_ATTR(hide_icon	, _M220, NULL		, hide_icon	);
+static DEVICE_ATTR(ringtone	, _M220, NULL		, store_ringtone);
+
+static struct attribute *yld_attributes[] = {
+	&dev_attr_line1.attr,
+	&dev_attr_line2.attr,
+	&dev_attr_line3.attr,
+	&dev_attr_get_icons.attr,
+	&dev_attr_show_icon.attr,
+	&dev_attr_hide_icon.attr,
+	&dev_attr_map_seg7.attr,
+	&dev_attr_ringtone.attr,
+	NULL
+};
+
+static struct attribute_group yld_attr_group = {
+	.attrs = yld_attributes
+};
+
+/*******************************************************************************
+ * Linux interface and usb initialisation
+ ******************************************************************************/
+
+struct driver_info {
+	char *name;
+};
+
+static const struct driver_info info_P1K = {
+	.name	= "Yealink usb-p1k",
+};
+
+static const struct usb_device_id usb_table [] = {
+	{
+		.match_flags		= USB_DEVICE_ID_MATCH_DEVICE |
+						USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor		= 0x6993,
+		.idProduct		= 0xb001,
+		.bInterfaceClass	= USB_CLASS_HID,
+		.bInterfaceSubClass	= 0,
+		.bInterfaceProtocol	= 0,
+		.driver_info		= (kernel_ulong_t)&info_P1K
+	},
+	{ }
+};
+
+static int usb_cleanup(struct yealink_dev *yld, int err)
+{
+	if (yld == NULL)
+		return err;
+
+        if (yld->idev) {
+		if (err)
+			input_free_device(yld->idev);
+		else
+			input_unregister_device(yld->idev);
+	}
+
+	usb_free_urb(yld->urb_irq);
+	usb_free_urb(yld->urb_ctl);
+
+	kfree(yld->ctl_req);
+	usb_free_coherent(yld->udev, USB_PKT_LEN, yld->ctl_data, yld->ctl_dma);
+	usb_free_coherent(yld->udev, USB_PKT_LEN, yld->irq_data, yld->irq_dma);
+
+	kfree(yld);
+	return err;
+}
+
+static void usb_disconnect(struct usb_interface *intf)
+{
+	struct yealink_dev *yld;
+
+	down_write(&sysfs_rwsema);
+	yld = usb_get_intfdata(intf);
+	sysfs_remove_group(&intf->dev.kobj, &yld_attr_group);
+	usb_set_intfdata(intf, NULL);
+	up_write(&sysfs_rwsema);
+
+	usb_cleanup(yld, 0);
+}
+
+static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev (intf);
+	struct driver_info *nfo = (struct driver_info *)id->driver_info;
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct yealink_dev *yld;
+	struct input_dev *input_dev;
+	int ret, pipe, i;
+
+	interface = intf->cur_altsetting;
+	endpoint = &interface->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	yld = kzalloc(sizeof(struct yealink_dev), GFP_KERNEL);
+	if (!yld)
+		return -ENOMEM;
+
+	yld->udev = udev;
+
+	yld->idev = input_dev = input_allocate_device();
+	if (!input_dev)
+		return usb_cleanup(yld, -ENOMEM);
+
+	/* allocate usb buffers */
+	yld->irq_data = usb_alloc_coherent(udev, USB_PKT_LEN,
+					   GFP_ATOMIC, &yld->irq_dma);
+	if (yld->irq_data == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	yld->ctl_data = usb_alloc_coherent(udev, USB_PKT_LEN,
+					   GFP_ATOMIC, &yld->ctl_dma);
+	if (!yld->ctl_data)
+		return usb_cleanup(yld, -ENOMEM);
+
+	yld->ctl_req = kmalloc(sizeof(*(yld->ctl_req)), GFP_KERNEL);
+	if (yld->ctl_req == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	/* allocate urb structures */
+	yld->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
+        if (yld->urb_irq == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	yld->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
+        if (yld->urb_ctl == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	/* get a handle to the interrupt data pipe */
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	if (ret != USB_PKT_LEN)
+		err("invalid payload size %d, expected %zd", ret, USB_PKT_LEN);
+
+	/* initialise irq urb */
+	usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data,
+			USB_PKT_LEN,
+			urb_irq_callback,
+			yld, endpoint->bInterval);
+	yld->urb_irq->transfer_dma = yld->irq_dma;
+	yld->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	yld->urb_irq->dev = udev;
+
+	/* initialise ctl urb */
+	yld->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+				      USB_DIR_OUT;
+	yld->ctl_req->bRequest	= USB_REQ_SET_CONFIGURATION;
+	yld->ctl_req->wValue	= cpu_to_le16(0x200);
+	yld->ctl_req->wIndex	= cpu_to_le16(interface->desc.bInterfaceNumber);
+	yld->ctl_req->wLength	= cpu_to_le16(USB_PKT_LEN);
+
+	usb_fill_control_urb(yld->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
+			(void *)yld->ctl_req, yld->ctl_data, USB_PKT_LEN,
+			urb_ctl_callback, yld);
+	yld->urb_ctl->transfer_dma	= yld->ctl_dma;
+	yld->urb_ctl->transfer_flags	|= URB_NO_TRANSFER_DMA_MAP;
+	yld->urb_ctl->dev = udev;
+
+	/* find out the physical bus location */
+	usb_make_path(udev, yld->phys, sizeof(yld->phys));
+	strlcat(yld->phys,  "/input0", sizeof(yld->phys));
+
+	/* register settings for the input device */
+	input_dev->name = nfo->name;
+	input_dev->phys = yld->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, yld);
+
+	input_dev->open = input_open;
+	input_dev->close = input_close;
+	/* input_dev->event = input_ev;	TODO */
+
+	/* register available key events */
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
+	for (i = 0; i < 256; i++) {
+		int k = map_p1k_to_key(i);
+		if (k >= 0) {
+			set_bit(k & 0xff, input_dev->keybit);
+			if (k >> 8)
+				set_bit(k >> 8, input_dev->keybit);
+		}
+	}
+
+	ret = input_register_device(yld->idev);
+	if (ret)
+		return usb_cleanup(yld, ret);
+
+	usb_set_intfdata(intf, yld);
+
+	/* clear visible elements */
+	for (i = 0; i < ARRAY_SIZE(lcdMap); i++)
+		setChar(yld, i, ' ');
+
+	/* display driver version on LCD line 3 */
+	store_line3(&intf->dev, NULL,
+			DRIVER_VERSION, sizeof(DRIVER_VERSION));
+
+	/* Register sysfs hooks (don't care about failure) */
+	ret = sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
+	return 0;
+}
+
+static struct usb_driver yealink_driver = {
+	.name		= "yealink",
+	.probe		= usb_probe,
+	.disconnect	= usb_disconnect,
+	.id_table	= usb_table,
+};
+
+module_usb_driver(yealink_driver);
+
+MODULE_DEVICE_TABLE (usb, usb_table);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/misc/yealink.h b/ap/os/linux/linux-3.4.x/drivers/input/misc/yealink.h
new file mode 100644
index 0000000..1e0f523
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/misc/yealink.h
@@ -0,0 +1,220 @@
+/*
+ * drivers/usb/input/yealink.h
+ *
+ * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef INPUT_YEALINK_H
+#define INPUT_YEALINK_H
+
+/* Using the control channel on interface 3 various aspects of the phone
+ * can be controlled like LCD, LED, dialtone and the ringtone.
+ */
+
+struct yld_ctl_packet {
+	u8	cmd;		/* command code, see below */
+	u8	size;		/* 1-11, size of used data bytes. */
+	u16	offset;		/* internal packet offset */
+	u8	data[11];
+	s8	sum;		/* negative sum of 15 preceding bytes */
+} __attribute__ ((packed));
+
+#define USB_PKT_LEN	sizeof(struct yld_ctl_packet)
+
+/* The following yld_ctl_packet's are available: */
+
+/* Init registers
+ *
+ * cmd		0x8e
+ * size		10
+ * offset	0
+ * data		0,0,0,0....
+ */
+#define CMD_INIT		0x8e
+
+/* Request key scan
+ *
+ * cmd		0x80
+ * size		1
+ * offset	0
+ * data[0]	on return returns the key number, if it changes there's a new
+ * 		key pressed.
+ */
+#define CMD_KEYPRESS		0x80
+
+/* Request scancode
+ *
+ * cmd		0x81
+ * size		1
+ * offset	key number [0-1f]
+ * data[0]	on return returns the scancode
+ */
+#define CMD_SCANCODE		0x81
+
+/* Set LCD
+ *
+ * cmd		0x04
+ * size		1-11
+ * offset	0-23
+ * data		segment bits
+ */
+#define CMD_LCD			0x04
+
+/* Set led
+ *
+ * cmd		0x05
+ * size		1
+ * offset	0
+ * data[0]	0 OFF / 1 ON
+ */
+#define CMD_LED			0x05
+
+/* Set ringtone volume
+ *
+ * cmd		0x11
+ * size		1
+ * offset	0
+ * data[0]	0-0xff  volume
+ */
+#define CMD_RING_VOLUME		0x11
+
+/* Set ringtone notes
+ *
+ * cmd		0x02
+ * size		1-11
+ * offset	0->
+ * data		binary representation LE16(-freq), LE16(duration) ....
+ */
+#define CMD_RING_NOTE		0x02
+
+/* Sound ringtone via the speaker on the back
+ *
+ * cmd		0x03
+ * size		1
+ * offset	0
+ * data[0]	0 OFF / 0x24 ON
+ */
+#define CMD_RINGTONE		0x03
+
+/* Sound dial tone via the ear speaker
+ *
+ * cmd		0x09
+ * size		1
+ * offset	0
+ * data[0]	0 OFF / 1 ON
+ */
+#define CMD_DIALTONE		0x09
+
+#endif /* INPUT_YEALINK_H */
+
+
+#if defined(_SEG) && defined(_PIC)
+/* This table maps the LCD segments onto individual bit positions in the
+ * yld_status struct.
+ */
+
+/* LCD, each segment must be driven separately.
+ *
+ * Layout:
+ *
+ *   |[]   [][]   [][]   [][]   in   |[][]
+ *   |[] M [][] D [][] : [][]   out  |[][]
+ *                             store
+ *
+ *    NEW REP         SU MO TU WE TH FR SA
+ *
+ *    [] [] [] [] [] [] [] [] [] [] [] []
+ *    [] [] [] [] [] [] [] [] [] [] [] []
+ */
+
+/* Line 1
+ *	Format		: 18.e8.M8.88...188
+ *	Icon names	: M D : IN OUT STORE
+ */
+#define LCD_LINE1_OFFSET	0
+#define LCD_LINE1_SIZE		17
+
+/* Note: first g then f =>			       !      !      */
+/* _SEG(    type    a      b      c      d      e      g      f   )  */
+	_SEG('1',  0,0 , 22,2 , 22,2 ,  0,0 ,  0,0 ,  0,0 ,  0,0	),
+	_SEG('8', 20,1 , 20,2 , 20,4 , 20,8 , 21,4 , 21,2 , 21,1	),
+	_PIC('.', 22,1 , "M"						),
+	_SEG('e', 18,1 , 18,2 , 18,4 , 18,1 , 19,2 , 18,1 , 19,1	),
+	_SEG('8', 16,1 , 16,2 , 16,4 , 16,8 , 17,4 , 17,2 , 17,1	),
+	_PIC('.', 15,8 , "D"						),
+	_SEG('M', 14,1 , 14,2 , 14,4 , 14,1 , 15,4 , 15,2 , 15,1	),
+	_SEG('8', 12,1 , 12,2 , 12,4 , 12,8 , 13,4 , 13,2 , 13,1	),
+	_PIC('.', 11,8 , ":"						),
+	_SEG('8', 10,1 , 10,2 , 10,4 , 10,8 , 11,4 , 11,2 , 11,1	),
+	_SEG('8',  8,1 ,  8,2 ,  8,4 ,  8,8 ,  9,4 ,  9,2 ,  9,1	),
+	_PIC('.',  7,1 , "IN"						),
+	_PIC('.',  7,2 , "OUT"						),
+	_PIC('.',  7,4 , "STORE"					),
+	_SEG('1',  0,0 ,  5,1 ,  5,1 ,  0,0 ,  0,0 ,  0,0 ,  0,0	),
+	_SEG('8',  4,1 ,  4,2 ,  4,4 ,  4,8 ,  5,8 ,  5,4 ,  5,2	),
+	_SEG('8',  2,1 ,  2,2 ,  2,4 ,  2,8 ,  3,4 ,  3,2 ,  3,1	),
+
+/* Line 2
+ *	Format		: .........
+ *	Pict. name	: NEW REP SU MO TU WE TH FR SA
+ */
+#define LCD_LINE2_OFFSET	LCD_LINE1_OFFSET + LCD_LINE1_SIZE
+#define LCD_LINE2_SIZE		9
+
+	_PIC('.', 23,2 , "NEW"	),
+	_PIC('.', 23,4 , "REP"	),
+	_PIC('.',  1,8 , "SU"	),
+	_PIC('.',  1,4 , "MO"	),
+	_PIC('.',  1,2 , "TU"	),
+	_PIC('.',  1,1 , "WE"	),
+	_PIC('.',  0,1 , "TH"	),
+	_PIC('.',  0,2 , "FR"	),
+	_PIC('.',  0,4 , "SA"	),
+
+/* Line 3
+ *	Format		: 888888888888
+ */
+#define LCD_LINE3_OFFSET	LCD_LINE2_OFFSET + LCD_LINE2_SIZE
+#define LCD_LINE3_SIZE		12
+
+	_SEG('8', 22,16, 22,32, 22,64, 22,128, 23,128, 23,64, 23,32  ),
+	_SEG('8', 20,16, 20,32, 20,64, 20,128, 21,128, 21,64, 21,32  ),
+	_SEG('8', 18,16, 18,32, 18,64, 18,128, 19,128, 19,64, 19,32  ),
+	_SEG('8', 16,16, 16,32, 16,64, 16,128, 17,128, 17,64, 17,32  ),
+	_SEG('8', 14,16, 14,32, 14,64, 14,128, 15,128, 15,64, 15,32  ),
+	_SEG('8', 12,16, 12,32, 12,64, 12,128, 13,128, 13,64, 13,32  ),
+	_SEG('8', 10,16, 10,32, 10,64, 10,128, 11,128, 11,64, 11,32  ),
+	_SEG('8',  8,16,  8,32,  8,64,  8,128,  9,128,  9,64,  9,32  ),
+	_SEG('8',  6,16,  6,32,  6,64,  6,128,  7,128,  7,64,  7,32  ),
+	_SEG('8',  4,16,  4,32,  4,64,  4,128,  5,128,  5,64,  5,32  ),
+	_SEG('8',  2,16,  2,32,  2,64,  2,128,  3,128,  3,64,  3,32  ),
+	_SEG('8',  0,16,  0,32,  0,64,  0,128,  1,128,  1,64,  1,32  ),
+
+/* Line 4
+ *
+ * The LED, DIALTONE and RINGTONE are implemented as icons and use the same
+ * sysfs interface.
+ */
+#define LCD_LINE4_OFFSET	LCD_LINE3_OFFSET + LCD_LINE3_SIZE
+
+	_PIC('.', offsetof(struct yld_status, led)	, 0x01, "LED" ),
+	_PIC('.', offsetof(struct yld_status, dialtone) , 0x01, "DIALTONE" ),
+	_PIC('.', offsetof(struct yld_status, ringtone) , 0x24, "RINGTONE" ),
+
+#undef _SEG
+#undef _PIC
+#endif /* _SEG && _PIC */